diff --git a/.vscode/settings.json b/.vscode/settings.json index 10822524b25..c2193d76a35 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -33,5 +33,6 @@ "Conda", "sagemath", "Cython" - ] + ], + "editor.formatOnType": true } diff --git a/.zenodo.json b/.zenodo.json index 06bf86e4065..999a424d8d2 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.8.beta0", - "version": "9.8.beta0", + "title": "sagemath/sage: 9.8.beta1", + "version": "9.8.beta1", "upload_type": "software", - "publication_date": "2022-09-25", + "publication_date": "2022-09-29", "creators": [ { "affiliation": "SageMath.org", @@ -15,7 +15,7 @@ "related_identifiers": [ { "scheme": "url", - "identifier": "https://github.com/sagemath/sage/tree/9.8.beta0", + "identifier": "https://github.com/sagemath/sage/tree/9.8.beta1", "relation": "isSupplementTo" }, { diff --git a/README.md b/README.md index 7a21328c9a4..dc4139a8172 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ If your Mac uses the Apple Silicon (M1, arm64) architecture: https://brew.sh/ required because it provides a version of ``gfortran`` with necessary changes for this platform that are not in a released upstream version of GCC. (The ``gfortran`` package that comes with the Sage - distribution is not suitable for the M1.) + distribution is not suitable for the M1/M2.) If your Mac uses the Intel (x86_64) architecture: @@ -184,14 +184,20 @@ in the Installation Guide. - Compilers: `gcc`, `gfortran`, `g++` (GCC 8.x to 12.x and recent versions of Clang (LLVM) are supported). - See the Installation Manual for a discussion of suitable compilers. + See [build/pkgs/gcc/SPKG.rst](build/pkgs/gcc/SPKG.rst) and + [build/pkgs/gfortran/SPKG.rst](build/pkgs/gfortran/SPKG.rst) + for a discussion of suitable compilers. - Build tools: GNU `make`, GNU `m4`, `perl` (including ``ExtUtils::MakeMaker``), `ranlib`, `git`, `tar`, `bc`. + See [build/pkgs/_prereq/SPKG.rst](build/pkgs/_prereq/SPKG.rst) for + more details. - Python 3.4 or later, or Python 2.7, a full installation including `urllib`; but ideally version 3.8.x, 3.9.x, or 3.10.x, which will avoid having to build Sage's own copy of Python 3. + See [build/pkgs/python3/SPKG.rst](build/pkgs/python3/SPKG.rst) + for more details. We have collected lists of system packages that provide these build prerequisites. See, in the folder diff --git a/VERSION.txt b/VERSION.txt index 58778909bd8..5a632a27b46 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.8.beta0, Release Date: 2022-09-25 +SageMath version 9.8.beta1, Release Date: 2022-09-29 diff --git a/build/bin/sage-dist-helpers b/build/bin/sage-dist-helpers index 339d06ce493..24769ebfffc 100644 --- a/build/bin/sage-dist-helpers +++ b/build/bin/sage-dist-helpers @@ -290,6 +290,8 @@ sdh_pip_install() { sdh_pip_editable_install() { echo "Installing $PKG_NAME (editable mode)" + # Until https://trac.sagemath.org/ticket/34209 switches us to PEP 660 editable wheels + export SETUPTOOLS_ENABLE_FEATURES=legacy-editable python3 -m pip install --verbose --no-deps --no-index --no-build-isolation --isolated --editable "$@" || \ sdh_die "Error installing $PKG_NAME" } diff --git a/build/make/Makefile.in b/build/make/Makefile.in index ea54177f241..79db8392d4a 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -430,7 +430,7 @@ define SET_SAGE_CHECK $(eval SAGE_CHECK_$(1) := $(2)) endef # Set defaults -$(foreach pkgname, $(NORMAL_PACKAGES),\ +$(foreach pkgname, $(NORMAL_PACKAGES) $(SCRIPT_PACKAGES),\ $(eval $(call SET_SAGE_CHECK,$(pkgname),$(SAGE_CHECK)))) # Parsing the SAGE_CHECK_PACKAGES variable: @@ -460,7 +460,7 @@ $(foreach clause, $(SAGE_CHECK_PACKAGES_sep), \ $(eval $(call SET_SAGE_CHECK,$(subst ?,,$(clause)),warn)), \ $(eval $(call SET_SAGE_CHECK,$(clause),yes))))) debug-check: - @echo $(foreach pkgname, $(NORMAL_PACKAGES), SAGE_CHECK_$(pkgname) = $(SAGE_CHECK_$(pkgname))) + @echo $(foreach pkgname, $(NORMAL_PACKAGES) $(SCRIPT_PACKAGES), SAGE_CHECK_$(pkgname) = $(SAGE_CHECK_$(pkgname))) #============================================================================== @@ -676,7 +676,7 @@ $(1)-$(4)-no-deps: . '$$(SAGE_ROOT)/build/bin/sage-build-env' && \ SAGE_SPKG_WHEELS=$$($(4))/var/lib/sage/wheels \ SAGE_INST_LOCAL=$$($(4)) \ - sage-logger -p '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-install' '$$(SAGE_LOGS)/$(1)-$(2).log' && \ + sage-logger -p 'SAGE_CHECK=$$(SAGE_CHECK_$(1)) $$(SAGE_ROOT)/build/pkgs/$(1)/spkg-install' '$$(SAGE_LOGS)/$(1)-$(2).log' && \ rm -f "$$($(4))/$(SPKG_INST_RELDIR)/$(1)-*" && \ touch "$$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2)"; \ else ( \ diff --git a/build/pkgs/_prereq/SPKG.rst b/build/pkgs/_prereq/SPKG.rst index a798c656ed0..2b64020a823 100644 --- a/build/pkgs/_prereq/SPKG.rst +++ b/build/pkgs/_prereq/SPKG.rst @@ -4,5 +4,49 @@ _prereq: Represents system packages required for installing SageMath from source Description ----------- -This script package represents the minimal requirements (system packages) +This dummy package represents the minimal requirements (system packages) for installing SageMath from source. + +In addition to standard :wikipedia:`POSIX ` utilities +and the :wikipedia:`bash ` shell, +the following standard command-line development tools must be installed on your +computer: + +- **make**: GNU make, version 3.80 or later. Version 3.82 or later is recommended. +- **m4**: GNU m4 1.4.2 or later (non-GNU or older versions might also work). +- **perl**: version 5.8.0 or later. +- **ar** and **ranlib**: can be obtained as part of GNU binutils. +- **tar**: GNU tar version 1.17 or later, or BSD tar (as provided on macOS). +- **python**: Python 3.4 or later, or Python 2.7. + (This range of versions is a minimal requirement for internal purposes of the SageMath + build system, which is referred to as ``sage-bootstrap-python``.) + +Other versions of these may work, but they are untested. + +On macOS, suitable versions of all of these tools are provided +by the Xcode Command Line Tools. To install them, open a terminal +window and run ``xcode-select --install``; then click "Install" in the +pop-up window. If the Xcode Command Line Tools are already installed, +you may want to check if they need to be updated by typing +``softwareupdate -l``. + +On Linux, ``ar`` and ``ranlib`` are in the `binutils +`_ package. The other +programs are usually located in packages with their respective names. + +On Redhat-derived systems not all perl components are installed by +default and you might have to install the ``perl-ExtUtils-MakeMaker`` +package. + +To check if you have the above prerequisites installed, for example ``perl``, +type:: + + $ command -v perl + +or:: + + $ which perl + +on the command line. If it gives an error (or returns nothing), then +either ``perl`` is not installed, or it is installed but not in your +:wikipedia:`PATH `. diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index d7e7fc0fcc1..53ac5f0f4d1 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,4 +1,4 @@ tarball=configure-VERSION.tar.gz -sha1=c2e1c4db6762c4d97d5127f5f056e46fe3d5a94d -md5=70dcc35964e4234443c4e77beb2245d7 -cksum=2271434645 +sha1=73f9fe2ad9e2cfe224c7667a784144a1c520b9d8 +md5=8be336b502a66c5a410183be1eca2ca9 +cksum=42655200 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index abdbdc62467..ac53b0e4214 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -04fbc829e9850eedf555acc683666c55cb7052d7 +51d49e23f3d3014e301fefcf72bf7a2a3fe0c4e0 diff --git a/build/pkgs/distlib/checksums.ini b/build/pkgs/distlib/checksums.ini index 9c739a93823..1d749b2f9a7 100644 --- a/build/pkgs/distlib/checksums.ini +++ b/build/pkgs/distlib/checksums.ini @@ -1,5 +1,5 @@ -tarball=distlib-VERSION.zip -sha1=e7927ebc964676c17d466ed6a345222c34167a85 -md5=c886b7d99b4085c5d960e7435dcbd397 -cksum=10374426 -upstream_url=https://pypi.io/packages/source/d/distlib/distlib-VERSION.zip +tarball=distlib-VERSION.tar.gz +sha1=3a86d49dc17320325004564d0dc86afa808624bc +md5=f60ba4e3f8e76c214d3d00b2227a16f7 +cksum=1543870863 +upstream_url=https://pypi.io/packages/source/d/distlib/distlib-VERSION.tar.gz diff --git a/build/pkgs/distlib/package-version.txt b/build/pkgs/distlib/package-version.txt index 42045acae20..449d7e73a96 100644 --- a/build/pkgs/distlib/package-version.txt +++ b/build/pkgs/distlib/package-version.txt @@ -1 +1 @@ -0.3.4 +0.3.6 diff --git a/build/pkgs/gcc/SPKG.rst b/build/pkgs/gcc/SPKG.rst index 1f5684b86b2..75feee2d6d8 100644 --- a/build/pkgs/gcc/SPKG.rst +++ b/build/pkgs/gcc/SPKG.rst @@ -1,10 +1,70 @@ -gcc: The GNU Compiler Collection, including the C, C++ and Fortran compiler -=========================================================================== +gcc: The GNU Compiler Collection or other suitable C and C++ compilers +====================================================================== Description ----------- -The GNU Compiler Collection, including the C, C++ and Fortran compiler. +This package represents the required C and C++ compilers. + +- GCC (GNU Compiler Collection) versions 8.x to 12.x are supported. + +- Clang (LLVM) is also supported. + +The required Fortran compiler is represented by the package ``gfortran``. + +You can pass the names of compilers to use to ``./configure`` using +the environment variables :envvar:`CC`, :envvar:`CXX`, and +:envvar:`FC`, for C, C++, and Fortran compilers, respectively. + +For example, if your C compiler is ``clang``, your C++ compiler is +``clang++``, and your Fortran compiler is ``flang``, then you would +need to run:: + + $ ./configure CC=clang CXX=clang++ FC=flang + +Vendor and versions of the C and C++ compilers should match. + +Users of older Linux distributions (in particular, ``ubuntu-xenial`` +or older, ``debian-stretch`` or older, ``linuxmint-18`` or older) +should upgrade their systems before attempting to install Sage from +source. Users of ``ubuntu-bionic``, ``linuxmint-19.x``, and +``opensuse-15.x`` can install a versioned ``gcc`` system package +and then use:: + + $ ./configure CC=gcc-8 CXX=g++-8 FC=gfortran-8 + +or similar. Users on ``ubuntu`` can also install a modern compiler +toolchain `using the ubuntu-toolchain-r ppa +`_. +On ``ubuntu-trusty``, also the package ``binutils-2.26`` is required; +after installing it, make it available using ``export +PATH="/usr/lib/binutils-2.26/bin:$PATH"``. Instead of upgrading their +distribution, users of ``centos-7`` can install a modern compiler +toolchain `using Redhat's devtoolset +`_. + +This package uses the non-standard default +``configure --with-system-gcc=force``, giving an error at ``configure`` +time when no suitable system compilers are configured. + +You can override this using ``./configure --without-system-gcc``. In +this case, Sage builds and installs the GNU Compiler Collection, +including the C, C++ and Fortran compiler. This is not recommended. +You will need suitable C and C++ compilers from which GCC can +bootstrap itself. There are some known problems with old assemblers, +in particular when building the ``ecm`` and ``fflas_ffpack`` +packages. You should ensure that your assembler understands all +instructions for your processor. On Linux, this means you need a +recent version of ``binutils`` (not provided by an SPKG); on macOS +you need a recent version of Xcode. + +(Installing the +``gfortran`` SPKG becomes a no-op in this case.) + +Building Sage from source on Apple Silicon (M1/M2) requires the use of +Apple's Command Line Tools, and those tools include a suitable +compiler. Sage's ``gcc`` SPKG is not suitable for M1/M2; building it +will likely fail. License ------- diff --git a/build/pkgs/gfortran/SPKG.rst b/build/pkgs/gfortran/SPKG.rst index 1bea5fae5fe..9559b98456d 100644 --- a/build/pkgs/gfortran/SPKG.rst +++ b/build/pkgs/gfortran/SPKG.rst @@ -4,8 +4,21 @@ gfortran: Fortran compiler from the GNU Compiler Collection Description ----------- -The GNU Compiler Collection, including the C, C++ and Fortran compiler. -This particular package is meant to only make gfortran available. +This package represents the required Fortran compiler. + +Officially we support ``gfortran`` from `GNU Compiler Collection (GCC) +`_. It has also been reported that using ``flang`` +(from LLVM) might work. + +You can pass the names of compilers to use to ``./configure`` using +the environment variables :envvar:`CC`, :envvar:`CXX`, and +:envvar:`FC`, for C, C++, and Fortran compilers, respectively. + +For example, if your C compiler is ``clang``, your C++ compiler is +``clang++``, and your Fortran compiler is ``flang``, then you would +need to run:: + + $ ./configure CC=clang CXX=clang++ FC=flang License ------- diff --git a/build/pkgs/hatchling/checksums.ini b/build/pkgs/hatchling/checksums.ini index ec1317175da..598cd79a2c7 100644 --- a/build/pkgs/hatchling/checksums.ini +++ b/build/pkgs/hatchling/checksums.ini @@ -1,5 +1,5 @@ tarball=hatchling-VERSION.tar.gz -sha1=63ae7f29657e4d069c716e098a9ac8114d2f29f9 -md5=e05f845d94f400c3085bbaab21adcdbe -cksum=3213522818 +sha1=8f102796a225fb18b0571a44308341c7211d5d94 +md5=c50eff4f711cee451037ec7eb780154a +cksum=3180958969 upstream_url=https://pypi.io/packages/source/h/hatchling/hatchling-VERSION.tar.gz diff --git a/build/pkgs/hatchling/package-version.txt b/build/pkgs/hatchling/package-version.txt index 3a3cd8cc8b0..81c871de46b 100644 --- a/build/pkgs/hatchling/package-version.txt +++ b/build/pkgs/hatchling/package-version.txt @@ -1 +1 @@ -1.3.1 +1.10.0 diff --git a/build/pkgs/importlib_metadata/checksums.ini b/build/pkgs/importlib_metadata/checksums.ini index d5a9b1a2668..ea39c54a4a3 100644 --- a/build/pkgs/importlib_metadata/checksums.ini +++ b/build/pkgs/importlib_metadata/checksums.ini @@ -1,5 +1,5 @@ tarball=importlib_metadata-VERSION.tar.gz -sha1=7d15d8e06299a8f24e076600899aceee75ce8b0b -md5=a605ba6ec315bc1324fd6b7210fe7c12 -cksum=448954927 +sha1=ec68de1ec1800048de8656b9d211e22b7fe7c53e +md5=cfcf29185e13439c76d09c94bc8d81f4 +cksum=2134804316 upstream_url=https://pypi.io/packages/source/i/importlib_metadata/importlib_metadata-VERSION.tar.gz diff --git a/build/pkgs/importlib_metadata/package-version.txt b/build/pkgs/importlib_metadata/package-version.txt index 326ec6355f3..815588ef140 100644 --- a/build/pkgs/importlib_metadata/package-version.txt +++ b/build/pkgs/importlib_metadata/package-version.txt @@ -1 +1 @@ -4.8.2 +4.12.0 diff --git a/build/pkgs/importlib_resources/checksums.ini b/build/pkgs/importlib_resources/checksums.ini index f769a9f43b4..99a4cdf7908 100644 --- a/build/pkgs/importlib_resources/checksums.ini +++ b/build/pkgs/importlib_resources/checksums.ini @@ -1,5 +1,5 @@ tarball=importlib_resources-VERSION.tar.gz -sha1=d1f2742895a68f3f8d19dd7285df1687877fb15a -md5=5db738106ca7c05340495c36357986a2 -cksum=1338307365 +sha1=3b4b20fa0399e2fa21c7506be27a4b943495d3ad +md5=3b6d98270d40b2ba7af1f8d09188f0c2 +cksum=2401793228 upstream_url=https://pypi.io/packages/source/i/importlib_resources/importlib_resources-VERSION.tar.gz diff --git a/build/pkgs/importlib_resources/package-version.txt b/build/pkgs/importlib_resources/package-version.txt index ce7f2b425b5..b3d91f9cfc0 100644 --- a/build/pkgs/importlib_resources/package-version.txt +++ b/build/pkgs/importlib_resources/package-version.txt @@ -1 +1 @@ -5.2.2 +5.9.0 diff --git a/build/pkgs/jupyter_packaging/checksums.ini b/build/pkgs/jupyter_packaging/checksums.ini index eb449d9da6f..65b3bd148f6 100644 --- a/build/pkgs/jupyter_packaging/checksums.ini +++ b/build/pkgs/jupyter_packaging/checksums.ini @@ -1,5 +1,5 @@ tarball=jupyter_packaging-VERSION.tar.gz -sha1=c9b7dd75a70ad6a7c621588db410f07fba7e0fad -md5=d30e6fb387d46398a3ab26765b8fa74f -cksum=669146472 +sha1=092d249360aa56838a188decc4bcd09647fda4d9 +md5=9c6834023bd699bda5365ab7ed18bde2 +cksum=3308833189 upstream_url=https://pypi.io/packages/source/j/jupyter_packaging/jupyter_packaging-VERSION.tar.gz diff --git a/build/pkgs/jupyter_packaging/package-version.txt b/build/pkgs/jupyter_packaging/package-version.txt index 26acbf080be..aa22d3ce39b 100644 --- a/build/pkgs/jupyter_packaging/package-version.txt +++ b/build/pkgs/jupyter_packaging/package-version.txt @@ -1 +1 @@ -0.12.2 +0.12.3 diff --git a/build/pkgs/msolve/SPKG.rst b/build/pkgs/msolve/SPKG.rst new file mode 100644 index 00000000000..00c1c417208 --- /dev/null +++ b/build/pkgs/msolve/SPKG.rst @@ -0,0 +1,21 @@ +msolve: Multivariate polynomial system solver +============================================= + +Description +----------- + +Open source C library implementing computer algebra algorithms for solving +polynomial systems (with rational coefficients or coefficients in a prime field). + +License +------- + +GPL v2+ + +Upstream Contact +---------------- + +https://github.com/algebraic-solving/msolve + +Upstream does not make source tarballs. +We make tarballs from the fork https://github.com/mkoeppe/msolve (branch 0.4.4+sage) diff --git a/build/pkgs/msolve/checksums.ini b/build/pkgs/msolve/checksums.ini new file mode 100644 index 00000000000..0b7558afd2b --- /dev/null +++ b/build/pkgs/msolve/checksums.ini @@ -0,0 +1,5 @@ +tarball=msolve-VERSION.tar.gz +sha1=5b227de8b222bfe8d143e1d7ea77ad71cd209dc8 +md5=2f34bd9ccb089688ae169201281108dc +cksum=941373315 +upstream_url=https://trac.sagemath.org/raw-attachment/ticket/31664/msolve-VERSION.tar.gz diff --git a/build/pkgs/msolve/dependencies b/build/pkgs/msolve/dependencies new file mode 100644 index 00000000000..4f96ff0a6c9 --- /dev/null +++ b/build/pkgs/msolve/dependencies @@ -0,0 +1,4 @@ +$(MP_LIBRARY) flint mpfr + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/msolve/package-version.txt b/build/pkgs/msolve/package-version.txt new file mode 100644 index 00000000000..fb78594e923 --- /dev/null +++ b/build/pkgs/msolve/package-version.txt @@ -0,0 +1 @@ +0.4.4+sage-2022-09-11 diff --git a/build/pkgs/msolve/spkg-install.in b/build/pkgs/msolve/spkg-install.in new file mode 100644 index 00000000000..2aaf0e99043 --- /dev/null +++ b/build/pkgs/msolve/spkg-install.in @@ -0,0 +1,4 @@ +cd src +sdh_configure +sdh_make +sdh_make_install diff --git a/build/pkgs/msolve/type b/build/pkgs/msolve/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/msolve/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/numpy/checksums.ini b/build/pkgs/numpy/checksums.ini index c15b3d8db64..544f35fbfb8 100644 --- a/build/pkgs/numpy/checksums.ini +++ b/build/pkgs/numpy/checksums.ini @@ -1,5 +1,5 @@ -tarball=numpy-VERSION.zip -sha1=3ac08064b2ec8db8fe4870c2545c9d154f46bb30 -md5=b44849506fbb54cdef9dbb435b2b1987 -cksum=735479084 -upstream_url=https://pypi.io/packages/source/n/numpy/numpy-VERSION.zip +tarball=numpy-VERSION.tar.gz +sha1=570c995d7b155c7e4ac43bc46594172cedf1e4fa +md5=6efc60a3f6c1b74c849d53fbcc07807b +cksum=3973735135 +upstream_url=https://pypi.io/packages/source/n/numpy/numpy-VERSION.tar.gz diff --git a/build/pkgs/numpy/package-version.txt b/build/pkgs/numpy/package-version.txt index 2a0ba77cc5e..ac1df3fce34 100644 --- a/build/pkgs/numpy/package-version.txt +++ b/build/pkgs/numpy/package-version.txt @@ -1 +1 @@ -1.22.4 +1.23.3 diff --git a/build/pkgs/numpy/spkg-install.in b/build/pkgs/numpy/spkg-install.in index f66c6f56426..2b555d8b871 100644 --- a/build/pkgs/numpy/spkg-install.in +++ b/build/pkgs/numpy/spkg-install.in @@ -7,6 +7,14 @@ if [ `uname` = "Darwin" ]; then unset ATLAS unset BLAS unset LAPACK + # https://trac.sagemath.org/ticket/34110#comment:35 + # The fix for "reciprocal" (affected by a clang compiler bug) in + # https://github.com/numpy/numpy/pull/19926 relies on -ftrapping-math + # being used when Apple clang v12+ is used. + # But numpy.distutils.ccompiler only sets this flag when + # $CC contains the string "clang" -- missing the case CC=/usr/bin/gcc. + # So we set it here explicitly if the compiler supports the flag. + export CFLAGS="$(testcflags.sh $CFLAGS -ftrapping-math)" else export {ATLAS,PTATLAS,OPENBLAS,MKL,MKLROOT}=None export LDFLAGS="${LDFLAGS} -shared" @@ -27,15 +35,10 @@ fi export FFLAGS="$FFLAGS -fPIC" export FCFLAGS="$FCFLAGS -fPIC" -# Numpy 1.20.3 enables some intrinsics on machines without support with `-march=native`. -# We disable it until this is fixed. -export CFLAGS="$CFLAGS_NON_NATIVE" - -export NUMPY_FCONFIG="config_fc --noopt --noarch" if [ "$SAGE_FAT_BINARY" = "yes" ]; then export NUMPY_FCONFIG="--cpu-baseline=NONE" else - export NUMPY_FCONFIG + export NUMPY_FCONFIG="" fi # Trac #32423: Fix 32-bit builds on x86_64 diff --git a/build/pkgs/pathspec/checksums.ini b/build/pkgs/pathspec/checksums.ini index cb80c60c623..2db40ded285 100644 --- a/build/pkgs/pathspec/checksums.ini +++ b/build/pkgs/pathspec/checksums.ini @@ -1,5 +1,5 @@ tarball=pathspec-VERSION.tar.gz -sha1=afe51c21951f457f82a5810016d0b6752ffc487b -md5=9b6b70fa5ffc31e6f5700522880140c0 -cksum=3501694416 +sha1=ef0f4b07097506575ca8052256b56f137a7b170d +md5=6f4fde5e701d328a2846d206edb63aa9 +cksum=2376511942 upstream_url=https://pypi.io/packages/source/p/pathspec/pathspec-VERSION.tar.gz diff --git a/build/pkgs/pathspec/package-version.txt b/build/pkgs/pathspec/package-version.txt index ac39a106c48..571215736a6 100644 --- a/build/pkgs/pathspec/package-version.txt +++ b/build/pkgs/pathspec/package-version.txt @@ -1 +1 @@ -0.9.0 +0.10.1 diff --git a/build/pkgs/pip/checksums.ini b/build/pkgs/pip/checksums.ini index 35d4f6fde7b..a13af9996c7 100644 --- a/build/pkgs/pip/checksums.ini +++ b/build/pkgs/pip/checksums.ini @@ -1,5 +1,5 @@ tarball=pip-VERSION.tar.gz -sha1=be5b671f4868816c6ad2e09258c22bdb3fc82775 -md5=6ec06d38c3aed5d22bcbbbfbf7114d6a -cksum=3372144553 +sha1=ed6e6d191a686b4f989a1dbb2640737a1123f24f +md5=05bb8c0607721d171e9eecf22a8c5cc6 +cksum=4023376185 upstream_url=https://pypi.io/packages/source/p/pip/pip-VERSION.tar.gz diff --git a/build/pkgs/pip/package-version.txt b/build/pkgs/pip/package-version.txt index 30ed8778377..637c2a16439 100644 --- a/build/pkgs/pip/package-version.txt +++ b/build/pkgs/pip/package-version.txt @@ -1 +1 @@ -22.1.2 +22.2.2 diff --git a/build/pkgs/pkgconfig/dependencies b/build/pkgs/pkgconfig/dependencies index 79554fc438d..6dfe046e55e 100644 --- a/build/pkgs/pkgconfig/dependencies +++ b/build/pkgs/pkgconfig/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) pkgconf +$(PYTHON) | $(PYTHON_TOOLCHAIN) pkgconf poetry_core ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/pkgconfig/spkg-install.in b/build/pkgs/pkgconfig/spkg-install.in index 761190e309c..d14edc90bcd 100644 --- a/build/pkgs/pkgconfig/spkg-install.in +++ b/build/pkgs/pkgconfig/spkg-install.in @@ -1,10 +1,5 @@ cd src -# Make sure that modern pip uses the generated setup.py -# that is distributed with the PyPI tarball, -# so we do not have to have poetry. Trac #29803. -rm -f pyproject.toml - sdh_pip_install . if [ $? -ne 0 ]; then diff --git a/build/pkgs/primecount/distros/homebrew.txt b/build/pkgs/primecount/distros/homebrew.txt new file mode 100644 index 00000000000..f67843baa2b --- /dev/null +++ b/build/pkgs/primecount/distros/homebrew.txt @@ -0,0 +1 @@ +primecount diff --git a/build/pkgs/python3/SPKG.rst b/build/pkgs/python3/SPKG.rst index 10d444bd020..94a163de1f3 100644 --- a/build/pkgs/python3/SPKG.rst +++ b/build/pkgs/python3/SPKG.rst @@ -4,7 +4,21 @@ python3: The Python programming language Description ----------- -The Python programming language +By default, Sage will try to use system's ``python3`` to set up a virtual +environment, a.k.a. `venv `_ +rather than building a Python 3 installation from scratch. + +Sage will accept versions 3.8.x to 3.10.x. + +You can also use ``--with-python=/path/to/python3_binary`` to tell Sage to use +``/path/to/python3_binary`` to set up the venv. Note that setting up the venv requires +a number of Python modules to be available within the Python in question. Currently, +as of Sage 9.7, these modules are as follows: ``sqlite3``, ``ctypes``, ``math``, +``hashlib``, ``crypt``, ``socket``, ``zlib``, ``distutils.core``, ``ssl`` - +they will be checked for by the ``configure`` script. + +Use the ``configure`` option ``--without-system-python3`` in case you want Python 3 +built from scratch. Upstream Contact diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index 35a8993af20..8e33acc92e6 100644 --- a/build/pkgs/sage_conf/install-requires.txt +++ b/build/pkgs/sage_conf/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 9.8b0 +sage-conf ~= 9.8b1 diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index 002c6b79c65..a2cc79f66c9 100644 --- a/build/pkgs/sage_docbuild/install-requires.txt +++ b/build/pkgs/sage_docbuild/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 9.8b0 +sage-docbuild ~= 9.8b1 diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index 5720bc8f2c5..050098266b7 100644 --- a/build/pkgs/sage_setup/install-requires.txt +++ b/build/pkgs/sage_setup/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 9.8b0 +sage-setup ~= 9.8b1 diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index 70be4d731ee..ca58fa64648 100644 --- a/build/pkgs/sage_sws2rst/install-requires.txt +++ b/build/pkgs/sage_sws2rst/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 9.8b0 +sage-sws2rst ~= 9.8b1 diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index 359dff35670..82d6db622ed 100644 --- a/build/pkgs/sagelib/install-requires.txt +++ b/build/pkgs/sagelib/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagelib ~= 9.8b0 +sagelib ~= 9.8b1 diff --git a/build/pkgs/sagelib/spkg-install b/build/pkgs/sagelib/spkg-install index 8d91b16b3f0..91e4d8c1869 100755 --- a/build/pkgs/sagelib/spkg-install +++ b/build/pkgs/sagelib/spkg-install @@ -52,6 +52,8 @@ if [ "$SAGE_EDITABLE" = yes ]; then # and renamed the distribution to "sagemath-standard"). There is no clean way to uninstall # them, so we just use rm. (cd "$SITEPACKAGESDIR" && rm -rf sage sage_setup sage-[1-9]*.egg-info sage-[1-9]*.dist-info) + # Until https://trac.sagemath.org/ticket/34209 switches us to PEP 660 editable wheels + export SETUPTOOLS_ENABLE_FEATURES=legacy-editable time python3 -m pip install --verbose --no-deps --no-index --no-build-isolation --isolated --editable . || exit 1 else # Make sure that an installed old version of sagelib in which sage is an ordinary package diff --git a/build/pkgs/sagemath_categories/dependencies b/build/pkgs/sagemath_categories/dependencies deleted file mode 120000 index 55c209e6418..00000000000 --- a/build/pkgs/sagemath_categories/dependencies +++ /dev/null @@ -1 +0,0 @@ -../sagemath_objects/dependencies \ No newline at end of file diff --git a/build/pkgs/sagemath_categories/dependencies b/build/pkgs/sagemath_categories/dependencies new file mode 100644 index 00000000000..d8b6bdbd4a7 --- /dev/null +++ b/build/pkgs/sagemath_categories/dependencies @@ -0,0 +1 @@ +$(PYTHON) sagemath_objects | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig python_build diff --git a/build/pkgs/sagemath_categories/dependencies_check b/build/pkgs/sagemath_categories/dependencies_check new file mode 100644 index 00000000000..7d2fe6c3064 --- /dev/null +++ b/build/pkgs/sagemath_categories/dependencies_check @@ -0,0 +1 @@ +tox sagemath_repl diff --git a/build/pkgs/sagemath_categories/install-requires.txt b/build/pkgs/sagemath_categories/install-requires.txt index 070f8caa2ea..f5c2a080bae 100644 --- a/build/pkgs/sagemath_categories/install-requires.txt +++ b/build/pkgs/sagemath_categories/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 9.8b0 +sagemath-categories ~= 9.8b1 diff --git a/build/pkgs/sagemath_environment/dependencies b/build/pkgs/sagemath_environment/dependencies deleted file mode 120000 index 55c209e6418..00000000000 --- a/build/pkgs/sagemath_environment/dependencies +++ /dev/null @@ -1 +0,0 @@ -../sagemath_objects/dependencies \ No newline at end of file diff --git a/build/pkgs/sagemath_environment/dependencies b/build/pkgs/sagemath_environment/dependencies new file mode 100644 index 00000000000..605611e7a21 --- /dev/null +++ b/build/pkgs/sagemath_environment/dependencies @@ -0,0 +1 @@ +$(PYTHON) | $(PYTHON_TOOLCHAIN) python_build diff --git a/build/pkgs/sagemath_environment/dependencies_check b/build/pkgs/sagemath_environment/dependencies_check new file mode 100644 index 00000000000..053148f8486 --- /dev/null +++ b/build/pkgs/sagemath_environment/dependencies_check @@ -0,0 +1 @@ +tox diff --git a/build/pkgs/sagemath_environment/install-requires.txt b/build/pkgs/sagemath_environment/install-requires.txt index e9976c7146f..5ac02d56d50 100644 --- a/build/pkgs/sagemath_environment/install-requires.txt +++ b/build/pkgs/sagemath_environment/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 9.8b0 +sagemath-environment ~= 9.8b1 diff --git a/build/pkgs/sagemath_objects/dependencies b/build/pkgs/sagemath_objects/dependencies index 217821d206b..807b8b17215 100644 --- a/build/pkgs/sagemath_objects/dependencies +++ b/build/pkgs/sagemath_objects/dependencies @@ -1,4 +1,3 @@ -FORCE $(PYTHON) cysignals gmpy2 ipython | $(PYTHON_TOOLCHAIN) sage_setup cython pkgconfig python_build +FORCE $(PYTHON) cysignals gmpy2 | $(PYTHON_TOOLCHAIN) sagemath_environment sage_setup cython pkgconfig python_build # FORCE: Always run the spkg-install script -# ipython - for the doctester diff --git a/build/pkgs/sagemath_objects/install-requires.txt b/build/pkgs/sagemath_objects/install-requires.txt index 0fb621f26f2..24f5473ae33 100644 --- a/build/pkgs/sagemath_objects/install-requires.txt +++ b/build/pkgs/sagemath_objects/install-requires.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 9.8b0 +sagemath-objects ~= 9.8b1 diff --git a/build/pkgs/sagemath_objects/spkg-install b/build/pkgs/sagemath_objects/spkg-install index 5c2ab2350c4..6cc85e07e55 100755 --- a/build/pkgs/sagemath_objects/spkg-install +++ b/build/pkgs/sagemath_objects/spkg-install @@ -19,15 +19,11 @@ export PIP_FIND_LINKS="file://$SAGE_SPKG_WHEELS" # (Important because sagemath-objects uses MANIFEST.in for filtering.) # Do not install the wheel. DIST_DIR="$(mktemp -d)" -if ! python3 -m build --outdir "$DIST_DIR"/dist .; then - # This happens on Debian without python3-venv installed - "ensurepip" is missing - echo "Falling back to --no-isolation" - python3 -m build --no-isolation --outdir "$DIST_DIR"/dist . || sdh_die "Failure building sdist and wheel" -fi +python3 -m build --outdir "$DIST_DIR"/dist . || sdh_die "Failure building sdist and wheel" wheel=$(cd "$DIST_DIR" && sdh_store_wheel . && echo $wheel) ls -l "$wheel" if [ "$SAGE_CHECK" != no ]; then - tox -v -e sagepython-norequirements --installpkg "$wheel" + tox -r -v -e sagepython-sagewheels-nopypi-norequirements --installpkg $wheel fi diff --git a/build/pkgs/sagemath_repl/dependencies b/build/pkgs/sagemath_repl/dependencies deleted file mode 120000 index 55c209e6418..00000000000 --- a/build/pkgs/sagemath_repl/dependencies +++ /dev/null @@ -1 +0,0 @@ -../sagemath_objects/dependencies \ No newline at end of file diff --git a/build/pkgs/sagemath_repl/dependencies b/build/pkgs/sagemath_repl/dependencies new file mode 100644 index 00000000000..ebc253dac5b --- /dev/null +++ b/build/pkgs/sagemath_repl/dependencies @@ -0,0 +1 @@ +$(PYTHON) sagemath_objects sagemath_environment ipython ipywidgets | $(PYTHON_TOOLCHAIN) python_build diff --git a/build/pkgs/sagemath_repl/dependencies_check b/build/pkgs/sagemath_repl/dependencies_check new file mode 100644 index 00000000000..053148f8486 --- /dev/null +++ b/build/pkgs/sagemath_repl/dependencies_check @@ -0,0 +1 @@ +tox diff --git a/build/pkgs/sagemath_repl/install-requires.txt b/build/pkgs/sagemath_repl/install-requires.txt new file mode 100644 index 00000000000..9d91ae25d19 --- /dev/null +++ b/build/pkgs/sagemath_repl/install-requires.txt @@ -0,0 +1,2 @@ +# This file is updated on every release by the sage-update-version script +sagemath-repl ~= 9.8b1 diff --git a/build/pkgs/setuptools/SPKG.rst b/build/pkgs/setuptools/SPKG.rst index 8d510960f1d..a50e171a98d 100644 --- a/build/pkgs/setuptools/SPKG.rst +++ b/build/pkgs/setuptools/SPKG.rst @@ -4,26 +4,24 @@ setuptools: Build system for Python packages Description ----------- -setuptools is a collection of enhancements to the Python distutils (for -Python 2.6 and up) that allow you to more easily build and distribute -Python packages, especially ones that have dependencies on other -packages. +setuptools is the classical build system for Python packages, +a collection of enhancements to the Python distutils. -Website: http://pypi.python.org/pypi/setuptools/ +This package represents version 63.x of ``setuptools``. +Sage installs this version to provide the build system +for non-PEP 517 packages. In particular, Sage uses it +for building ``numpy``, whose build system ``numpy.distutils`` +is not compatible with newer versions of ``setuptools``, +see https://github.com/numpy/numpy/pull/22154 License ------- -PSF or ZPL. i.e Python Software Foundation License or Zope Public -License - +MIT License Upstream Contact ---------------- -- Phillip J. Eby (distutils-sig@python org) - -Dependencies ------------- +http://pypi.python.org/pypi/setuptools/ -- python +https://github.com/pypa/setuptools diff --git a/build/pkgs/setuptools/checksums.ini b/build/pkgs/setuptools/checksums.ini index 8a9faad33ca..d47099a8019 100644 --- a/build/pkgs/setuptools/checksums.ini +++ b/build/pkgs/setuptools/checksums.ini @@ -1,5 +1,5 @@ tarball=setuptools-VERSION.tar.gz -sha1=2a5a4ac384ace22dd10e3dac0a1b6af49e03c596 -md5=d72acb93671bde8e4ca0971866f9cdda -cksum=2262493785 +sha1=b14b8e2cf965fdb6870ebfccee50c751c056f757 +md5=02a0e4dc4fa13168904e8769a077aa26 +cksum=2734084418 upstream_url=https://pypi.io/packages/source/s/setuptools/setuptools-VERSION.tar.gz diff --git a/build/pkgs/setuptools/install-requires.txt b/build/pkgs/setuptools/install-requires.txt index 486c3c348ee..0810ca37277 100644 --- a/build/pkgs/setuptools/install-requires.txt +++ b/build/pkgs/setuptools/install-requires.txt @@ -1,2 +1 @@ -# Set this bound until https://trac.sagemath.org/ticket/34209 adds support for PEP660 editable builds -setuptools >=49.6.0,<64.0.0 +setuptools >=49.6.0 diff --git a/build/pkgs/setuptools/package-version.txt b/build/pkgs/setuptools/package-version.txt index 61f1f83a084..fe3c6688881 100644 --- a/build/pkgs/setuptools/package-version.txt +++ b/build/pkgs/setuptools/package-version.txt @@ -1 +1 @@ -63.2.0 +63.4.3 diff --git a/build/pkgs/setuptools_wheel/SPKG.rst b/build/pkgs/setuptools_wheel/SPKG.rst index c78602a296a..b77a6679f8f 100644 --- a/build/pkgs/setuptools_wheel/SPKG.rst +++ b/build/pkgs/setuptools_wheel/SPKG.rst @@ -3,3 +3,6 @@ setuptools_wheel: Build the setuptools package as a wheel After installing setuptools and wheel, we build a wheel of setuptools to complete the set of wheels stored in our wheelhouse. + +This version of setuptools is suitable for PEP 517/518/660 builds, +but it is not suitable for building ``numpy``. diff --git a/build/pkgs/setuptools_wheel/checksums.ini b/build/pkgs/setuptools_wheel/checksums.ini deleted file mode 120000 index 4f64d3ce107..00000000000 --- a/build/pkgs/setuptools_wheel/checksums.ini +++ /dev/null @@ -1 +0,0 @@ -../setuptools/checksums.ini \ No newline at end of file diff --git a/build/pkgs/setuptools_wheel/checksums.ini b/build/pkgs/setuptools_wheel/checksums.ini new file mode 100644 index 00000000000..2da328e1726 --- /dev/null +++ b/build/pkgs/setuptools_wheel/checksums.ini @@ -0,0 +1,5 @@ +tarball=setuptools-VERSION.tar.gz +sha1=e5f9797d85db9bb2ce39b401c1b7aca38de616b5 +md5=ec88a6545351e72ca73fcec7a6bff6ad +cksum=1981709060 +upstream_url=https://pypi.io/packages/source/s/setuptools/setuptools-VERSION.tar.gz diff --git a/build/pkgs/setuptools_wheel/package-version.txt b/build/pkgs/setuptools_wheel/package-version.txt deleted file mode 120000 index 5268dbec8f6..00000000000 --- a/build/pkgs/setuptools_wheel/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -../setuptools/package-version.txt \ No newline at end of file diff --git a/build/pkgs/setuptools_wheel/package-version.txt b/build/pkgs/setuptools_wheel/package-version.txt new file mode 100644 index 00000000000..ba0d20023a1 --- /dev/null +++ b/build/pkgs/setuptools_wheel/package-version.txt @@ -0,0 +1 @@ +65.4.0 diff --git a/build/pkgs/terminado/checksums.ini b/build/pkgs/terminado/checksums.ini index f33efd4b5da..794b2cda764 100644 --- a/build/pkgs/terminado/checksums.ini +++ b/build/pkgs/terminado/checksums.ini @@ -1,5 +1,5 @@ tarball=terminado-VERSION.tar.gz -sha1=65f40480c1d8077b78dcffb7e0c909eae86998bf -md5=4871263f6aaed18e09603fa6785b4340 -cksum=2070178009 +sha1=b0ff75a4f024dc07c9a819c1a63d75908624a5d3 +md5=e3fe92b48b3885ffa19b9890ed41578f +cksum=1261401246 upstream_url=https://pypi.io/packages/source/t/terminado/terminado-VERSION.tar.gz diff --git a/build/pkgs/terminado/dependencies b/build/pkgs/terminado/dependencies index e44a0d91033..54ec1c7c229 100644 --- a/build/pkgs/terminado/dependencies +++ b/build/pkgs/terminado/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) ptyprocess tornado +$(PYTHON) ptyprocess tornado | $(PYTHON_TOOLCHAIN) hatchling ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/terminado/package-version.txt b/build/pkgs/terminado/package-version.txt index 34a83616bb5..a5510516948 100644 --- a/build/pkgs/terminado/package-version.txt +++ b/build/pkgs/terminado/package-version.txt @@ -1 +1 @@ -0.12.1 +0.15.0 diff --git a/build/pkgs/terminado/spkg-install.in b/build/pkgs/terminado/spkg-install.in index cb4ba894442..058b1344dc2 100644 --- a/build/pkgs/terminado/spkg-install.in +++ b/build/pkgs/terminado/spkg-install.in @@ -1,8 +1,3 @@ cd src -# Make sure that modern pip uses the generated setup.py -# that is distributed with the PyPI tarball, -# so we do not have to have flit. Trac #29803. -rm -f pyproject.toml - sdh_pip_install . diff --git a/build/pkgs/tomlkit/checksums.ini b/build/pkgs/tomlkit/checksums.ini index f2116d86933..f43c80b7196 100644 --- a/build/pkgs/tomlkit/checksums.ini +++ b/build/pkgs/tomlkit/checksums.ini @@ -1,5 +1,5 @@ tarball=tomlkit-VERSION.tar.gz -sha1=c618d9b0490fb626c053c691def29223dcfbd6cc -md5=c4edce886bc20ef8ecea49984cce2e69 -cksum=2455377393 +sha1=65f56e209410e4eee4b45d048e6b4dc0fcaad74a +md5=d0edd43143c7840deb88185685cea8dd +cksum=846256591 upstream_url=https://pypi.io/packages/source/t/tomlkit/tomlkit-VERSION.tar.gz diff --git a/build/pkgs/tomlkit/package-version.txt b/build/pkgs/tomlkit/package-version.txt index d9df1bbc0c7..35ad34429be 100644 --- a/build/pkgs/tomlkit/package-version.txt +++ b/build/pkgs/tomlkit/package-version.txt @@ -1 +1 @@ -0.11.0 +0.11.4 diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index d6094609d88..132ada17594 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -266,12 +266,20 @@ def fix_checksum(self, package_name): def create(self, package_name, version=None, tarball=None, pkg_type=None, upstream_url=None, description=None, license=None, upstream_contact=None, pypi=False, source='normal'): """ - Create a normal package + Create a package + + $ sage --package create foo --version 1.3 --tarball FoO-VERSION.tar.gz --type experimental + + $ sage --package create scikit_spatial --pypi --type optional + + $ sage --package create torch --pypi --source pip --type optional + + $ sage --package create jupyterlab_markup --pypi --source wheel --type optional """ if '-' in package_name: raise ValueError('package names must not contain dashes, use underscore instead') if pypi: - pypi_version = PyPiVersion(package_name) + pypi_version = PyPiVersion(package_name, source=source) if source == 'normal': if not tarball: # Guess the general format of the tarball name. @@ -281,6 +289,14 @@ def create(self, package_name, version=None, tarball=None, pkg_type=None, upstre # Use a URL from pypi.io instead of the specific URL received from the PyPI query # because it follows a simple pattern. upstream_url = 'https://pypi.io/packages/source/{0:1.1}/{0}/{1}'.format(package_name, tarball) + elif source == 'wheel': + if not tarball: + tarball = pypi_version.tarball.replace(pypi_version.version, 'VERSION') + if not tarball.endswith('-none-any.whl'): + raise ValueError('Only platform-independent wheels can be used for wheel packages, got {0}'.format(tarball)) + if not version: + version = pypi_version.version + upstream_url = 'https://pypi.io/packages/py3/{0:1.1}/{0}/{1}'.format(package_name, tarball) if not description: description = pypi_version.summary if not license: diff --git a/build/sage_bootstrap/cmdline.py b/build/sage_bootstrap/cmdline.py index 780f3c5a8e3..aea51cb48f0 100644 --- a/build/sage_bootstrap/cmdline.py +++ b/build/sage_bootstrap/cmdline.py @@ -312,7 +312,7 @@ def make_parser(): 'package_name', default=None, type=str, help='Package name.') parser_create.add_argument( - '--source', type=str, default='normal', help='Package source (one of normal, script, pip)') + '--source', type=str, default='normal', help='Package source (one of normal, wheel, script, pip)') parser_create.add_argument( '--version', type=str, default=None, help='Package version') parser_create.add_argument( diff --git a/build/sage_bootstrap/creator.py b/build/sage_bootstrap/creator.py index 3779707de1f..f7a6ab203dc 100644 --- a/build/sage_bootstrap/creator.py +++ b/build/sage_bootstrap/creator.py @@ -87,6 +87,8 @@ def set_python_data_and_scripts(self, pypi_package_name=None, source='normal'): If ``source`` is ``"normal"``, write the files ``spkg-install.in`` and ``install-requires.txt``. + If ``source`` is ``"wheel"``, write the file ``install-requires.txt``. + If ``source`` is ``"pip"``, write the file ``requirements.txt``. """ if pypi_package_name is None: @@ -99,10 +101,13 @@ def set_python_data_and_scripts(self, pypi_package_name=None, source='normal'): f.write('cd src\nsdh_pip_install .\n') with open(os.path.join(self.path, 'install-requires.txt'), 'w+') as f: f.write('{0}\n'.format(pypi_package_name)) + elif source == 'wheel': + with open(os.path.join(self.path, 'install-requires.txt'), 'w+') as f: + f.write('{0}\n'.format(pypi_package_name)) elif source == 'pip': with open(os.path.join(self.path, 'requirements.txt'), 'w+') as f: f.write('{0}\n'.format(pypi_package_name)) elif source == 'script': pass else: - raise ValueError('package source must be one of normal, script, or pip') + raise ValueError('package source must be one of normal, script, pip, or wheel') diff --git a/build/sage_bootstrap/pypi.py b/build/sage_bootstrap/pypi.py index 24b050045f9..a11f3a95b46 100644 --- a/build/sage_bootstrap/pypi.py +++ b/build/sage_bootstrap/pypi.py @@ -34,11 +34,15 @@ class PyPiError(Exception): class PyPiVersion(object): - def __init__(self, package_name): + def __init__(self, package_name, source='normal'): self.name = package_name self.json = self._get_json() # Replace provided name with the canonical name self.name = self.json['info']['name'] + if source == 'wheel': + self.python_version = 'py3' + else: + self.python_version = 'source' def _get_json(self): response = urllib.urlopen(self.json_url) @@ -65,9 +69,9 @@ def url(self): Return the source url """ for download in self.json['urls']: - if download['python_version'] == 'source': + if download['python_version'] == self.python_version: return download['url'] - raise PyPiError('No source url for %s found', self.name) + raise PyPiError('No %s url for %s found', self.python_version, self.name) @property def tarball(self): @@ -75,9 +79,9 @@ def tarball(self): Return the source tarball name """ for download in self.json['urls']: - if download['python_version'] == 'source': + if download['python_version'] == self.python_version: return download['filename'] - raise PyPiError('No source url for %s found', self.name) + raise PyPiError('No %s url for %s found', self.python_version, self.name) @property def package_url(self): diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sagemath-categories/MANIFEST.in.m4 b/pkgs/sagemath-categories/MANIFEST.in.m4 index 3a9b1d9bff1..390c7e5759f 100644 --- a/pkgs/sagemath-categories/MANIFEST.in.m4 +++ b/pkgs/sagemath-categories/MANIFEST.in.m4 @@ -1,13 +1,36 @@ dnl MANIFEST.in is generated from this file by SAGE_ROOT/bootstrap via m4. +prune sage -dnl Include all from sagemath-objects (via m4 include) -include(`../sagemath_objects/src/MANIFEST.in') +include VERSION.txt -# Extra in sagemath-categories: global-include all__sagemath_categories.py graft sage/categories +# Exclude what is already shipped in sagemath-objects +exclude sage/categories/action.* +exclude sage/categories/algebra_functor.* +exclude sage/categories/basic.* +exclude sage/categories/cartesian_product.* +exclude sage/categories/category*.* +exclude sage/categories/covariant_functorial_construction.* +exclude sage/categories/functor.* +exclude sage/categories/homset.* +exclude sage/categories/homsets.* +exclude sage/categories/map.* +exclude sage/categories/morphism.* +exclude sage/categories/isomorphic_objects.* +exclude sage/categories/objects.* +exclude sage/categories/primer.* +exclude sage/categories/pushout.* +exclude sage/categories/quotients.* +exclude sage/categories/realizations.* +exclude sage/categories/sets_cat.* +exclude sage/categories/sets_with_partial_maps.* +exclude sage/categories/subobjects.* +exclude sage/categories/subquotients.* +exclude sage/categories/with_realizations.* +# Exclude to make it a namespace package exclude sage/categories/__init__.py -include sage/misc/prandom.* # dep of sage/rings/ring + include sage/rings/ideal.* include sage/rings/ring.* graft sage/typeset # dep of sage.categories.tensor @@ -17,10 +40,12 @@ graft sage/typeset # dep of sage.categories.tensor global-exclude *.c global-exclude *.cpp -include sage/cpython/debugimpl.c -include sage/misc/inherit_comparison_impl.c global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-categories/README.rst b/pkgs/sagemath-categories/README.rst index 81311e5a217..d1f90fea966 100644 --- a/pkgs/sagemath-categories/README.rst +++ b/pkgs/sagemath-categories/README.rst @@ -12,15 +12,27 @@ About SageMath https://www.sagemath.org -SageMath fully supports all major Linux distributions, recent versions of macOS, and Windows (using Cygwin or Windows Subsystem for Linux). +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). -The traditional and recommended way to install SageMath is from source via Sage-the-distribution (https://www.sagemath.org/download-source.html). Sage-the-distribution first builds a large number of open source packages from source (unless it finds suitable versions installed in the system) and then installs the Sage Library (sagelib, implemented in Python and Cython). +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). About this experimental pip-installable source distribution ----------------------------------------------------------- -This pip-installable source distribution `sagemath-categories` is an experimental distribution of a small part of the Sage Library. Use at your own risk. It provides a small subset of the modules of the Sage library ("sagelib", `sagemath-standard`). It is a superset of the `sagemath-objects` (providing Sage objects, the element/parent framework, categories, the coercion system and the related metaclasses), making various additional categories available without introducing dependencies on additional mathematical libraries. +This pip-installable source distribution `sagemath-categories` is an +experimental distribution of a small part of the Sage Library. Use at your own +risk. It provides a small subset of the modules of the Sage library +("sagelib", `sagemath-standard`). It is a superset of the `sagemath-objects` +(providing Sage objects, the element/parent framework, categories, the coercion +system and the related metaclasses), making various additional categories +available without introducing dependencies on additional mathematical +libraries. Dependencies diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sagemath-categories/bin b/pkgs/sagemath-categories/bin deleted file mode 120000 index 1956438021b..00000000000 --- a/pkgs/sagemath-categories/bin +++ /dev/null @@ -1 +0,0 @@ -../sagemath-objects/bin \ No newline at end of file diff --git a/pkgs/sagemath-categories/pyproject.toml.m4 b/pkgs/sagemath-categories/pyproject.toml.m4 deleted file mode 120000 index b65c0df8a46..00000000000 --- a/pkgs/sagemath-categories/pyproject.toml.m4 +++ /dev/null @@ -1 +0,0 @@ -../sagemath-objects/pyproject.toml.m4 \ No newline at end of file diff --git a/pkgs/sagemath-categories/pyproject.toml.m4 b/pkgs/sagemath-categories/pyproject.toml.m4 new file mode 100644 index 00000000000..0afd7849de5 --- /dev/null +++ b/pkgs/sagemath-categories/pyproject.toml.m4 @@ -0,0 +1,14 @@ +[build-system] +# Minimum requirements for the build system to execute. +requires = [ + esyscmd(`sage-get-system-packages install-requires-toml \ + setuptools \ + wheel \ + sage_setup \ + sagemath_environment \ + sagemath_objects \ + cython \ + gmpy2 \ + cysignals \ + ')] +build-backend = "setuptools.build_meta" diff --git a/pkgs/sagemath-categories/sage_setup b/pkgs/sagemath-categories/sage_setup deleted file mode 120000 index 88b8133df49..00000000000 --- a/pkgs/sagemath-categories/sage_setup +++ /dev/null @@ -1 +0,0 @@ -../../src/sage_setup \ No newline at end of file diff --git a/pkgs/sagemath-categories/setup.cfg.m4 b/pkgs/sagemath-categories/setup.cfg.m4 index 4ba67f86fdb..744022da6eb 100644 --- a/pkgs/sagemath-categories/setup.cfg.m4 +++ b/pkgs/sagemath-categories/setup.cfg.m4 @@ -28,21 +28,8 @@ classifiers = python_requires = >=3.8, <3.11 install_requires = esyscmd(`sage-get-system-packages install-requires \ - cython \ - pkgconfig \ - ipython \ - gmpy2 \ - cysignals \ + sagemath_objects \ | sed "2,\$s/^/ /;"')dnl -scripts = - bin/sage - bin/sage-env - bin/sage-eval - bin/sage-fixdoctests - bin/sage-ipython - bin/sage-python - bin/sage-run - bin/sage-runtests - bin/sage-venv-config - bin/sage-version.sh +[options.extras_require] +test = sagemath-repl diff --git a/pkgs/sagemath-categories/tox.ini b/pkgs/sagemath-categories/tox.ini index 7ac63bae0ec..44ca511ac22 100644 --- a/pkgs/sagemath-categories/tox.ini +++ b/pkgs/sagemath-categories/tox.ini @@ -13,17 +13,31 @@ envlist = [testenv] deps = !norequirements: -rrequirements.txt + # tox 3.x does not handle extras when using --installpkg. https://github.com/tox-dev/tox/issues/1576 + sagemath-repl -setenv = - # Sage scripts such as sage-runtests like to use $HOME/.sage - HOME={envdir} +extras = test passenv = + # Variables set by .homebrew-build-env + CPATH + LIBRARY_PATH + PKG_CONFIG_PATH # Parallel build SAGE_NUM_THREADS SAGE_NUM_THREADS_PARALLEL - # SAGE_VENV only for referring to the basepython - sagepython: SAGE_VENV + # SAGE_VENV only for referring to the basepython or finding the wheels + sagepython, sagewheels: SAGE_VENV + # Location of the wheels + sagewheels: SAGE_SPKG_WHEELS + +setenv = + # Sage scripts such as sage-runtests like to use $HOME/.sage + HOME={envdir} + # We supply pip options by environment variables so that they + # apply both to the installation of the dependencies and of the package + sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + nopypi: PIP_NO_INDEX=true whitelist_externals = bash @@ -35,10 +49,19 @@ commands = # Test that importing sage.categories.all initializes categories {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.categories.all import *; SimplicialComplexes(); FunctionFields()' - bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_categories --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' + bash -c 'cd {temp_dir} && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --initial --environment=sage.all__sagemath_categories --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' [testenv:sagepython] basepython = {env:SAGE_VENV}/bin/python3 +[testenv:sagepython-sagewheels-nopypi] +basepython = {env:SAGE_VENV}/bin/python3 + +[testenv:sagepython-sagewheels-nopypi-norequirements] +basepython = {env:SAGE_VENV}/bin/python3 + +[testenv:sagepython-sagewheels] +basepython = {env:SAGE_VENV}/bin/python3 + [testenv:sagepython-norequirements] basepython = {env:SAGE_VENV}/bin/python3 diff --git a/pkgs/sagemath-environment/README.rst b/pkgs/sagemath-environment/README.rst index f5c52660ca8..ba5905777c0 100644 --- a/pkgs/sagemath-environment/README.rst +++ b/pkgs/sagemath-environment/README.rst @@ -8,16 +8,27 @@ About SageMath "Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, and MATLAB" - Copyright (C) 2005-2020 The Sage Development Team + Copyright (C) 2005-2022 The Sage Development Team https://www.sagemath.org -SageMath fully supports all major Linux distributions, recent versions of macOS, and Windows (using Cygwin or Windows Subsystem for Linux). +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). -The traditional and recommended way to install SageMath is from source via Sage-the-distribution (https://www.sagemath.org/download-source.html). Sage-the-distribution first builds a large number of open source packages from source (unless it finds suitable versions installed in the system) and then installs the Sage Library (sagelib, implemented in Python and Cython). +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). About this experimental pip-installable source distribution ----------------------------------------------------------- -This pip-installable source distribution `sagemath-environment` is an experimental distribution of a small part of the Sage Library. Use at your own risk. It provides a small, fundamental subset of the modules of the Sage library ("sagelib", `sagemath-standard`), providing the connection to the system and software environment. +This pip-installable source distribution `sagemath-environment` is an +experimental distribution of a small part of the Sage Library. Use at your own +risk. It provides a small, fundamental subset of the modules of the Sage +library ("sagelib", `sagemath-standard`), providing the connection to the +system and software environment. It also includes the `sage` script for +launching the Sage REPL and accessing various developer tools (see `sage +--help`). diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sagemath-environment/tox.ini b/pkgs/sagemath-environment/tox.ini index 890ffdf0015..f4875e6228c 100644 --- a/pkgs/sagemath-environment/tox.ini +++ b/pkgs/sagemath-environment/tox.ini @@ -16,16 +16,22 @@ isolated_build = True deps = !norequirements: -rrequirements.txt -setenv = - # Sage scripts such as sage-runtests like to use $HOME/.sage - HOME={envdir} - passenv = # Parallel build SAGE_NUM_THREADS SAGE_NUM_THREADS_PARALLEL - # SAGE_VENV only for referring to the basepython - sagepython: SAGE_VENV + # SAGE_VENV only for referring to the basepython or finding the wheels + sagepython, sagewheels: SAGE_VENV + # Location of the wheels + sagewheels: SAGE_SPKG_WHEELS + +setenv = + # Sage scripts such as sage-runtests like to use $HOME/.sage + HOME={envdir} + # We supply pip options by environment variables so that they + # apply both to the installation of the dependencies and of the package + sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + nopypi: PIP_NO_INDEX=true whitelist_externals = bash @@ -37,5 +43,14 @@ commands = [testenv:sagepython] basepython = {env:SAGE_VENV}/bin/python3 +[testenv:sagepython-sagewheels-nopypi] +basepython = {env:SAGE_VENV}/bin/python3 + +[testenv:sagepython-sagewheels-nopypi-norequirements] +basepython = {env:SAGE_VENV}/bin/python3 + +[testenv:sagepython-sagewheels] +basepython = {env:SAGE_VENV}/bin/python3 + [testenv:sagepython-norequirements] basepython = {env:SAGE_VENV}/bin/python3 diff --git a/pkgs/sagemath-objects/MANIFEST.in b/pkgs/sagemath-objects/MANIFEST.in index d112d9b5c16..ffa9e9c7f10 100644 --- a/pkgs/sagemath-objects/MANIFEST.in +++ b/pkgs/sagemath-objects/MANIFEST.in @@ -1,15 +1,10 @@ prune sage graft sage/cpython -graft sage_setup # FIXME: Vendor it until we have made a new sage_setup release -include sage/env.py # FIXME: sage_setup must be changed so it does not depend on it -include sage/version.py # FIXME: likewise -include sage/misc/package_dir.p* # For sage_setup include VERSION.txt global-include all__sagemath_objects.py -graft sage/features graft sage/structure include sage/categories/action.* include sage/categories/algebra_functor.* @@ -67,6 +62,9 @@ include sage/misc/instancedoc.* # dep of sage/misc/lazy_import include sage/misc/persist.* include sage/misc/sage_unittest.* # dep of sage/misc/persist +include sage/misc/randstate.* # used in sage.doctest +include sage/misc/prandom.* # dep of sage/rings/ring + include sage/ext/stdsage.pxd include sage/sets/pythonclass.* include sage/arith/power.* @@ -82,28 +80,9 @@ graft sage/libs/gmp # sage/misc/latex -- this should really go to another package -## For doctesting -- this duplication will be removed in #28925 -global-include all__sagemath_environment.py -global-include all__sagemath_repl.py -include bin/sage -include bin/sage-env -include bin/sage-env-config -include bin/sage-python -include bin/sage-runtests -graft sage/doctest -include sage/misc/temporary_file.* -include sage/misc/randstate.* -include sage/misc/misc.* # walltime, cputime -# graft sage/features -include sage/misc/package.* -include sage/misc/sagedoc.py -include sage/misc/banner.py -include sage/misc/sage_input.py -include sage/misc/sage_eval.py -include sage/misc/viewer.py - -graft sage/repl -graft sage/server +## FIXME: Needed for doctesting +include sage/misc/misc.* # walltime, cputime used in sage.doctest + global-exclude *.c global-exclude *.cpp @@ -114,3 +93,7 @@ global-exclude __pycache__ global-exclude *.py[co] global-exclude *.bak global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-objects/README.rst b/pkgs/sagemath-objects/README.rst index 8058f633654..9dc9cfd888f 100644 --- a/pkgs/sagemath-objects/README.rst +++ b/pkgs/sagemath-objects/README.rst @@ -12,15 +12,25 @@ About SageMath https://www.sagemath.org -SageMath fully supports all major Linux distributions, recent versions of macOS, and Windows (using Cygwin or Windows Subsystem for Linux). +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). -The traditional and recommended way to install SageMath is from source via Sage-the-distribution (https://www.sagemath.org/download-source.html). Sage-the-distribution first builds a large number of open source packages from source (unless it finds suitable versions installed in the system) and then installs the Sage Library (sagelib, implemented in Python and Cython). +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). About this experimental pip-installable source distribution ----------------------------------------------------------- -This pip-installable source distribution `sagemath-objects` is an experimental distribution of a small part of the Sage Library. Use at your own risk. It provides a small, fundamental subset of the modules of the Sage library ("sagelib", `sagemath-standard`), making Sage objects, the element/parent framework, categories, the coercion system and the related metaclasses available. +This pip-installable source distribution `sagemath-objects` is an experimental +distribution of a small part of the Sage Library. Use at your own risk. It +provides a small, fundamental subset of the modules of the Sage library +("sagelib", `sagemath-standard`), making Sage objects, the element/parent +framework, categories, the coercion system and the related metaclasses +available. Dependencies diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sagemath-objects/bin/sage b/pkgs/sagemath-objects/bin/sage deleted file mode 120000 index 028392920ce..00000000000 --- a/pkgs/sagemath-objects/bin/sage +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-env b/pkgs/sagemath-objects/bin/sage-env deleted file mode 120000 index e35bf8a4000..00000000000 --- a/pkgs/sagemath-objects/bin/sage-env +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-env \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-eval b/pkgs/sagemath-objects/bin/sage-eval deleted file mode 120000 index ac096cd38f1..00000000000 --- a/pkgs/sagemath-objects/bin/sage-eval +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-eval \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-fixdoctests b/pkgs/sagemath-objects/bin/sage-fixdoctests deleted file mode 120000 index 3d394f77c44..00000000000 --- a/pkgs/sagemath-objects/bin/sage-fixdoctests +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-fixdoctests \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-ipython b/pkgs/sagemath-objects/bin/sage-ipython deleted file mode 120000 index 00b3d2b0c50..00000000000 --- a/pkgs/sagemath-objects/bin/sage-ipython +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-ipython \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-python b/pkgs/sagemath-objects/bin/sage-python deleted file mode 120000 index 26d8bde2c71..00000000000 --- a/pkgs/sagemath-objects/bin/sage-python +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-python \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-run b/pkgs/sagemath-objects/bin/sage-run deleted file mode 120000 index a2bce45f085..00000000000 --- a/pkgs/sagemath-objects/bin/sage-run +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-run \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-runtests b/pkgs/sagemath-objects/bin/sage-runtests deleted file mode 120000 index 8e3dbbaf100..00000000000 --- a/pkgs/sagemath-objects/bin/sage-runtests +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-runtests \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-venv-config b/pkgs/sagemath-objects/bin/sage-venv-config deleted file mode 120000 index d1e0d8ec19b..00000000000 --- a/pkgs/sagemath-objects/bin/sage-venv-config +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-venv-config \ No newline at end of file diff --git a/pkgs/sagemath-objects/bin/sage-version.sh b/pkgs/sagemath-objects/bin/sage-version.sh deleted file mode 120000 index 46cfd0287a5..00000000000 --- a/pkgs/sagemath-objects/bin/sage-version.sh +++ /dev/null @@ -1 +0,0 @@ -../../../src/bin/sage-version.sh \ No newline at end of file diff --git a/pkgs/sagemath-objects/pyproject.toml.m4 b/pkgs/sagemath-objects/pyproject.toml.m4 index 0a0149b9e45..c13665be51d 100644 --- a/pkgs/sagemath-objects/pyproject.toml.m4 +++ b/pkgs/sagemath-objects/pyproject.toml.m4 @@ -5,6 +5,7 @@ requires = [ setuptools \ wheel \ sage_setup \ + sagemath_environment \ cython \ gmpy2 \ cysignals \ diff --git a/pkgs/sagemath-objects/sage_setup b/pkgs/sagemath-objects/sage_setup deleted file mode 120000 index 88b8133df49..00000000000 --- a/pkgs/sagemath-objects/sage_setup +++ /dev/null @@ -1 +0,0 @@ -../../src/sage_setup \ No newline at end of file diff --git a/pkgs/sagemath-objects/setup.cfg.m4 b/pkgs/sagemath-objects/setup.cfg.m4 index 00c65ca9f8a..cd5d4f72a9e 100644 --- a/pkgs/sagemath-objects/setup.cfg.m4 +++ b/pkgs/sagemath-objects/setup.cfg.m4 @@ -28,21 +28,22 @@ classifiers = python_requires = >=3.8, <3.11 install_requires = esyscmd(`sage-get-system-packages install-requires \ - cython \ - pkgconfig \ - ipython \ gmpy2 \ cysignals \ | sed "2,\$s/^/ /;"')dnl -scripts = - bin/sage - bin/sage-env - bin/sage-eval - bin/sage-fixdoctests - bin/sage-ipython - bin/sage-python - bin/sage-run - bin/sage-runtests - bin/sage-venv-config - bin/sage-version.sh +[options.extras_require] +# Currently we do not use the sage doctester to test sagemath-objects, +# so we do not list sagemath-repl here. +test = + + +[options.package_data] +sage.cpython = + pyx_visit.h + string_impl.h + cython_metaclass.h + python_debug.h + +sage.rings = + integer_fake.h diff --git a/pkgs/sagemath-objects/tox.ini b/pkgs/sagemath-objects/tox.ini index e03cbab1c3c..babc128ff0c 100644 --- a/pkgs/sagemath-objects/tox.ini +++ b/pkgs/sagemath-objects/tox.ini @@ -14,16 +14,28 @@ envlist = deps = !norequirements: -rrequirements.txt -setenv = - # Sage scripts such as sage-runtests like to use $HOME/.sage - HOME={envdir} +extras = test passenv = + # Variables set by .homebrew-build-env + CPATH + LIBRARY_PATH + PKG_CONFIG_PATH # Parallel build SAGE_NUM_THREADS SAGE_NUM_THREADS_PARALLEL - # SAGE_VENV only for referring to the basepython - sagepython: SAGE_VENV + # SAGE_VENV only for referring to the basepython or finding the wheels + sagepython, sagewheels: SAGE_VENV + # Location of the wheels + sagewheels: SAGE_SPKG_WHEELS + +setenv = + # Sage scripts such as sage-runtests like to use $HOME/.sage + HOME={envdir} + # We supply pip options by environment variables so that they + # apply both to the installation of the dependencies and of the package + sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + nopypi: PIP_NO_INDEX=true whitelist_externals = bash @@ -34,10 +46,19 @@ commands = {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); from sage.all__sagemath_objects import *' - #bash -c 'cd bin && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_objects --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' + #bash -c 'cd {temp_dir} && SAGE_SRC=$(python -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_objects --initial --optional=sage $SAGE_SRC/sage/structure || echo "(lots of doctest failures are expected)"' [testenv:sagepython] basepython = {env:SAGE_VENV}/bin/python3 +[testenv:sagepython-sagewheels-nopypi] +basepython = {env:SAGE_VENV}/bin/python3 + +[testenv:sagepython-sagewheels-nopypi-norequirements] +basepython = {env:SAGE_VENV}/bin/python3 + +[testenv:sagepython-sagewheels] +basepython = {env:SAGE_VENV}/bin/python3 + [testenv:sagepython-norequirements] basepython = {env:SAGE_VENV}/bin/python3 diff --git a/pkgs/sagemath-repl/MANIFEST.in b/pkgs/sagemath-repl/MANIFEST.in index 9bee69fd999..c54f63b15ee 100644 --- a/pkgs/sagemath-repl/MANIFEST.in +++ b/pkgs/sagemath-repl/MANIFEST.in @@ -11,4 +11,11 @@ include sage/misc/sage_eval.py include VERSION.txt +global-exclude __pycache__ global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/pkgs/sagemath-repl/README.rst b/pkgs/sagemath-repl/README.rst index c240fbc1bac..3dde4aae5e5 100644 --- a/pkgs/sagemath-repl/README.rst +++ b/pkgs/sagemath-repl/README.rst @@ -8,16 +8,25 @@ About SageMath "Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, and MATLAB" - Copyright (C) 2005-2020 The Sage Development Team + Copyright (C) 2005-2022 The Sage Development Team https://www.sagemath.org -SageMath fully supports all major Linux distributions, recent versions of macOS, and Windows (using Cygwin or Windows Subsystem for Linux). +SageMath fully supports all major Linux distributions, recent versions of +macOS, and Windows (using Cygwin or Windows Subsystem for Linux). -The traditional and recommended way to install SageMath is from source via Sage-the-distribution (https://www.sagemath.org/download-source.html). Sage-the-distribution first builds a large number of open source packages from source (unless it finds suitable versions installed in the system) and then installs the Sage Library (sagelib, implemented in Python and Cython). +The traditional and recommended way to install SageMath is from source via +Sage-the-distribution (https://www.sagemath.org/download-source.html). +Sage-the-distribution first builds a large number of open source packages from +source (unless it finds suitable versions installed in the system) and then +installs the Sage Library (sagelib, implemented in Python and Cython). About this experimental pip-installable source distribution ----------------------------------------------------------- -This pip-installable source distribution `sagemath-repl` is an experimental distribution of a small part of the Sage Library. Use at your own risk. It provides a small, fundamental subset of the modules of the Sage library ("sagelib", `sagemath-standard`), providing the IPython kernel, Sage preparser, and doctester. +This pip-installable source distribution `sagemath-repl` is an experimental +distribution of a small part of the Sage Library. Use at your own risk. It +provides a small, fundamental subset of the modules of the Sage library +("sagelib", `sagemath-standard`), providing the IPython kernel, Sage preparser, +and doctester. diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/pkgs/sagemath-repl/setup.cfg.m4 b/pkgs/sagemath-repl/setup.cfg.m4 index f8757ee66cb..96515e21499 100644 --- a/pkgs/sagemath-repl/setup.cfg.m4 +++ b/pkgs/sagemath-repl/setup.cfg.m4 @@ -18,14 +18,14 @@ classifiers = Operating System :: POSIX Operating System :: MacOS :: MacOS X Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Programming Language :: Python :: Implementation :: CPython Topic :: Scientific/Engineering :: Mathematics [options] -python_requires = >=3.7, <3.11 +python_requires = >=3.8, <3.11 install_requires = esyscmd(`sage-get-system-packages install-requires \ sagemath_objects \ diff --git a/pkgs/sagemath-repl/tox.ini b/pkgs/sagemath-repl/tox.ini index a7e321104cd..b564bcda707 100644 --- a/pkgs/sagemath-repl/tox.ini +++ b/pkgs/sagemath-repl/tox.ini @@ -16,16 +16,26 @@ isolated_build = True deps = !norequirements: -rrequirements.txt -setenv = - # Sage scripts such as sage-runtests like to use $HOME/.sage - HOME={envdir} - passenv = + # Variables set by .homebrew-build-env + CPATH + LIBRARY_PATH + PKG_CONFIG_PATH # Parallel build SAGE_NUM_THREADS SAGE_NUM_THREADS_PARALLEL - # SAGE_VENV only for referring to the basepython - sagepython: SAGE_VENV + # SAGE_VENV only for referring to the basepython or finding the wheels + sagepython, sagewheels: SAGE_VENV + # Location of the wheels + sagewheels: SAGE_SPKG_WHEELS + +setenv = + # Sage scripts such as sage-runtests like to use $HOME/.sage + HOME={envdir} + # We supply pip options by environment variables so that they + # apply both to the installation of the dependencies and of the package + sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} + nopypi: PIP_NO_INDEX=true whitelist_externals = bash @@ -34,10 +44,19 @@ commands = # Beware of the treacherous non-src layout. "./sage/" shadows the installed sage package. {envpython} -c 'import sys; "" in sys.path and sys.path.remove(""); import sage.repl.all; import sage.doctest.all' - bash -c 'cd bin && SAGE_SRC=$({envpython} -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_repl --optional=sage $SAGE_SRC/sage/repl $SAGE_SRC/sage/doctest $SAGE_SRC/sage/misc/sage_input.py $SAGE_SRC/sage/misc/sage_eval.py || echo "(lots of doctest failures are expected)"' + bash -c 'cd bin && SAGE_SRC=$({envpython} -c "from sage.env import SAGE_SRC; print(SAGE_SRC)") && sage-runtests --environment=sage.all__sagemath_repl --initial --optional=sage $SAGE_SRC/sage/repl $SAGE_SRC/sage/doctest $SAGE_SRC/sage/misc/sage_input.py $SAGE_SRC/sage/misc/sage_eval.py || echo "(lots of doctest failures are expected)"' [testenv:sagepython] basepython = {env:SAGE_VENV}/bin/python3 +[testenv:sagepython-sagewheels-nopypi] +basepython = {env:SAGE_VENV}/bin/python3 + +[testenv:sagepython-sagewheels-nopypi-norequirements] +basepython = {env:SAGE_VENV}/bin/python3 + +[testenv:sagepython-sagewheels] +basepython = {env:SAGE_VENV}/bin/python3 + [testenv:sagepython-norequirements] basepython = {env:SAGE_VENV}/bin/python3 diff --git a/pkgs/sagemath-standard/tox.ini b/pkgs/sagemath-standard/tox.ini index 75e72ae32bd..f021a7d2b22 100644 --- a/pkgs/sagemath-standard/tox.ini +++ b/pkgs/sagemath-standard/tox.ini @@ -84,8 +84,7 @@ passenv = SAGE_NUM_THREADS # SAGE_VENV only for referring to the basepython or finding the wheels sagepython, sagewheels: SAGE_VENV - # Location of the wheels (needs to include a PEP 503 compliant - # Simple Repository index, i.e., a subdirectory "simple") + # Location of the wheels sagewheels: SAGE_SPKG_WHEELS setenv = diff --git a/src/VERSION.txt b/src/VERSION.txt index aadd65deb15..737bfe2c1d2 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta1 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 802ca805250..4f92b35ee39 100644 --- a/src/bin/sage-version.sh +++ b/src/bin/sage-version.sh @@ -4,6 +4,6 @@ # which stops "setup.py develop" from rewriting it as a Python file. : # This file is auto-generated by the sage-update-version script, do not edit! -SAGE_VERSION='9.8.beta0' -SAGE_RELEASE_DATE='2022-09-25' -SAGE_VERSION_BANNER='SageMath version 9.8.beta0, Release Date: 2022-09-25' +SAGE_VERSION='9.8.beta1' +SAGE_RELEASE_DATE='2022-09-29' +SAGE_VERSION_BANNER='SageMath version 9.8.beta1, Release Date: 2022-09-29' diff --git a/src/doc/en/developer/git_trac.rst b/src/doc/en/developer/git_trac.rst index 580c791ce60..25977e5ef23 100644 --- a/src/doc/en/developer/git_trac.rst +++ b/src/doc/en/developer/git_trac.rst @@ -17,6 +17,8 @@ perform every development task with just git and a web browser. Installing the Git-Trac Command =============================== +:: + [user@localhost]$ git clone https://github.com/sagemath/git-trac-command.git Cloning into 'git-trac-command'... [...] diff --git a/src/doc/en/developer/packaging.rst b/src/doc/en/developer/packaging.rst index 33ca56415f8..8f084b38ff6 100644 --- a/src/doc/en/developer/packaging.rst +++ b/src/doc/en/developer/packaging.rst @@ -1106,7 +1106,7 @@ set the ``upstream_url`` field in ``checksums.ini`` described above. For Python packages available from PyPI, you can use:: - [user@localhost]$ sage -package create scikit_spatial --pypi --type optional + [user@localhost]$ sage --package create scikit_spatial --pypi --type optional This automatically downloads the most recent version from PyPI and also obtains most of the necessary information by querying PyPI. @@ -1117,7 +1117,11 @@ in the file ``install-requires.txt``. To create a pip package rather than a normal package, you can use:: - [user@localhost]$ sage -package create scikit_spatial --pypi --source pip --type optional + [user@localhost]$ sage --package create scikit_spatial --pypi --source pip --type optional + +To create a wheel package rather than a normal package, you can use:: + + [user@localhost]$ sage --package create scikit_spatial --pypi --source wheel --type optional .. _section-manual-build: diff --git a/src/doc/en/developer/packaging_sage_library.rst b/src/doc/en/developer/packaging_sage_library.rst index 536e1da5913..c792b8ee68e 100644 --- a/src/doc/en/developer/packaging_sage_library.rst +++ b/src/doc/en/developer/packaging_sage_library.rst @@ -487,26 +487,49 @@ Hierarchy of distribution packages def node(label, pos): return text(label, (3*pos[0],2*pos[1]), background_color='pink', color='black') def edge(start, end, **kwds): - return arrow((3*start[0],2*start[1]+.5),(3*end[0],2*end[1]-.5), arrowsize=2, **kwds) + return arrow((3*start[0],2*start[1]),(3*end[0],2*end[1]-.28), arrowsize=2, **kwds) def extras_require(start, end): return edge(start, end, linestyle='dashed') g = Graphics() - g += (node("sage_conf", (0.5,0)) + extras_require((0.5,0),(0.5,1))) - g += (node("sagemath-objects", (1.5,0)) + edge((1.5,0),(1.5,1))) - g += (node("sagemath-environment", (0.5,1)) - + edge((0.5,1),(0,2)) + edge((0.5,1),(1,2)) + edge((0.5,1),(2,2))) - g += (node("sagemath-categories", (1.5,1)) + edge((1.5,1),(0,2)) + - edge((1.5,1),(1,2)) + edge((1.5,1),(2,2))) - g += (node("sagemath-graphs", (0,2)) + node("sagemath-polyhedra", (1,2)) + node("sagemath-singular", (2,2)) + - edge((0,2),(0,3)) + edge((0,2),(1,3)) + edge((1,2),(1,3)) + edge((2,2),(2,3))) - g += (node("sagemath-tdlib", (0,3)) + node("sagemath-standard-no-symbolics", (1,3)) + node("sagemath-symbolics", (2,3)) + - edge((1,3),(1,4)) + edge((2,3),(1,4))) + g += (extras_require((0.5,0),(0.5,1)) + node("sage_conf", (0.5,0))) + g += (edge((1.5,0),(0.75,2)) + edge((1.5,0),(1.5,1)) + + node("sagemath-objects", (1.5,0))) + g += (edge((0.5,1),(0,2)) + edge((0.5,1),(0.6,2)) + edge((0.5,1),(1.25,2)) + edge((0.5,1),(1.8,2)) + + node("sagemath-environment", (0.5,1))) + g += (edge((1.5,1),(0.2,2)) + edge((1.5,1),(1.41,2)) + edge((1.5,1),(2,2)) + + node("sagemath-categories", (1.5,1))) + g += (edge((0,2),(0,3)) + edge((0,2),(0.75,3)) + edge((0.67,2),(1,3)) + edge((1.33,2),(1.25,3)) + edge((2,2),(2,3)) + + node("sagemath-graphs", (0,2)) + node("sagemath-repl", (0.67,2)) + node("sagemath-polyhedra", (1.33,2)) + node("sagemath-singular", (2,2))) + g += (edge((1,3),(1,4)) + edge((2,3),(1.2,4)) + + node("sagemath-tdlib", (0,3)) + node("sagemath-standard-no-symbolics", (1,3)) + node("sagemath-symbolics", (2,3))) g += node("sagemath-standard", (1,4)) sphinx_plot(g, figsize=(8, 4), axes=False) Solid arrows indicate ``install_requires``, i.e., a declared runtime dependency. Dashed arrows indicate ``extras_require``, i.e., a declared optional runtime dependency. +Not shown in the diagram are build dependencies and optional dependencies for testing. + +- `sage_conf `_ is a configuration + module. It provides the configuration variable settings determined by the + ``configure`` script. + +- `sagemath-environment `_ + provides the connection to the system and software environment. It includes + :mod:`sage.env`, :mod:`sage.features`, :mod:`sage.misc.package_dir`, etc. + +- `sagemath-objects `_ + provides a small fundamental subset of the modules of the Sage library, + in particular all of :mod:`sage.structure`, a small portion of :mod:`sage.categories`, + and a portion of :mod:`sage.misc`. + +- `sagemath-categories `_ + provides a small subset of the modules of the Sage library, building upon sagemath-objects. + It provides all of :mod:`sage.categories` and a small portion of :mod:`sage.rings`. + +- `sagemath-repl `_ provides + the IPython kernel and Sage preparser (:mod:`sage.repl`), + the Sage doctester (:mod:`sage.doctest`), and some related modules from :mod:`sage.misc`. Testing distribution packages diff --git a/src/doc/en/installation/source.rst b/src/doc/en/installation/source.rst index ca362d68d3e..879c15f4847 100644 --- a/src/doc/en/installation/source.rst +++ b/src/doc/en/installation/source.rst @@ -38,12 +38,6 @@ will not need to read them. Prerequisites ------------- -General requirements -~~~~~~~~~~~~~~~~~~~~ - -This section details the technical prerequisites needed on all platforms. See -also the `System-specific requirements`_ below. - Disk space and memory ^^^^^^^^^^^^^^^^^^^^^ @@ -51,169 +45,76 @@ Your computer comes with at least 6 GB of free disk space. It is recommended to have at least 2 GB of RAM, but you might get away with less (be sure to have some swap space in this case). -Command-line tools -^^^^^^^^^^^^^^^^^^ - -In addition to standard :wikipedia:`POSIX ` utilities -and the :wikipedia:`bash ` shell, -the following standard command-line development tools must be installed on your -computer: - -- A **C/C++ compiler**: GCC versions 8.x to 12.x are supported. - Clang (LLVM) is also supported. - See also `Using alternative compilers`_. -- **make**: GNU make, version 3.80 or later. Version 3.82 or later is recommended. -- **m4**: GNU m4 1.4.2 or later (non-GNU or older versions might also work). -- **perl**: version 5.8.0 or later. -- **ar** and **ranlib**: can be obtained as part of GNU binutils. -- **tar**: GNU tar version 1.17 or later, or BSD tar. -- **python**: Python 3.4 or later, or Python 2.7. - (This range of versions is a minimal requirement for internal purposes of the SageMath - build system, which is referred to as ``sage-bootstrap-python``.) - -Other versions of these may work, but they are untested. - - -Fortran and compiler suites -########################### - -Sage installation also needs a Fortran compiler. It is determined -automatically whether Sage's GCC package, or just its part containing -Fortran compiler ``gfortran`` needs to be installed. This can be -overwritten by running ``./configure`` with option -``--without-system-gcc``. - -Officially we support -gfortran from `GNU Compiler Collection (GCC) `_. -If C and C++ compilers also come from there (i.e., gcc and g++), their versions -should match. -Alternatively, one may use C and C++ compilers from -`Clang: a C language family frontend for LLVM `_, -and thus matching versions of -clang, clang++ , along with a recent gfortran. (Flang (or other LLVM-based -Fortran compilers) are not officially supported, however it is possible to -to build Sage using flang, with some extra efforts needed to set various flags; -this is work in progress at the moment (May 2019)). - -Therefore, if you plan on using your own GCC compilers, then make sure that -their versions match. - -To force using specific compilers, set environment variables ``CC``, -``CXX``, and ``FC`` (for C, C++, and Fortran compilers, respectively) -to the desired values, and run ``./configure``. For example, -``./configure CC=clang CXX=clang++ FC=gfortran`` will configure Sage -to be built with Clang C/C++ compilers and Fortran compiler -``gfortran``. - -Alternatively, Sage includes a GCC package, so that C, C++ and Fortran -compilers will be built when the build system detects that it is needed, -e.g., non-GCC compilers, or -versions of the GCC compilers known to miscompile some components of Sage, -or simply a missing Fortran compiler. -In any case, you always need at least a C/C++ compiler to build the GCC -package and its prerequisites before the compilers it provides can be used. - -Note that you can always override this behavior through the configure -options ``--without-system-gcc`` and ``--with-system-gcc``, see -:ref:`section_compilers`. - -There are some known problems with old assemblers, in particular when -building the ``ecm`` and ``fflas_ffpack`` packages. You should ensure -that your assembler understands all instructions for your -processor. On Linux, this means you need a recent version of -``binutils``; on macOS you need a recent version of Xcode. - -Python for venv -^^^^^^^^^^^^^^^ +Software prerequisites and recommended packages +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sage depends on `a large number of software packages +<../reference/spkg/index.html>`_. Sage provides its own software +distribution providing most of these packages, so you do not have to +worry about having to download and install these packages yourself. -By default, Sage will try to use system's ``python3`` to set up a virtual -environment, a.k.a. `venv `_ -rather than building a Python 3 installation from scratch. -Use the ``configure`` option ``--without-system-python3`` in case you want Python 3 -built from scratch. - -Sage will accept versions 3.8.x to 3.10.x. - -You can also use ``--with-python=/path/to/python3_binary`` to tell Sage to use -``/path/to/python3_binary`` to set up the venv. Note that setting up venv requires -a number of Python modules to be available within the Python in question. Currently, -for Sage 9.6, these modules are as follows: ``sqlite3``, ``ctypes``, ``math``, -``hashlib``, ``crypt``, ``socket``, ``zlib``, ``distutils.core``, ``ssl`` - -they will be checked for by the ``configure`` script. - -Other notes -^^^^^^^^^^^ - -After extracting the Sage source tarball, the subdirectory :file:`upstream` -contains the source distributions for everything on which Sage depends. - -If cloned from a git repository, the upstream tarballs will be downloaded, -verified, and cached as part of the Sage installation process. -We emphasize that all of this software is included with Sage, so you do not -have to worry about trying to download and install any one of these packages -(such as Python, for example) yourself. - -When the Sage installation program is run, -it will check that you have each of the above-listed prerequisites, -and inform you of any that are missing, or have unsuitable versions. - -System-specific requirements -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -On macOS, there are various developer tools needed which may require -some registration on Apple's developer site; see -:ref:`section_macprereqs`. - -On Redhat-derived systems not all perl components are installed by -default and you might have to install the ``perl-ExtUtils-MakeMaker`` -package. - -On Linux systems (e.g., Ubuntu, Redhat, etc), ``ar`` and ``ranlib`` are in the -`binutils `_ package. -The other programs are usually located in packages with their respective names. -Assuming you have sufficient privileges, you can install the ``binutils`` and -other necessary/standard components. The lists provided below are longer than -the minimal prerequisites, which are basically ``binutils``, ``gcc``/``clang``, ``make``, -``tar``, but there is no real need to build compilers and other standard tools -and libraries on a modern Linux system, in order to be able to build Sage. +If you extracted Sage from a source tarball, the subdirectory +:file:`upstream` contains the source distributions for all standard +packages on which Sage depends. If cloned from a git repository, the +upstream tarballs will be downloaded, verified, and cached as part of +the Sage installation process. + +However, there are minimal prerequisites for building Sage that +already must be installed on your system: + +- `Fundamental system packages required for installing from source + <../reference/spkg/_prereq.html>`_ + +- `C/C++ compilers <../reference/spkg/gcc.html>`_ + +If you have sufficient privileges (for example, on Linux you can +use ``sudo`` to become the ``root`` user), then you can install these packages +using the commands for your platform indicated in the pages linked above. If you do not have the privileges to do this, ask your system administrator to -do this, or build the components from source code. -The method of installing additional software varies from distribution to -distribution, but on a `Debian `_ based system (e.g. -`Ubuntu `_ or `Mint `_), -you would use -:wikipedia:`apt-get `. +do this for you. + +In addition to these minimal prerequisites, we strongly recommend to use system +installations of the following: -Installing prerequisites -~~~~~~~~~~~~~~~~~~~~~~~~ +- `Fortran compiler <../reference/spkg/gfortran.html>`_ -To check if you have the above prerequisites installed, for example ``perl``, -type:: +- `Python <../reference/spkg/python3.html>`_ - $ command -v perl +Sage developers will also need the `system packages required for +bootstrapping <../reference/spkg/_bootstrap.html>`_; they cannot be +installed by Sage. -or:: +When the ``./configure`` script runs, it will check for the presence of many +packages (including the above) and inform you of any that are +missing or have unsuitable versions. **Please read the messages that +``./configure`` prints:** It will inform you which additional system packages +you can install to avoid having to build them from source. This can save a lot of +time. - $ which perl +The following sections provide the commands to install a large +recommended set of packages on various systems, which will minimize +the time it takes to build Sage. This is intended as a convenient +shortcut, but of course you can choose to take a more fine-grained +approach. -on the command line. If it gives an error (or returns nothing), then -either ``perl`` is not installed, or it is installed but not in your -:wikipedia:`PATH `. .. _sec-installation-from-sources-linux-recommended-installation: -Debian/Ubuntu prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Debian/Ubuntu package installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -On Debian ("buster" or newer) or Ubuntu ("bionic" or newer): +On Debian ("buster" or newer) or Ubuntu ("bionic" or newer), we recommend that you +install: .. literalinclude:: debian.txt -If you wish to do Sage development, additionally install the following: +If you wish to do Sage development, we recommend that you additionally +install the following: .. literalinclude:: debian-develop.txt -For all users, we recommend the following: +For all users, we recommend that you install the following system packages, +which provide additional functionality and cannot be installed by Sage: .. literalinclude:: debian-recommended.txt @@ -223,16 +124,20 @@ install: .. literalinclude:: debian-optional.txt -Fedora/Redhat/CentOS prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Fedora/Redhat/CentOS package installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On Fedora/Redhat/CentOS, we recommend that you install: .. literalinclude:: fedora.txt -If you wish to do Sage development, additionally install the following: +If you wish to do Sage development, we recommend that you additionally +install the following: .. literalinclude:: fedora-develop.txt -For all users, we recommend the following: +For all users, we recommend that you install the following system packages, +which provide additional functionality and cannot be installed by Sage: .. literalinclude:: fedora-recommended.txt @@ -242,16 +147,20 @@ install: .. literalinclude:: fedora-optional.txt -Arch Linux prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Arch Linux package installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On ArchLinux, we recommend that you install: .. literalinclude:: arch.txt -If you wish to do Sage development, additionally install the following: +If you wish to do Sage development, we recommend that you additionally +install the following: .. literalinclude:: arch-develop.txt -For all users, we recommend the following: +For all users, we recommend that you install the following system packages, +which provide additional functionality and cannot be installed by Sage: .. literalinclude:: arch-recommended.txt @@ -261,16 +170,20 @@ install: .. literalinclude:: arch-optional.txt -OpenSUSE prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +OpenSUSE package installation +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +On OpenSUSE, we recommend that you install: .. literalinclude:: opensuse.txt -If you wish to do Sage development, additionally install the following: +If you wish to do Sage development, we recommend that you additionally +install the following: .. literalinclude:: opensuse-develop.txt -For all users, we recommend the following: +For all users, we recommend that you install the following system packages, +which provide additional functionality and cannot be installed by Sage: .. literalinclude:: opensuse-recommended.txt @@ -282,8 +195,8 @@ install: .. _section_macprereqs: -macOS prerequisite installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +macOS prerequisites +^^^^^^^^^^^^^^^^^^^ On macOS systems, you need a recent version of `Command Line Tools `_. @@ -312,25 +225,11 @@ a registration. to Command Line Tools. +macOS package installation +^^^^^^^^^^^^^^^^^^^^^^^^^^ -macOS recommended installation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Although Sage can in theory build its own version of gfortran, this -can take a while, and the process fails on some recent versions of -OS X. So instead you can install your own copy. One advantage of this -is that you can install it once, and it will get used every time you -build Sage, rather than building gfortran every time. - -One way to do that is with the `Homebrew package manager -`_. Install Homebrew as their web page describes, and -then the command :: - - $ brew install gcc - -will install Homebrew's gcc package, which includes gfortran. Sage -will also use other Homebrew packages, if they are present. You can -install the following: +If you use the `Homebrew package manager +`_, you can install the following: .. literalinclude:: homebrew.txt @@ -344,11 +243,13 @@ Sage, run :: command like this to your shell profile if you want the settings to persist between shell sessions. -If you wish to do Sage development, additionally install the following: +If you wish to do Sage development, we recommend that you additionally +install the following: .. literalinclude:: homebrew-develop.txt -For all users, we recommend the following: +For all users, we recommend that you install the following system packages, +which provide additional functionality and cannot be installed by Sage: .. literalinclude:: homebrew-recommended.txt @@ -547,50 +448,6 @@ If you don't want conda to be used by sage, deactivate conda (for the current sh Then SageMath will be built either using the compilers provided by the operating system, or its own compilers. -Specific notes for ``make`` and ``tar`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -On macOS, the system-wide BSD ``tar`` supplied will build Sage, so there is no -need to install the GNU ``tar``. - -.. _section_compilers: - -Using alternative compilers -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Sage developers tend to use fairly recent versions of GCC. -Nonetheless, the Sage build process on Linux -should succeed with any reasonable C/C++ compiler; -(we do not recommend GCC older than version 5.1). -This is because Sage will build GCC first (if needed) and then use that newly -built GCC to compile Sage. - -If you don't want this and want to try building Sage with a different set of -compilers, -you need to pass Sage's ``./configure`` compiler names, via environment -variables ``CC``, ``CXX``, and ``FC``, for C, C++, and Fortran compilers, -respectively, e.g. if you C compiler is ``clang``, your C++ compiler is ``clang++``, -and your Fortran compiler is ``flang`` then you would need to run:: - - $ CC=clang CXX=clang++ FC=flang ./configure - -before running ``make``. It is recommended that you inspect the output of ``./configure`` -in order to check that Sage will not try to build GCC. Namely, there should be lines like:: - - gcc-7.2.0 will not be installed (configure check) - ... - gfortran-7.2.0 will not be installed (configure check) - -indicating that Sage will not attempt to build ``gcc/g++/gfortran``. - -If you are interested in working on support for commercial compilers from -`HP `_, -`IBM `_, -`Intel `_, -`Sun/Oracle `_, -etc, -please email the sage-devel mailing list at https://groups.google.com/group/sage-devel. - Additional software ------------------- @@ -702,7 +559,7 @@ General procedure serious consequences if you are logged in as root. Typing ``make`` performs the usual steps for each Sage's dependency, - but installs all the resulting files into the local build tree. + but installs all the resulting files into the installation prefix. Depending on the age and the architecture of your system, it can take from a few tens of minutes to several hours to build Sage from source. On really slow hardware, it can even take a few days to build Sage. @@ -867,9 +724,10 @@ General procedure Now typing ``sage`` within your terminal emulator should start Sage. #. Optional: - Install optional Sage packages and databases. - Type ``sage --optional`` to see a list of them (this requires an Internet - connection), or visit https://www.sagemath.org/packages/optional/. + Install optional Sage packages and databases. See `the list of optional packages + in the reference manual <../reference/spkg/index.html#optional-packages>`_ for + detailed information, or type ``sage --optional`` (this requires an Internet connection). + Then type ``sage -i `` to automatically download and install a given package. @@ -1331,4 +1189,4 @@ a single copy of Sage in a multi-user computer network. $ sudo chown -R root SAGE_LOCAL -**This page was last updated in May 2022 (Sage 9.7).** +**This page was last updated in September 2022 (Sage 9.8).** diff --git a/src/doc/en/reference/discrete_geometry/index.rst b/src/doc/en/reference/discrete_geometry/index.rst index 0289ea570d9..e9e9255877e 100644 --- a/src/doc/en/reference/discrete_geometry/index.rst +++ b/src/doc/en/reference/discrete_geometry/index.rst @@ -112,6 +112,7 @@ Backends for Polyhedra sage/geometry/polyhedron/backend_cdd sage/geometry/polyhedron/backend_cdd_rdf sage/geometry/polyhedron/backend_field + sage/geometry/polyhedron/backend_number_field sage/geometry/polyhedron/backend_normaliz sage/geometry/polyhedron/backend_polymake sage/geometry/polyhedron/backend_ppl diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index cce33d64029..a3c8aa161ed 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -133,5 +133,4 @@ 'ACEQuantumOnsagerAlgebra', 'AlternatingCentralExtensionQuantumOnsager') lazy_import('sage.algebras.yangian', 'Yangian') -del lazy_import # We remove the object from here so it doesn't appear under tab completion - +del lazy_import # We remove the object from here so it doesn't appear under tab completion diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 8fc5d750dd6..be0db957cf6 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -666,7 +666,7 @@ def _basis_index_function(self, x): # if the input is a tuple, assume that it has # entries in {0, ..., 2**Q.dim()-1} if isinstance(x, tuple): - return FrozenBitset(x, capacity = Q.dim()) + return FrozenBitset(x, capacity=Q.dim()) # slice the output of format in order to make conventions # of format and FrozenBitset agree. @@ -2994,4 +2994,3 @@ def groebner_basis(self, term_order=None, reduced=True): self._groebner_strategy.compute_groebner(reduced=reduced) self._reduced = reduced return self._groebner_strategy.groebner_basis - diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index 98e338d3468..3d01aaf03a1 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -9,7 +9,7 @@ AUTHORS: - Trevor K. Karn, Travis Scrimshaw (July 2022): Initial implementation """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2022 Trevor K. Karn # (C) 2022 Travis Scrimshaw # @@ -17,8 +17,8 @@ AUTHORS: # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_check from sage.libs.gmp.mpz cimport mpz_sizeinbase, mpz_setbit, mpz_tstbit, mpz_cmp_si, mpz_sgn @@ -137,7 +137,7 @@ cdef class GroebnerStrategy: return self.int_to_bitset(max(self.bitset_to_int(k) for k in mc)) cdef inline partial_S_poly_left(self, GBElement f, GBElement g): - """ + r""" Compute one half of the `S`-polynomial for ``f`` and ``g``. This computes: @@ -154,7 +154,7 @@ cdef class GroebnerStrategy: return ret cdef inline partial_S_poly_right(self, GBElement f, GBElement g): - """ + r""" Compute one half of the `S`-polynomial for ``f`` and ``g``. This computes: diff --git a/src/sage/algebras/finite_gca.py b/src/sage/algebras/finite_gca.py index 0a40e539438..5f21cdc8290 100644 --- a/src/sage/algebras/finite_gca.py +++ b/src/sage/algebras/finite_gca.py @@ -6,17 +6,16 @@ - Michael Jung (2021): initial version """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2021 Michael Jung # # 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/ +# **************************************************************************** +from __future__ import annotations from sage.combinat.free_module import CombinatorialFreeModule from sage.categories.algebras import Algebras from sage.misc.cachefunc import cached_method @@ -27,6 +26,7 @@ from sage.sets.condition_set import ConditionSet from sage.rings.integer_ring import ZZ + class FiniteGCAlgebra(CombinatorialFreeModule, Algebra): r""" Finite dimensional graded commutative algebras. @@ -484,16 +484,15 @@ def one_basis(self): n = len(self._degrees) return self._weighted_vectors([0 for _ in range(n)]) - def gens(self): + def gens(self) -> tuple: r""" - Return the generators of ``self`` as a list. + Return the generators of ``self`` as a tuple. EXAMPLES:: sage: A. = GradedCommutativeAlgebra(QQ, degrees=(4,8,2), max_degree=10) sage: A.gens() - [x, y, z] - + (x, y, z) """ n = len(self._degrees) zero = [0 for _ in range(n)] @@ -502,7 +501,7 @@ def gens(self): ind = list(zero) ind[k] = 1 indices.append(self._weighted_vectors(ind)) - return [self.monomial(ind) for ind in indices] + return tuple([self.monomial(ind) for ind in indices]) @cached_method def gen(self, i): diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 29ed81ff47d..f3cdb5a6af8 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -1757,11 +1757,11 @@ def _test_ring_constructions(self, **options): raise RuntimeError('fatal: base ring embedding %s does not work' % bri) test_eleBgenEmb = self._tester(**options) - test_eleBgenEmb.assertTrue(eleBgenEmb == eleB) + test_eleBgenEmb.assertEqual(eleBgenEmb, eleB) test_eleEgenEmb = self._tester(**options) - test_eleEgenEmb.assertTrue(eleEgenEmb == eleE) + test_eleEgenEmb.assertEqual(eleEgenEmb, eleE) test_eleBembE = self._tester(**options) - test_eleBembE.assertTrue(eleBembE == eleB) + test_eleBembE.assertEqual(eleBembE, eleB) # -------------------------------------------------------------------------- # _test_matrix_constructions @@ -1806,7 +1806,7 @@ def check_matrix(representation_type): m12mult = m1*m2 m12mat = b12.matrix(representation_type=representation_type) test_matrix = self._tester(**options) - test_matrix.assertTrue(m12mult == m12mat) + test_matrix.assertEqual(m12mult, m12mat) from sage.combinat.root_system.reflection_group_real import is_chevie_available @@ -3535,4 +3535,3 @@ def char_function(ele): return char_function irrs = [irr for irr in self.irred_repr if irr.number_gens() == self._nstrands - 1] return [self.characters(irrs[i], original=original) for i in range(len(irrs))] - diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py index d30633cad55..1a21f5dcb9f 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -1477,7 +1477,7 @@ def specialize_links_gould(self): L = LaurentPolynomialRing(ZZ, 't0, t1') t0, t1 = L.gens() lu = t0 + t1 - 1 - lv = t0*t1 - t0 - t1 + lv = t0 * t1 - t0 - t1 lw = -t0 * t1 LL = L.localization((lu, lv)) u = LL(lu) @@ -1486,4 +1486,3 @@ def specialize_links_gould(self): phi = self.hom((u, v, w, LL.one())) inc = L.convert_map_from(LL) return inc * phi - diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py index 01c72e26098..b2d68fb2f6f 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py @@ -1079,4 +1079,3 @@ def some_elements(self): True """ return tuple([self(x) for x in self._cubic_hecke_algebra.some_elements()]) - diff --git a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py index 5ee696bee17..23af0d3f7dd 100644 --- a/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/n2_lie_conformal_algebra.py @@ -19,18 +19,19 @@ - Reimundo Heluani (2020-06-03): Initial implementation. """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2020 Reimundo Heluani # # 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/ +# **************************************************************************** from .graded_lie_conformal_algebra import GradedLieConformalAlgebra + class N2LieConformalAlgebra(GradedLieConformalAlgebra): """ The N=2 super Lie conformal algebra. @@ -70,7 +71,7 @@ class N2LieConformalAlgebra(GradedLieConformalAlgebra): sage: G.bracket(G) {0: 2*L, 2: 2/3*C} """ - def __init__(self,R): + def __init__(self, R): """ Initialize self. @@ -79,24 +80,25 @@ def __init__(self,R): sage: V = lie_conformal_algebras.N2(QQ) sage: TestSuite(V).run() """ - n2dict =\ - {('L','L'):{0:{('L',1):1}, 1:{('L',0): 2}, - 3:{('C', 0):R(2).inverse_of_unit()}}, - ('L','G1'):{0:{('G1',1):1}, 1:{('G1',0):3*R(2).\ - inverse_of_unit()}}, - ('L','G2'):{0:{('G2',1):1}, 1:{('G2',0):3*R(2).\ - inverse_of_unit()}}, - ('G1','G2'): {0:{('L',0):1,('J',1):R(2).inverse_of_unit()}, - 1:{('J',0):1}, 2:{('C',0):R(3).inverse_of_unit()}}, - ('L','J'): {0:{('J',1):1},1:{('J',0):1}}, - ('J','J'): {1:{('C',0):R(3).inverse_of_unit()}}, - ('J','G1'): {0:{('G1',0):1}}, - ('J','G2'): {0:{('G2',0):-1}}} + n2dict = {('L', 'L'): {0: {('L', 1): 1}, + 1: {('L', 0): 2}, + 3: {('C', 0): R(2).inverse_of_unit()}}, + ('L', 'G1'): {0: {('G1', 1): 1}, + 1: {('G1', 0): 3 * R(2).inverse_of_unit()}}, + ('L', 'G2'): {0: {('G2', 1): 1}, + 1: {('G2', 0): 3 * R(2).inverse_of_unit()}}, + ('G1', 'G2'): {0: {('L', 0): 1, ('J', 1): R(2).inverse_of_unit()}, + 1: {('J', 0): 1}, + 2: {('C', 0): R(3).inverse_of_unit()}}, + ('L', 'J'): {0: {('J', 1): 1}, 1: {('J', 0): 1}}, + ('J', 'J'): {1: {('C', 0): R(3).inverse_of_unit()}}, + ('J', 'G1'): {0: {('G1', 0): 1}}, + ('J', 'G2'): {0: {('G2', 0): -1}}} from sage.rings.rational_field import QQ - weights = (2,1,QQ(3/2),QQ(3/2)) - parity = (0,0,1,1) - GradedLieConformalAlgebra.__init__(self,R,n2dict, - names=('L', 'J','G1','G2'), + weights = (2, 1, QQ(3) / 2, QQ(3) / 2) + parity = (0, 0, 1, 1) + GradedLieConformalAlgebra.__init__(self, R, n2dict, + names=('L', 'J', 'G1', 'G2'), central_elements=('C',), weights=weights, parity=parity) @@ -108,7 +110,5 @@ def _repr_(self): sage: R = lie_conformal_algebras.N2(QQbar); R The N=2 super Lie conformal algebra over Algebraic Field - """ - return "The N=2 super Lie conformal algebra over {}".\ - format(self.base_ring()) + return f"The N=2 super Lie conformal algebra over {self.base_ring()}" diff --git a/src/sage/algebras/q_commuting_polynomials.py b/src/sage/algebras/q_commuting_polynomials.py index b772f04a57e..d1aae987d61 100644 --- a/src/sage/algebras/q_commuting_polynomials.py +++ b/src/sage/algebras/q_commuting_polynomials.py @@ -346,6 +346,5 @@ def product_on_basis(self, x, y): Ly = y.list() # This could be made more efficient - qpow = sum(exp * sum(self._B[j,i] * val for j, val in enumerate(Ly[:i])) for i,exp in enumerate(Lx)) + qpow = sum(exp * sum(self._B[j, i] * val for j, val in enumerate(Ly[:i])) for i, exp in enumerate(Lx)) return self.term(x * y, self._q ** qpow) - diff --git a/src/sage/algebras/quantum_clifford.py b/src/sage/algebras/quantum_clifford.py index f646b0c2a52..1e57682f255 100644 --- a/src/sage/algebras/quantum_clifford.py +++ b/src/sage/algebras/quantum_clifford.py @@ -948,8 +948,7 @@ def inverse(self): if any(p[i] != 0 for i in range(Cl._n)): return super().__invert__() tk = 2 * Cl._k - w = tuple([tk-val if val else 0 for val in w]) - return Cl.element_class(Cl, {(p, w) : coeff.inverse_of_unit()}) + w = tuple([tk - val if val else 0 for val in w]) + return Cl.element_class(Cl, {(p, w): coeff.inverse_of_unit()}) __invert__ = inverse - diff --git a/src/sage/algebras/yangian.py b/src/sage/algebras/yangian.py index b63648bbb95..55bb61fccf5 100644 --- a/src/sage/algebras/yangian.py +++ b/src/sage/algebras/yangian.py @@ -19,10 +19,9 @@ from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod -from sage.structure.unique_representation import UniqueRepresentation from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis -from sage.rings.integer_ring import ZZ +from sage.categories.cartesian_product import cartesian_product from sage.rings.infinity import infinity from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.sets.family import Family @@ -31,157 +30,6 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.algebras.associated_graded import AssociatedGradedAlgebra -import itertools - - -class GeneratorIndexingSet(UniqueRepresentation): - """ - Helper class for the indexing set of the generators. - """ - def __init__(self, index_set, level=None): - """ - Initialize ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - """ - self._index_set = index_set - self._level = level - - def __repr__(self): - """ - Return a string representation of ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: GeneratorIndexingSet((1,2)) - Cartesian product of Positive integers, (1, 2), (1, 2) - sage: GeneratorIndexingSet((1,2), 4) - Cartesian product of (1, 2, 3, 4), (1, 2), (1, 2) - """ - if self._level is None: - L = PositiveIntegers() - else: - L = tuple(range(1, self._level + 1)) - return "Cartesian product of {L}, {I}, {I}".format(L=L, I=self._index_set) - - def an_element(self): - """ - Initialize ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - sage: I.an_element() - (3, 1, 1) - sage: I = GeneratorIndexingSet((1,2), 5) - sage: I.an_element() - (3, 1, 1) - sage: I = GeneratorIndexingSet((1,2), 1) - sage: I.an_element() - (1, 1, 1) - """ - if self._level is not None and self._level < 3: - return (1, self._index_set[0], self._index_set[0]) - return (3, self._index_set[0], self._index_set[0]) - - def cardinality(self): - """ - Return the cardinality of ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - sage: I.cardinality() - +Infinity - sage: I = GeneratorIndexingSet((1,2), level=3) - sage: I.cardinality() == 3 * 2 * 2 - True - """ - if self._level is not None: - return self._level * len(self._index_set)**2 - return infinity - - __len__ = cardinality - - def __call__(self, x): - """ - Call ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - sage: I([1, 2]) - (1, 2) - """ - return tuple(x) - - def __contains__(self, x): - """ - Check containment of ``x`` in ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - sage: (4, 1, 2) in I - True - sage: [4, 2, 1] in I - True - sage: (-1, 1, 1) in I - False - sage: (1, 3, 1) in I - False - - :: - - sage: I3 = GeneratorIndexingSet((1,2), 3) - sage: (1, 1, 2) in I3 - True - sage: (3, 1, 1) in I3 - True - sage: (4, 1, 1) in I3 - False - """ - return (isinstance(x, (tuple, list)) and len(x) == 3 - and x[0] in ZZ and x[0] > 0 - and (self._level is None or x[0] <= self._level) - and x[1] in self._index_set - and x[2] in self._index_set) - - def __iter__(self): - """ - Iterate over ``self``. - - TESTS:: - - sage: from sage.algebras.yangian import GeneratorIndexingSet - sage: I = GeneratorIndexingSet((1,2)) - sage: it = iter(I) - sage: [next(it) for dummy in range(5)] - [(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), (2, 1, 1)] - - sage: I = GeneratorIndexingSet((1,2), 3) - sage: list(I) - [(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), - (2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2), - (3, 1, 1), (3, 1, 2), (3, 2, 1), (3, 2, 2)] - """ - I = self._index_set - if self._level is not None: - for x in itertools.product(range(1, self._level + 1), I, I): - yield x - return - for i in PositiveIntegers(): - for x in itertools.product(I, I): - yield (i, x[0], x[1]) - class Yangian(CombinatorialFreeModule): r""" @@ -392,7 +240,7 @@ def __init__(self, base_ring, n, variable_name, filtration): category = category.Connected() self._index_set = tuple(range(1, n + 1)) # The keys for the basis are tuples (l, i, j) - indices = GeneratorIndexingSet(self._index_set) + indices = cartesian_product([PositiveIntegers(), self._index_set, self._index_set]) # We note that the generators are non-commutative, but we always sort # them, so they are, in effect, indexed by the free abelian monoid basis_keys = IndexedFreeAbelianMonoid(indices, bracket=False, @@ -501,7 +349,7 @@ def _element_constructor_(self, x): True sage: Y6 = Yangian(QQ, 4, level=6, filtration='natural') sage: Y(Y6.an_element()) - t(1)[1,1]*t(1)[1,2]^2*t(1)[1,3]^3*t(3)[1,1] + t(1)[1,1]^2*t(1)[1,2]^2*t(1)[1,3]^3 + 2*t(1)[1,1] + 3*t(1)[1,2] + 1 """ if isinstance(x, CombinatorialFreeModule.Element): if isinstance(x.parent(), Yangian) and x.parent()._n <= self._n: @@ -543,8 +391,8 @@ def algebra_generators(self): sage: Y = Yangian(QQ, 4) sage: Y.algebra_generators() - Lazy family (generator(i))_{i in Cartesian product of - Positive integers, (1, 2, 3, 4), (1, 2, 3, 4)} + Lazy family (generator(i))_{i in The Cartesian product of + (Positive integers, {1, 2, 3, 4}, {1, 2, 3, 4})} """ return Family(self._indices._indices, self.gen, name="generator") @@ -816,7 +664,8 @@ def __init__(self, base_ring, n, level, variable_name, filtration): category = HopfAlgebrasWithBasis(base_ring).Filtered() self._index_set = tuple(range(1,n+1)) # The keys for the basis are tuples (l, i, j) - indices = GeneratorIndexingSet(self._index_set, level) + L = range(1, self._level + 1) + indices = cartesian_product([L, self._index_set, self._index_set]) # We note that the generators are non-commutative, but we always sort # them, so they are, in effect, indexed by the free abelian monoid basis_keys = IndexedFreeAbelianMonoid(indices, bracket=False, prefix=variable_name) @@ -1152,7 +1001,10 @@ def __init__(self, Y): EXAMPLES:: sage: grY = Yangian(QQ, 4).graded_algebra() - sage: TestSuite(grY).run() # long time + sage: g = grY.indices().gens() + sage: x = grY(g[1,1,1] * g[1,1,2]^2 * g[1,1,3]^3 * g[3,1,1]) + sage: elts = [grY(g[1,1,1]), grY(g[2,1,1]), x] + sage: TestSuite(grY).run(elements=elts) # long time """ if Y._filtration != 'loop': raise ValueError("the Yangian must have the loop filtration") @@ -1170,6 +1022,17 @@ def antipode_on_basis(self, m): -tbar(2)[1,1] sage: x = grY.an_element(); x + tbar(1)[1,1]*tbar(1)[1,2]^2*tbar(1)[1,3]^3*tbar(42)[1,1] + sage: grY.antipode_on_basis(x.leading_support()) + -tbar(1)[1,1]*tbar(1)[1,2]^2*tbar(1)[1,3]^3*tbar(42)[1,1] + - 2*tbar(1)[1,1]*tbar(1)[1,2]*tbar(1)[1,3]^3*tbar(42)[1,2] + - 3*tbar(1)[1,1]*tbar(1)[1,2]^2*tbar(1)[1,3]^2*tbar(42)[1,3] + + 5*tbar(1)[1,2]^2*tbar(1)[1,3]^3*tbar(42)[1,1] + + 10*tbar(1)[1,2]*tbar(1)[1,3]^3*tbar(42)[1,2] + + 15*tbar(1)[1,2]^2*tbar(1)[1,3]^2*tbar(42)[1,3] + + sage: g = grY.indices().gens() + sage: x = grY(g[1,1,1] * g[1,1,2]^2 * g[1,1,3]^3 * g[3,1,1]); x tbar(1)[1,1]*tbar(1)[1,2]^2*tbar(1)[1,3]^3*tbar(3)[1,1] sage: grY.antipode_on_basis(x.leading_support()) -tbar(1)[1,1]*tbar(1)[1,2]^2*tbar(1)[1,3]^3*tbar(3)[1,1] diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index e57076646f4..1bd4d4c6a1f 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -1,6 +1,10 @@ # -*- coding: utf-8 -*- r""" Miscellaneous arithmetic functions + +AUTHORS: + +- Kevin Stueve (2010-01-17): in ``is_prime(n)``, delegated calculation to ``n.is_prime()`` """ # **************************************************************************** @@ -471,25 +475,29 @@ def factorial(n, algorithm='gmp'): def is_prime(n): r""" - Return ``True`` if `n` is a prime number, and ``False`` otherwise. - - Use a provable primality test or a strong pseudo-primality test depending - on the global :mod:`arithmetic proof flag `. + Determine whether `n` is a prime element of its parent ring. INPUT: - - ``n`` - the object for which to determine primality + - ``n`` -- the object for which to determine primality + + Exceptional special cases: + + - For integers, determine whether `n` is a *positive* prime. + - For number fields except `\QQ`, determine whether `n` + is a prime element *of the maximal order*. + + ALGORITHM: + + For integers, this function uses a provable primality test + or a strong pseudo-primality test depending on the global + :mod:`arithmetic proof flag `. .. SEEALSO:: - :meth:`is_pseudoprime` - :meth:`sage.rings.integer.Integer.is_prime` - AUTHORS: - - - Kevin Stueve kstueve@uw.edu (2010-01-17): - delegated calculation to ``n.is_prime()`` - EXAMPLES:: sage: is_prime(389) @@ -505,18 +513,59 @@ def is_prime(n): sage: is_prime(-2) False + :: + sage: a = 2**2048 + 981 sage: is_prime(a) # not tested - takes ~ 1min sage: proof.arithmetic(False) sage: is_prime(a) # instantaneous! True sage: proof.arithmetic(True) + + TESTS: + + Make sure the warning from :trac:`25046` works as intended:: + + sage: is_prime(7/1) + doctest:warning + ... + UserWarning: Testing primality in Rational Field, which is a field, + hence the result will always be False. To test whether n is a prime + integer, use is_prime(ZZ(n)) or ZZ(n).is_prime(). Using n.is_prime() + instead will silence this warning. + False + sage: ZZ(7/1).is_prime() + True + sage: QQ(7/1).is_prime() + False + + However, number fields redefine ``.is_prime()`` in an incompatible fashion + (cf. :trac:`32340`) and we should not warn:: + + sage: K. = NumberField(x^2+1) + sage: is_prime(1+i) + True """ try: - return n.is_prime() + ret = n.is_prime() except (AttributeError, NotImplementedError): return ZZ(n).is_prime() + R = n.parent() + if R.is_field(): + # number fields redefine .is_prime(), see #32340 + from sage.rings.number_field.number_field import NumberField_generic + if not isinstance(R, NumberField_generic): + import warnings + s = f'Testing primality in {R}, which is a field, ' \ + 'hence the result will always be False. ' + if R is QQ: + s += 'To test whether n is a prime integer, use ' \ + 'is_prime(ZZ(n)) or ZZ(n).is_prime(). ' + s += 'Using n.is_prime() instead will silence this warning.' + warnings.warn(s) + + return ret def is_pseudoprime(n): r""" @@ -3224,10 +3273,10 @@ def crt(a, b, m=None, n=None): CRT = crt -def CRT_list(v, moduli): - r""" Given a list ``v`` of elements and a list of corresponding +def CRT_list(values, moduli): + r""" Given a list ``values`` of elements and a list of corresponding ``moduli``, find a single element that reduces to each element of - ``v`` modulo the corresponding moduli. + ``values`` modulo the corresponding moduli. .. SEEALSO:: @@ -3289,22 +3338,37 @@ def CRT_list(v, moduli): sage: from gmpy2 import mpz sage: CRT_list([mpz(2),mpz(3),mpz(2)], [mpz(3),mpz(5),mpz(7)]) 23 + + Make sure we are not mutating the input lists:: + + sage: xs = [1,2,3] + sage: ms = [5,7,9] + sage: CRT_list(xs, ms) + 156 + sage: xs + [1, 2, 3] + sage: ms + [5, 7, 9] """ - if not isinstance(v, list) or not isinstance(moduli, list): + if not isinstance(values, list) or not isinstance(moduli, list): raise ValueError("arguments to CRT_list should be lists") - if len(v) != len(moduli): + if len(values) != len(moduli): raise ValueError("arguments to CRT_list should be lists of the same length") - if not v: + if not values: return ZZ.zero() - if len(v) == 1: - return moduli[0].parent()(v[0]) - x = v[0] - m = moduli[0] + if len(values) == 1: + return moduli[0].parent()(values[0]) + + # The result is computed using a binary tree. In typical cases, + # this scales much better than folding the list from one side. from sage.arith.functions import lcm - for i in range(1, len(v)): - x = CRT(x, v[i], m, moduli[i]) - m = lcm(m, moduli[i]) - return x % m + while len(values) > 1: + vs, ms = values[::2], moduli[::2] + for i, (v, m) in enumerate(zip(values[1::2], moduli[1::2])): + vs[i] = CRT(vs[i], v, ms[i], m) + ms[i] = lcm(ms[i], m) + values, moduli = vs, ms + return values[0] % moduli[0] def CRT_basis(moduli): diff --git a/src/sage/arith/power.pyx b/src/sage/arith/power.pyx index 3c9219a5f11..2900d9f2a45 100644 --- a/src/sage/arith/power.pyx +++ b/src/sage/arith/power.pyx @@ -24,7 +24,7 @@ cpdef generic_power(a, n): """ Return `a^n`. - If `n` is negative, return `(1/a)^(-n)`. + If `n` is negative, return `(1/a)^{-n}`. INPUT: diff --git a/src/sage/categories/additive_magmas.py b/src/sage/categories/additive_magmas.py index e81dcf9d4b9..cf2fdf242b9 100644 --- a/src/sage/categories/additive_magmas.py +++ b/src/sage/categories/additive_magmas.py @@ -519,7 +519,7 @@ def algebra_generators(self): An example of a commutative semigroup: the free commutative semigroup generated by ('a', 'b', 'c', 'd') sage: A = S.algebra(QQ) sage: A.algebra_generators() - Finite family {0: B[a], 1: B[b], 2: B[c], 3: B[d]} + Family (B[a], B[b], B[c], B[d]) .. TODO:: diff --git a/src/sage/categories/additive_semigroups.py b/src/sage/categories/additive_semigroups.py index fde92f27896..0527867154b 100644 --- a/src/sage/categories/additive_semigroups.py +++ b/src/sage/categories/additive_semigroups.py @@ -153,7 +153,7 @@ def algebra_generators(self): An example of a commutative semigroup: the free commutative semigroup generated by ('a', 'b', 'c', 'd') sage: A = S.algebra(QQ) sage: A.algebra_generators() - Finite family {0: B[a], 1: B[b], 2: B[c], 3: B[d]} + Family (B[a], B[b], B[c], B[d]) """ return self.basis().keys().additive_semigroup_generators().map(self.monomial) diff --git a/src/sage/categories/commutative_algebras.py b/src/sage/categories/commutative_algebras.py index 0f24e90c524..cff24e1298a 100644 --- a/src/sage/categories/commutative_algebras.py +++ b/src/sage/categories/commutative_algebras.py @@ -89,4 +89,3 @@ def extra_super_categories(self): True """ return [CommutativeRings()] - diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 8cf87ffe94f..2d5d7730693 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -144,4 +144,3 @@ def _test_fraction_field(self, **options): class ElementMethods: pass - diff --git a/src/sage/categories/monoids.py b/src/sage/categories/monoids.py index 93638b04078..dc548a72e66 100644 --- a/src/sage/categories/monoids.py +++ b/src/sage/categories/monoids.py @@ -556,18 +556,17 @@ def algebra_generators(self): sage: Z12.semigroup_generators() Family (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) sage: Z12.algebra(QQ).algebra_generators() - Finite family {0: B[0], 1: B[1], 2: B[2], 3: B[3], 4: B[4], 5: B[5], - 6: B[6], 7: B[7], 8: B[8], 9: B[9], 10: B[10], 11: B[11]} + Family (B[0], B[1], B[2], B[3], B[4], B[5], B[6], B[7], B[8], B[9], B[10], B[11]) sage: GroupAlgebras(QQ).example(AlternatingGroup(10)).algebra_generators() - Finite family {0: (8,9,10), 1: (1,2,3,4,5,6,7,8,9)} + Family ((8,9,10), (1,2,3,4,5,6,7,8,9)) sage: A = DihedralGroup(3).algebra(QQ); A Algebra of Dihedral group of order 6 as a permutation group over Rational Field sage: A.algebra_generators() - Finite family {0: (1,2,3), 1: (1,3)} + Family ((1,2,3), (1,3)) """ monoid = self.basis().keys() try: diff --git a/src/sage/categories/semigroups.py b/src/sage/categories/semigroups.py index 007401e5474..d053b20e3c0 100644 --- a/src/sage/categories/semigroups.py +++ b/src/sage/categories/semigroups.py @@ -882,7 +882,7 @@ def algebra_generators(self): sage: M.semigroup_generators() Family ('a', 'b', 'c', 'd') sage: M.algebra(ZZ).algebra_generators() - Finite family {0: B['a'], 1: B['b'], 2: B['c'], 3: B['d']} + Family (B['a'], B['b'], B['c'], B['d']) """ return self.basis().keys().semigroup_generators().map(self.monomial) diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index d096a950773..13ea3b0338f 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -1616,7 +1616,7 @@ def algebra(self, base_ring, category=None, **kwds): of `S`, or ``None`` This returns the space of formal linear combinations of - elements of `G` with coefficients in `R`, endowed with + elements of `S` with coefficients in `K`, endowed with whatever structure can be induced from that of `S`. See the documentation of :mod:`sage.categories.algebra_functor` for details. diff --git a/src/sage/combinat/crystals/littelmann_path.py b/src/sage/combinat/crystals/littelmann_path.py index 2ddd6f3c461..e747ab5ecca 100644 --- a/src/sage/combinat/crystals/littelmann_path.py +++ b/src/sage/combinat/crystals/littelmann_path.py @@ -9,7 +9,7 @@ - Travis Scrimshaw (2016): Implemented :class:`~sage.combinat.crystals.littelmann_path.InfinityCrystalOfLSPaths` """ -#**************************************************************************** +# *************************************************************************** # Copyright (C) 2012 Mark Shimozono # Anne Schilling # @@ -22,8 +22,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#**************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from sage.misc.cachefunc import cached_in_parent_method, cached_method from sage.structure.unique_representation import UniqueRepresentation @@ -147,10 +147,7 @@ def __classcall_private__(cls, starting_weight, cartan_type = None, starting_wei """ if cartan_type is not None: cartan_type, starting_weight = CartanType(starting_weight), cartan_type - if cartan_type.is_affine(): - extended = True - else: - extended = False + extended = cartan_type.is_affine() R = RootSystem(cartan_type) P = R.weight_space(extended = extended) @@ -333,7 +330,7 @@ def split_step(self, which_step, r): sage: b.split_step(0,1/3) (1/3*Lambda[1] + 1/3*Lambda[2], 2/3*Lambda[1] + 2/3*Lambda[2]) """ - assert 0 <= which_step and which_step <= len(self.value) + assert 0 <= which_step <= len(self.value) v = self.value[which_step] return self.parent()(self.value[:which_step] + (r*v,(1-r)*v) + self.value[which_step+1:]) @@ -476,7 +473,7 @@ def e(self, i, power=1, to_string_end=False, length_only=False): ix = len(data)-1 while ix >= 0 and data[ix][1] < M + p: - # get the index of the current step to be processed + # get the index of the current step to be processed j = data[ix][0] # find the i-height where the current step might need to be split if ix == 0: @@ -621,7 +618,7 @@ def _latex_(self): ##################################################################### -## Projected level-zero +# Projected level-zero class CrystalOfProjectedLevelZeroLSPaths(CrystalOfLSPaths): @@ -1144,7 +1141,9 @@ def energy_function(self): Wd = WeylGroup(cartan_dual, prefix='s', implementation="permutation") G = Wd.quantum_bruhat_graph(J) Qd = RootSystem(cartan_dual).root_lattice() - dualize = lambda x: Qv.from_vector(x.to_vector()) + + def dualize(x): + return Qv.from_vector(x.to_vector()) L = [Wd.from_reduced_word(x.reduced_word()) for x in L] def stretch_short_root(a): @@ -1177,7 +1176,7 @@ def stretch_short_root(a): ##################################################################### -## B(\infty) +# B(\infty) class InfinityCrystalOfLSPaths(UniqueRepresentation, Parent): @@ -1464,7 +1463,7 @@ def phi(self,i): ##################################################################### -## Helper functions +# Helper functions def positively_parallel_weights(v, w): diff --git a/src/sage/combinat/integer_vector.py b/src/sage/combinat/integer_vector.py index e0cd57a3eec..352ec520d4d 100644 --- a/src/sage/combinat/integer_vector.py +++ b/src/sage/combinat/integer_vector.py @@ -479,6 +479,36 @@ def check(self): raise ValueError(f"{self} doesn't satisfy correct constraints") + def trim(self): + """ + Remove trailing zeros from the integer vector. + + EXAMPLES:: + + sage: IV = IntegerVectors() + sage: IV([5,3,5,1,0,0]).trim() + [5, 3, 5, 1] + sage: IV([5,0,5,1,0]).trim() + [5, 0, 5, 1] + sage: IV([4,3,3]).trim() + [4, 3, 3] + sage: IV([0,0,0]).trim() + [] + + sage: IV = IntegerVectors(k=4) + sage: v = IV([4,3,2,0]).trim(); v + [4, 3, 2] + sage: v.parent() + Integer vectors + """ + P = IntegerVectors() + v = list(self) + if all(i == 0 for i in v): + return P.element_class(P, [], check=False) + while not v[-1]: + v = v[:-1] + return P.element_class(P, v, check=False) + class IntegerVectors(Parent, metaclass=ClasscallMetaclass): """ The class of (non-negative) integer vectors. diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index 953b5c4e680..9b5ee82aa81 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -193,8 +193,8 @@ cdef class dancing_linksWrapper: r""" Reinitialization of the search algorithm - This recreates an empty `dancing_links` object and adds the rows to - the instance of dancing_links. + This recreates an empty ``dancing_links`` object and adds the rows to + the instance of ``dancing_links.`` EXAMPLES:: @@ -805,7 +805,7 @@ cdef class dancing_linksWrapper: INPUT: - ``ncpus`` -- integer (default: ``None``), maximal number of - subprocesses to use at the same time. If `ncpus>1` the dancing + subprocesses to use at the same time. If ``ncpus>1`` the dancing links problem is split into independent subproblems to allow parallel computation. If ``None``, it detects the number of effective CPUs in the system using @@ -968,8 +968,8 @@ cdef class dancing_linksWrapper: .. NOTE:: - When comparing the time taken by method `one_solution`, - have in mind that `one_solution_using_sat_solver` first + When comparing the time taken by method ``one_solution``, + have in mind that ``one_solution_using_sat_solver`` first creates the SAT solver instance from the dancing links solver. This copy of data may take many seconds depending on the size of the problem. @@ -1096,8 +1096,8 @@ cdef class dancing_linksWrapper: .. NOTE:: - When comparing the time taken by method `one_solution`, have in - mind that `one_solution_using_milp_solver` first creates (and + When comparing the time taken by method ``one_solution``, have in + mind that ``one_solution_using_milp_solver`` first creates (and caches) the MILP solver instance from the dancing links solver. This copy of data may take many seconds depending on the size of the problem. diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index 515b762278c..d857092f9c7 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -3489,15 +3489,15 @@ def _glue_spectra(a_spec, b_spec, orientation): p = len(a_spec) q = len(b_spec) - for r in range(1, p+q+1): + for r in range(1, p + q + 1): new_a_spec.append(0) - for i in range(max(1, r-q), min(p, r) + 1): - k_val = binomial(r-1, i-1) * binomial(p+q-r, p-i) + for i in range(max(1, r - q), min(p, r) + 1): + k_val = binomial(r - 1, i - 1) * binomial(p + q - r, p - i) if orientation: - inner_sum = sum(b_spec[j-1] for j in range(r-i + 1, len(b_spec) + 1)) + inner_sum = sum(b_spec[j - 1] for j in range(r - i + 1, len(b_spec) + 1)) else: - inner_sum = sum(b_spec[j-1] for j in range(1, r-i + 1)) - new_a_spec[-1] = new_a_spec[-1] + (a_spec[i-1] * k_val * inner_sum) + inner_sum = sum(b_spec[j - 1] for j in range(1, r - i + 1)) + new_a_spec[-1] = new_a_spec[-1] + (a_spec[i - 1] * k_val * inner_sum) return new_a_spec diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index 00f50e68f19..dba3c15c549 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -1307,9 +1307,9 @@ def is_semidistributive(self): """ H = self._hasse_diagram # See trac #21528 for explanation. - return ( (H.in_degree_sequence().count(1) == + return ((H.in_degree_sequence().count(1) == H.out_degree_sequence().count(1)) and - self.is_meet_semidistributive() ) + self.is_meet_semidistributive()) def is_meet_semidistributive(self, certificate=False): r""" @@ -1693,11 +1693,11 @@ def is_cosectionally_complemented(self, certificate=False): H = self._hasse_diagram jn = H.join_matrix() n = H.order() - for e in range(n-2, -1, -1): + for e in range(n - 2, -1, -1): t = 0 for uc in H.neighbors_out(e): t = jn[t, uc] - if t == n-1: + if t == n - 1: break else: if certificate: @@ -1882,8 +1882,8 @@ def is_sectionally_complemented(self, certificate=False): H = self._hasse_diagram mt = H.meet_matrix() - n = H.order()-1 - for e in range(2, n+1): + n = H.order() - 1 + for e in range(2, n + 1): t = n for lc in H.neighbors_in(e): t = mt[t, lc] @@ -3085,9 +3085,9 @@ def vertical_decomposition(self, elements_only=False): if elements_only: return [self[e] for e in self._hasse_diagram.vertical_decomposition(return_list=True)] - elms = ( [0] + - self._hasse_diagram.vertical_decomposition(return_list=True) + - [self.cardinality() - 1] ) + elms = ([0] + + self._hasse_diagram.vertical_decomposition(return_list=True) + + [self.cardinality() - 1]) n = len(elms) result = [] for i in range(n - 1): @@ -4975,6 +4975,7 @@ def _log_2(n): return bits return bits + 1 + ############################################################################ FiniteMeetSemilattice._dual_class = FiniteJoinSemilattice diff --git a/src/sage/combinat/posets/moebius_algebra.py b/src/sage/combinat/posets/moebius_algebra.py index 9ed121e66c2..aada2725078 100644 --- a/src/sage/combinat/posets/moebius_algebra.py +++ b/src/sage/combinat/posets/moebius_algebra.py @@ -102,7 +102,7 @@ def __init__(self, R, L): TESTS:: - sage: L = posets.BooleanLattice(4) + sage: L = posets.BooleanLattice(3) sage: M = L.moebius_algebra(QQ) sage: TestSuite(M).run() """ @@ -632,7 +632,7 @@ def __init__(self, M, prefix='KL'): TESTS:: - sage: L = posets.BooleanLattice(4) + sage: L = posets.BooleanLattice(3) sage: M = L.quantum_moebius_algebra() sage: TestSuite(M.KL()).run() # long time """ diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index e415dc300f2..377fc569fde 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -219,7 +219,7 @@ def BooleanLattice(n, facade=None, use_subsets=False): from sage.sets.set import Set V = [Set(), Set([1])] return LatticePoset((V, [V]), facade=facade) - return LatticePoset(([0,1], [[0,1]]), facade=facade) + return LatticePoset(([0, 1], [[0, 1]]), facade=facade) if use_subsets: from sage.sets.set import Set @@ -288,7 +288,7 @@ def ChainPoset(n, facade=None): raise TypeError("number of elements must be an integer, not {0}".format(n)) if n < 0: raise ValueError("number of elements must be non-negative, not {0}".format(n)) - D = DiGraph([range(n), [[x,x+1] for x in range(n-1)]], + D = DiGraph([range(n), [[x, x + 1] for x in range(n - 1)]], format='vertices_and_edges') return FiniteLatticePoset(hasse_diagram=D, category=FiniteLatticePosets(), @@ -377,7 +377,7 @@ def PentagonPoset(facade=None): sage: posets.DiamondPoset(5).is_distributive() False """ - return LatticePoset([[1,2],[4],[3],[4],[]], facade=facade) + return LatticePoset([[1, 2], [4], [3], [4], []], facade=facade) @staticmethod def DiamondPoset(n, facade=None): @@ -404,10 +404,10 @@ def DiamondPoset(n, facade=None): raise TypeError("number of elements must be an integer, not {0}".format(n)) if n <= 2: raise ValueError("n must be an integer at least 3") - c = [[n-1] for x in range(n)] - c[0] = [x for x in range(1,n-1)] - c[n-1] = [] - D = DiGraph({v:c[v] for v in range(n)}, format='dict_of_lists') + c = [[n - 1] for x in range(n)] + c[0] = [x for x in range(1, n - 1)] + c[n - 1] = [] + D = DiGraph({v: c[v] for v in range(n)}, format='dict_of_lists') return FiniteLatticePoset(hasse_diagram=D, category=FiniteLatticePosets(), facade=facade) @@ -441,8 +441,8 @@ def Crown(n, facade=None): raise TypeError("number of elements must be an integer, not {0}".format(n)) if n < 2: raise ValueError("n must be an integer at least 2") - D = {i: [i+n, i+n+1] for i in range(n-1)} - D[n-1] = [n, n+n-1] + D = {i: [i + n, i + n + 1] for i in range(n - 1)} + D[n - 1] = [n, n + n - 1] return FinitePoset(hasse_diagram=DiGraph(D), category=FinitePosets(), facade=facade) @@ -485,7 +485,7 @@ def DivisorLattice(n, facade=None): if n <= 0: raise ValueError("n must be a positive integer") Div_n = divisors(n) - hasse = DiGraph([Div_n, lambda a, b: b%a==0 and is_prime(b//a)]) + hasse = DiGraph([Div_n, lambda a, b: b % a == 0 and is_prime(b // a)]) return FiniteLatticePoset(hasse, elements=Div_n, facade=facade, category=FiniteLatticePosets()) @@ -509,7 +509,8 @@ def IntegerCompositions(n): """ from sage.combinat.composition import Compositions C = Compositions(n) - return Poset((C, [[c,d] for c in C for d in C if d.is_finer(c)]), cover_relations=False) + return Poset((C, [[c, d] for c in C for d in C if d.is_finer(c)]), + cover_relations=False) @staticmethod def IntegerPartitions(n): @@ -535,19 +536,19 @@ def lower_covers(partition): of elements in the poset of integer partitions. """ lc = [] - for i in range(len(partition)-1): - for j in range(i+1,len(partition)): + for i in range(len(partition) - 1): + for j in range(i + 1, len(partition)): new_partition = partition[:] del new_partition[j] del new_partition[i] - new_partition.append(partition[i]+partition[j]) + new_partition.append(partition[i] + partition[j]) new_partition.sort(reverse=True) tup = tuple(new_partition) if tup not in lc: lc.append(tup) return lc from sage.combinat.partition import Partitions - H = DiGraph(dict([[tuple(p),lower_covers(p)] for p in Partitions(n)])) + H = DiGraph(dict([[tuple(p), lower_covers(p)] for p in Partitions(n)])) return Poset(H.reverse()) @staticmethod @@ -574,20 +575,20 @@ def lower_covers(partition): restricted poset of integer partitions. """ lc = [] - for i in range(len(partition)-1): - for j in range(i+1,len(partition)): + for i in range(len(partition) - 1): + for j in range(i + 1, len(partition)): if partition[i] != partition[j]: new_partition = partition[:] del new_partition[j] del new_partition[i] - new_partition.append(partition[i]+partition[j]) + new_partition.append(partition[i] + partition[j]) new_partition.sort(reverse=True) tup = tuple(new_partition) if tup not in lc: lc.append(tup) return lc from sage.combinat.partition import Partitions - H = DiGraph(dict([[tuple(p),lower_covers(p)] for p in Partitions(n)])) + H = DiGraph(dict([[tuple(p), lower_covers(p)] for p in Partitions(n)])) return Poset(H.reverse()) @staticmethod @@ -677,9 +678,8 @@ def PowerPoset(n): all_pos_n.add(P.relabel(list(r))) return MeetSemilattice((all_pos_n, - lambda A, B: all(B.is_lequal(x, y) for x,y in A.cover_relations_iterator()) - )) - + lambda A, B: all(B.is_lequal(x, y) + for x, y in A.cover_relations_iterator()))) @staticmethod def ProductOfChains(chain_lengths, facade=None): @@ -794,7 +794,7 @@ def RandomPoset(n, p): p = float(p) except Exception: raise TypeError("probability must be a real number, not {0}".format(p)) - if p < 0 or p> 1: + if p < 0 or p > 1: raise ValueError("probability must be between 0 and 1, not {0}".format(p)) D = DiGraph(loops=False, multiedges=False) @@ -904,7 +904,7 @@ def RandomLattice(n, p, properties=None): if n <= 3: return posets.ChainPoset(n) covers = _random_lattice(n, p) - covers_dict = {i:covers[i] for i in range(n)} + covers_dict = {i: covers[i] for i in range(n)} D = DiGraph(covers_dict) D.relabel([i-1 for i in Permutations(n).random_element()]) return LatticePoset(D, cover_relations=True) @@ -1173,9 +1173,11 @@ def SymmetricGroupWeakOrderPoset(n, labels="permutations", side="right"): Finite poset containing 24 elements """ if n < 10 and labels == "permutations": - element_labels = dict([[s,"".join(map(str,s))] for s in Permutations(n)]) + element_labels = dict([[s, "".join(map(str, s))] + for s in Permutations(n)]) if n < 10 and labels == "reduced_words": - element_labels = dict([[s,"".join(map(str,s.reduced_word_lexmin()))] for s in Permutations(n)]) + element_labels = dict([[s, "".join(map(str, s.reduced_word_lexmin()))] + for s in Permutations(n)]) if side == "left": def weak_covers(s): @@ -1193,7 +1195,8 @@ def weak_covers(s): """ return [v for v in s.bruhat_succ() if s.length() + (s.inverse().left_action_product(v)).length() == v.length()] - return Poset(dict([[s, weak_covers(s)] for s in Permutations(n)]),element_labels) + return Poset(dict([[s, weak_covers(s)] for s in Permutations(n)]), + element_labels) @staticmethod def TetrahedralPoset(n, *colors, **labels): @@ -1253,33 +1256,33 @@ def TetrahedralPoset(n, *colors, **labels): if c not in ('green', 'red', 'yellow', 'orange', 'silver', 'blue'): raise ValueError("color input must be from the following: 'green', 'red', 'yellow', 'orange', 'silver', and 'blue'") elem = [(i, j, k) for i in range(n) - for j in range(n-i) for k in range(n-i-j)] + for j in range(n - i) for k in range(n - i - j)] rels = [] elem_labels = {} if 'labels' in labels: if labels['labels'] == 'integers': labelcount = 0 - for (i,j,k) in elem: - elem_labels[(i,j,k)] = labelcount + for (i, j, k) in elem: + elem_labels[(i, j, k)] = labelcount labelcount += 1 for c in colors: - for (i,j,k) in elem: - if i+j+k < n-1: + for (i, j, k) in elem: + if i + j + k < n - 1: if c == 'green': - rels.append([(i,j,k),(i+1,j,k)]) + rels.append([(i, j, k), (i + 1, j, k)]) if c == 'red': - rels.append([(i,j,k),(i,j,k+1)]) + rels.append([(i, j, k), (i, j, k + 1)]) if c == 'yellow': - rels.append([(i,j,k),(i,j+1,k)]) - if j < n-1 and k > 0: + rels.append([(i, j, k), (i, j + 1, k)]) + if j < n - 1 and k > 0: if c == 'orange': - rels.append([(i,j,k),(i,j+1,k-1)]) - if i < n-1 and j > 0: + rels.append([(i, j, k), (i, j + 1, k - 1)]) + if i < n - 1 and j > 0: if c == 'silver': - rels.append([(i,j,k),(i+1,j-1,k)]) - if i < n-1 and k > 0: + rels.append([(i, j, k), (i + 1, j - 1, k)]) + if i < n - 1 and k > 0: if c == 'blue': - rels.append([(i,j,k),(i+1,j,k-1)]) + rels.append([(i, j, k), (i + 1, j, k - 1)]) return Poset([elem, rels], elem_labels) # shard intersection order @@ -1684,9 +1687,9 @@ def PermutationPattern(n): if n <= 0: raise ValueError("number of elements must be nonnegative, not {}".format(n)) elem = [] - for i in range(1, n+1): + for i in range(1, n + 1): elem += Permutations(i) - return Poset((elem, lambda a,b: b.has_pattern(a))) + return Poset((elem, lambda a, b: b.has_pattern(a))) @staticmethod def PermutationPatternInterval(bottom, top): @@ -1737,7 +1740,7 @@ def PermutationPatternInterval(bottom, top): level = 0 # Consider the top element to be level 0, and then go down from there. rel = [] # List of covering relations to be fed into poset constructor. while len(top) - len(bottom) >= level + 1: - elem.append([]) # Add a new empty level + elem.append([]) # Add a new empty level for upper in elem[level]: # Run through all permutations on current level # and find relations for which it is upper cover @@ -1746,17 +1749,17 @@ def PermutationPatternInterval(bottom, top): # Try and remove the ith element from the permutation lower = list(upper) j = lower.pop(i) - for k in range(len(top)-level-1): # Standardize result + for k in range(len(top)-level-1): # Standardize result if lower[k] > j: lower[k] = lower[k] - 1 lower_perm = P(lower) - if lower_perm.has_pattern(bottom): # Check to see if result is in interval + if lower_perm.has_pattern(bottom): # Check to see if result is in interval rel += [[lower_perm, upper_perm]] - if lower not in elem[level+1]: - elem[level+1].append(lower_perm) + if lower not in elem[level + 1]: + elem[level + 1].append(lower_perm) level += 1 elem = [item for sublist in elem for item in sublist] - return Poset((elem,rel)) + return Poset((elem, rel)) @staticmethod def PermutationPatternOccurrenceInterval(bottom, top, pos): @@ -1793,13 +1796,13 @@ def PermutationPatternOccurrenceInterval(bottom, top, pos): P = Permutations() top = P(top) bottom = P(bottom) - if not to_standard([top[z] for z in pos]) == list(bottom): # check input + if not to_standard([top[z] for z in pos]) == list(bottom): # check input raise ValueError("cannot find 'bottom' in 'top' given by 'pos'") elem = [[(top, pos)]] level = 0 rel = [] while len(top) - len(bottom) >= level + 1: - elem.append([]) # Add a new empty level + elem.append([]) # Add a new empty level for upper in elem[level]: for i in range(len(top)-level): # Try and remove the ith element from the permutation @@ -1816,11 +1819,11 @@ def PermutationPatternOccurrenceInterval(bottom, top, pos): lower_pos[f] = upper[1][f] - 1 rel += [[(P(lower_perm), tuple(lower_pos)), (P(upper[0]), upper[1])]] - if (P(lower_perm), tuple(lower_pos)) not in elem[level+1]: - elem[level+1].append((P(lower_perm), tuple(lower_pos))) + if (P(lower_perm), tuple(lower_pos)) not in elem[level + 1]: + elem[level + 1].append((P(lower_perm), tuple(lower_pos))) level += 1 elem = [item for sublist in elem for item in sublist] - return Poset([elem,rel]) + return Poset([elem, rel]) @staticmethod def RibbonPoset(n, descents): @@ -1838,7 +1841,9 @@ def RibbonPoset(n, descents): sage: sorted(R.cover_relations()) [[0, 1], [2, 1], [3, 2], [3, 4]] """ - return Mobile(DiGraph([list(range(n)), [(i+1, i) if i in descents else (i, i+1) for i in range(n-1) ]])) + return Mobile(DiGraph([list(range(n)), + [(i + 1, i) if i in descents else (i, i + 1) + for i in range(n - 1)]])) @staticmethod def MobilePoset(ribbon, hangers, anchor=None): @@ -1889,15 +1894,15 @@ def MobilePoset(ribbon, hangers, anchor=None): for r, hangs in hangers.items(): for i, h in enumerate(hangs): for v in h._elements: - elements.append((r,i,v)) + elements.append((r, i, v)) for cr in h.cover_relations(): cover_relations.append(((r, i, cr[0]), (r, i, cr[1]))) - cover_relations.append(((r,i,h.top()), r)) + cover_relations.append(((r, i, h.top()), r)) return Mobile(DiGraph([elements, cover_relations])) -## RANDOM LATTICES +# RANDOM LATTICES # Following are helper functions for random lattice generation. # There is no parameter checking, 0, 1, ..., n may or may not be a @@ -1939,8 +1944,8 @@ def _random_lattice(n, p): from sage.misc.functional import sqrt from sage.misc.prandom import random - n = n-1 - meets = [[None]*n for _ in range(n)] + n = n - 1 + meets = [[None] * n for _ in range(n)] meets[0][0] = 0 maxs = set([0]) lc_all = [[]] # No lower covers for the bottom element. @@ -2008,11 +2013,11 @@ def _random_dismantlable_lattice(n): """ from sage.misc.prandom import randint - D = DiGraph({0: [n-1]}) - for i in range(1, n-1): - a = randint(0, i//2) + D = DiGraph({0: [n - 1]}) + for i in range(1, n - 1): + a = randint(0, i // 2) b_ = list(D.depth_first_search(a)) - b = b_[randint(1, len(b_)-1)] + b = b_[randint(1, len(b_) - 1)] D.add_vertex(i) D.add_edge(a, i) D.add_edge(i, b) @@ -2053,19 +2058,19 @@ def _random_planar_lattice(n): """ from sage.misc.prandom import randint - G = DiGraph({0: [n-1]}) + G = DiGraph({0: [n - 1]}) while G.order() < n: - i = G.order()-1 - a = randint(0, i//2) + i = G.order() - 1 + a = randint(0, i // 2) b_ = list(G.depth_first_search(a)) - b = b_[randint(1, len(b_)-1)] + b = b_[randint(1, len(b_) - 1)] G1 = G.copy() G.add_vertex(i) G.add_edge(a, i) G.add_edge(i, b) G.delete_edge(a, b) G2 = G.copy() - G2.add_edge(n-1, 0) + G2.add_edge(n - 1, 0) if not G2.is_planar(): G = G1.copy() return G @@ -2102,7 +2107,7 @@ def _random_distributive_lattice(n): from sage.graphs.digraph_generators import digraphs if n < 4: - return digraphs.Path(n-1) + return digraphs.Path(n - 1) H = HasseDiagram({0: []}) while sum(1 for _ in H.antichains_iterator()) < n: @@ -2123,7 +2128,7 @@ def _random_distributive_lattice(n): for b in D.neighbors_out(to_delete): D.add_edge(a, b) D.delete_vertex(to_delete) - D.relabel({z:z-1 for z in range(to_delete + 1, D.order() + 1)}) + D.relabel({z: z - 1 for z in range(to_delete + 1, D.order() + 1)}) H = HasseDiagram(D) return D @@ -2177,4 +2182,5 @@ def _random_stone_lattice(n): return result + posets = Posets diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index 2c236e4a4ae..98f7a13b1df 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -286,6 +286,7 @@ from __future__ import annotations from collections import defaultdict from copy import copy, deepcopy +from typing import List from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -765,7 +766,8 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio # Check for duplicate elements elif len(elements) != len(set(elements)): raise ValueError("the provided list of elements is not a linear " - "extension for the poset as it contains duplicate elements") + "extension for the poset as it contains " + "duplicate elements") else: elements = None return FinitePoset(D, elements=elements, category=category, facade=facade, key=key) @@ -2652,7 +2654,7 @@ def relations_number(self): # Maybe this should also be deprecated. intervals_number = relations_number - def linear_intervals_count(self) -> list[int]: + def linear_intervals_count(self) -> List[int]: """ Return the enumeration of linear intervals w.r.t. their cardinality. @@ -8106,7 +8108,7 @@ def is_eulerian(self, k=None, certificate=False): for rank_diff in range(2, k + 1, 2): for level in range(height - rank_diff): for i in levels[level]: - for j in levels[level+rank_diff]: + for j in levels[level + rank_diff]: if H.is_lequal(i, j) and M[i, j] != 1: if certificate: return (False, (self._vertex_to_element(i), @@ -8160,13 +8162,13 @@ def is_greedy(self, certificate=False): True """ H = self._hasse_diagram - N1 = H.order()-1 + N1 = H.order() - 1 it = H.greedy_linear_extensions_iterator() A = next(it) - A_jumps = sum(1 for i in range(N1) if H.has_edge(A[i], A[i+1])) + A_jumps = sum(1 for i in range(N1) if H.has_edge(A[i], A[i + 1])) for B in it: - B_jumps = sum(1 for i in range(N1) if H.has_edge(B[i], B[i+1])) + B_jumps = sum(1 for i in range(N1) if H.has_edge(B[i], B[i + 1])) if A_jumps != B_jumps: if certificate: if A_jumps > B_jumps: @@ -8452,13 +8454,15 @@ def p_partition_enumerator(self, tup, R, weights=None, check=False): # The simple case: ``weights == None``. F = QR.Fundamental() for lin in self.linear_extensions(facade=True): - descents = [i + 1 for i in range(n-1) if tupdict[lin[i]] > tupdict[lin[i+1]]] + descents = [i + 1 for i in range(n - 1) + if tupdict[lin[i]] > tupdict[lin[i + 1]]] res += F(Composition(from_subset=(descents, n))) return res for lin in self.linear_extensions(facade=True): M = QR.Monomial() lin_weights = Composition([weights.get(lin[i], 1) for i in range(n)]) - descents = [i + 1 for i in range(n-1) if tupdict[lin[i]] > tupdict[lin[i+1]]] + descents = [i + 1 for i in range(n - 1) + if tupdict[lin[i]] > tupdict[lin[i + 1]]] d_c = Composition(from_subset=(descents, n)) for comp in d_c.finer(): res += M[lin_weights.fatten(comp)] diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index fd0068f8793..99e96a9b816 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -1514,4 +1514,3 @@ def read_markov(bas_ele, variables, num_strands=4): 0, 1]} return data[num_strands][bas_ele] - diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index d21f1a250b3..70429a47ac0 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -4545,7 +4545,7 @@ def name(self, style="singular"): _SupportedFindStatCollection(lambda x: (lambda E, V: Graph([list(range(V)), lambda i,j: (i,j) in E or (j,i) in E], immutable=True))(*literal_eval(x)), - lambda X: str((sorted(X.edges(labels=False)), X.num_verts())), + lambda X: str((X.edges(labels=False, sort=True), X.num_verts())), lambda x: (g.copy(immutable=True) for g in graphs(x, copy=False)), lambda x: x.num_verts(), lambda x: isinstance(x, Graph)), @@ -4767,13 +4767,13 @@ def _element_constructor_(self, entry): sage: cc = FindStatCollection(graphs(3)); cc # optional -- internet a subset of Cc0020: Graphs - sage: cc.first_terms(lambda x: x.edges(labels=False)).list() # optional -- internet + sage: cc.first_terms(lambda x: x.edges(labels=False, sort=True)).list() # optional -- internet [(Graph on 3 vertices, []), (Graph on 3 vertices, [(0, 2)]), (Graph on 3 vertices, [(0, 2), (1, 2)]), (Graph on 3 vertices, [(0, 1), (0, 2), (1, 2)])] - sage: len(cc.first_terms(lambda x: x.edges(labels=False)).list()) # optional -- internet + sage: len(cc.first_terms(lambda x: x.edges(labels=False, sort=False)).list()) # optional -- internet 4 """ if isinstance(entry, self.Element): diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index cdfc11a9e52..f47d5d36249 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -1103,6 +1103,303 @@ def nth_iterate(self, P, n, **kwds): raise TypeError("must be a forward orbit") return self.orbit(P, [n,n+1], **kwds)[0] + def arakelov_zhang_pairing(self, g, **kwds): + r""" + Return an estimate of the Arakelov-Zhang pairing of the rational + maps ``self`` and ``g`` on `\mathbb{P}^1` over a number field. + + The Arakelov-Zhang pairing was introduced by Petsche, Szpiro, and + Tucker in 2012, which measures the dynamical closeness of two rational + maps. They prove inter alia that if one takes a sequence of small points + for one map (for example, preperiodic points for ``self``) and measure + their dynamical height with respect to the other map (say, ``g``), then + the values of the height will tend to the value of the Arakelov-Zhang pairing. + + The Arakelov-Zhang pairing involves mutual energy integrals between dynamical + measures, which are in the case of polynomials, the equilibrium measures + of the associated Julia sets at each place. As a result, these pairings + are very difficult to compute exactly via analytic methods. We use a + discrete approximation to these energy integrals. + + ALGORITHM: + + We select periodic points of order `n`, or ``n``-th preimages of a + specified starting value given by ``f_starting_point`` and ``g_starting_point``. + At the archimedean places and the places of bad reduction of the two maps, + we compute the discrete approximations to the energy integrals involved + using these points. + + INPUT: + + - ``g`` - a rational map of `\mathbb{P}^1` given as a projective morphism. + ``g`` and ``self`` should have the same field of definition. + + kwds: + + - ``n`` - (default: 5) a positive integer + Order of periodic points to use or preimages to take if starting points are specified. + + - ``f_starting_point`` - (optional, default: ``None``) value in the base number field or None. + If ``f_starting_point`` is None, we solve for points of period ``n`` for ``self``. + Otherwise, we take ``n``-th preimages of the point given by ``f_starting_point`` + under ``f`` on the affine line. + + - ``g_starting_point`` - (optional, default: ``None``) value in the base number field or None. + If ``g_starting_point`` is None, we solve for points of period ``n`` for ``g``. + Otherwise, we take ``n``-th preimages of the point given by ``g_starting_point`` + under ``g`` on the affine line. + + - ``check_primes_of_bad_reduction`` - (optional, default: ``False``) boolean. + Passed to the ``primes_of_bad_reduction`` function for ``self`` and ``g``. + + - ``prec`` - (optional, default: ``RealField`` default) + default precision for RealField values which are returned. + + - ``noise_multiplier`` - (default: 2) a real number. + Discriminant terms involved in the computation at the archimedean places + are often not needed, particularly if the capacity of the Julia sets is 1, + and introduce a lot of error. By a well-known result of Mahler (see + also M. Baker, ""A lower bound for averages of dynamical Green's + functions") such error (for a set of `N` points) is on the order of + `\log(N)/N` after our normalization. We check if the value of the + archimedean discriminant terms is within ``2*noise_multiplier`` of + `\log(N)/N`. If so, we discard it. In practice this greatly improves + the accuracy of the estimate of the pairing. If desired, + ``noise_multiplier`` can be set to 0, and no terms will be ignored. + + OUTPUT: + + - a real number estimating the Arakelov-Zhang pairing of the two rational maps. + + EXAMPLES:: + + sage: K. = CyclotomicField(3) + sage: P. = ProjectiveSpace(K, 1) + sage: f = DynamicalSystem_projective([x^2 + (2*k + 2)*y^2, y^2]) + sage: g = DynamicalSystem_projective([x^2, y^2]) + sage: pairingval = f.arakelov_zhang_pairing(g, n=5); pairingval + 0.409598197761958 + + :: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([x^2 + 4*y^2, y^2]) + sage: g = DynamicalSystem_projective([x^2, y^2]) + sage: pairingval = f.arakelov_zhang_pairing(g, n=6); pairingval + 0.750178391443644 + sage: # Compare to the exact value: + sage: dynheight = f.canonical_height(P(0, 1)); dynheight + 0.75017839144364417318023000563 + sage: dynheight - pairingval + 0.000000000000000 + + Notice that if we set the noise_multiplier to 0, the accuracy is diminished:: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([x^2 + 4*y^2, y^2]) + sage: g = DynamicalSystem_projective([x^2, y^2]) + sage: pairingval = f.arakelov_zhang_pairing(g, n=6, noise_multiplier=0) + sage: pairingval + 0.650660018921632 + sage: dynheight = f.canonical_height(P(0, 1)); dynheight + 0.75017839144364417318023000563 + sage: pairingval - dynheight + -0.0995183725220122 + + We compute the example of Prop. 18(d) from Petsche, Szpiro and Tucker:: + + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([y^2 - (y - x)^2, y^2]) + sage: g = DynamicalSystem_projective([x^2, y^2]) + sage: f.arakelov_zhang_pairing(g) + 0.326954667248466 + sage: # Correct value should be = 0.323067... + sage: f.arakelov_zhang_pairing(g, n=9) + 0.323091061918965 + sage: _ - 0.323067 + 0.0000240619189654789 + + Also from Prop. 18 of Petsche, Szpiro and Tucker, includes places of bad reduction:: + + sage: R. = PolynomialRing(ZZ) + sage: K. = NumberField(z^3 - 11) + sage: P. = ProjectiveSpace(K,1) + sage: a = 7/(b - 1) + sage: f = DynamicalSystem_projective([a*y^2 - (a*y - x)^2, y^2]) + sage: g = DynamicalSystem_projective([x^2, y^2]) + sage: # If all archimedean absolute values of a have modulus > 2, + sage: # then the pairing should be h(a). + sage: f.arakelov_zhang_pairing(g, n=6) + 1.93846423207664 + sage: _ - a.global_height() + -0.00744591697867292 + """ + n = kwds.pop('n', 5) + f_starting_point = kwds.pop('f_starting_point', None) + g_starting_point = kwds.pop('g_starting_point', None) + check_primes_of_bad_reduction = kwds.pop('check_primes_of_bad_reduction', False) + prec = kwds.pop('prec', None) + noise_multiplier = kwds.pop('noise_multiplier', 2) + + f_domain = self.domain() + R = f_domain.base_ring() + g_domain = g.domain() + + if f_domain != g_domain: + raise TypeError("Implemented only for rational maps of the same projective line.") + + if n <= 0: + raise ValueError("Period must be a positive integer.") + + if not (is_ProjectiveSpace(f_domain) and is_ProjectiveSpace(g_domain)): + raise NotImplementedError("Not implemented for subschemes.") + + if f_domain.dimension_relative() > 1: + raise NotImplementedError("Only implemented for dimension 1.") + + if not self.is_endomorphism(): + raise TypeError("Self must be an endomorphism.") + + if R not in NumberFields() and R is not QQbar: + raise NotImplementedError("Only implemented for number fields.") + + f_iterate_map = self.nth_iterate_map(n) + f_iter_map_poly = f_iterate_map.defining_polynomials() + if f_starting_point is None: + f_poly_hom = f_iter_map_poly[0] * f_domain.gens()[1] - f_iter_map_poly[1] * f_domain.gens()[0] + else: + f_poly_hom = f_iter_map_poly[0] - f_starting_point * f_iter_map_poly[1] + + g_iterate_map = g.nth_iterate_map(n) + g_iter_map_poly = g_iterate_map.defining_polynomials() + if g_starting_point is None: + g_poly_hom = g_iter_map_poly[0] * g_domain.gens()[1] - g_iter_map_poly[1] * g_domain.gens()[0] + else: + g_poly_hom = g_iter_map_poly[0] - g_starting_point * g_iter_map_poly[1] + + f_poly = f_poly_hom([(f_domain.gens()[0]), 1]).univariate_polynomial().monic() + g_poly = g_poly_hom([(g_domain.gens()[0]), 1]).univariate_polynomial().monic() + + # If f_poly and g_poly are not square-free, make them square-free. + if not f_poly.is_squarefree(): + f_poly = f_poly.quo_rem(gcd(f_poly, f_poly.derivative()))[0] + if not g_poly.is_squarefree(): + g_poly = g_poly.quo_rem(gcd(g_poly, g_poly.derivative()))[0] + + if f_poly.degree() <= 2 or g_poly.degree() <= 2: + # f_point or g_point is exceptional + raise ValueError("One of the starting points is exceptional. \ + Please specify a non-exceptional initial point.") + + if gcd(f_poly, g_poly).degree() > 0: + if f_poly.degree() > g_poly.degree(): + f_poly = f_poly.quo_rem(gcd(f_poly, g_poly))[0] + else: + g_poly = g_poly.quo_rem(gcd(f_poly, g_poly))[0] + + if f_poly.degree() <= 2 or g_poly.degree() <= 2: + raise ValueError("After removing common factors, the n-th \ + iterates of 'self' and 'g' have too many \ + roots in common. Try another 'n' or starting \ + values.") + + # We want higher precision here temporarily, since resultants are + # usually very large. This is not to say that the computation is + # very accurate, merely that we want to keep track of potentially + # very large height integers/rationals. + old_prec = prec + if prec is None: + Real = RealField(512) + elif prec < 512: + prec = 512 + Real = RealField(prec) + + bad_primes = list(set(self.primes_of_bad_reduction(check=check_primes_of_bad_reduction)) + .union(g.primes_of_bad_reduction(check=check_primes_of_bad_reduction))) + + f_deg = f_poly.degree() + g_deg = g_poly.degree() + + f_disc = f_poly.discriminant() + g_disc = g_poly.discriminant() + + res = f_poly.resultant(g_poly) + + # The code below actually computes -( mu_f - mu_g, mu_f - mu_g ), + # so flip the sign at the end. + AZ_pairing = Real(0) + if R is QQ: + for p in bad_primes: + temp = (ZZ(1)/2) * (-f_disc.ord(p)) * Real(p).log() / (f_deg**2) + if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): + AZ_pairing += temp + + temp = (ZZ(1)/2) * (-g_disc.ord(p)) * Real(p).log() / (g_deg**2) + if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): + AZ_pairing += temp + + AZ_pairing -= (-res.ord(p)) * Real(p).log() / (f_deg * g_deg) + + temp = (ZZ(1)/2) * (Real(f_disc).abs().log()) / (f_deg**2) + if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): + AZ_pairing += temp + + temp = (ZZ(1)/2) * (Real(g_disc).abs().log()) / (g_deg**2) + if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): + AZ_pairing += temp + + AZ_pairing -= Real(res).abs().log() / (f_deg * g_deg) + + # For number fields + else: + K = self.base_ring() + d = K.absolute_degree() + + for v in bad_primes: + Nv = v.absolute_ramification_index() * v.residue_class_degree() / d + + temp = Nv * ((ZZ(1)/2) * K(f_disc).abs_non_arch(v, prec=prec).log() / (f_deg**2)) + if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): + AZ_pairing += temp + + temp = Nv * ((ZZ(1)/2) * K(g_disc).abs_non_arch(v, prec=prec).log() / (g_deg**2)) + if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): + AZ_pairing += temp + + AZ_pairing -= Nv * (K(res).abs_non_arch(v, prec=prec).log() / (f_deg * g_deg)) + + if f_disc.is_rational(): + f_disc = QQ(f_disc) + temp = (ZZ(1)/2) * (Real(f_disc).abs().log()) / (f_deg**2) + if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): + AZ_pairing += temp + else: + temp = (ZZ(1)/d) * (ZZ(1)/2) * (Real(K(f_disc).norm()).abs().log()) / (f_deg**2) + if abs(temp) > noise_multiplier * Real(f_deg).log() / Real(f_deg): + AZ_pairing += temp + + if g_disc.is_rational(): + g_disc = QQ(g_disc) + temp = (ZZ(1)/2) * (Real(g_disc).abs().log()) / (g_deg**2) + if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): + AZ_pairing += temp + else: + temp = (ZZ(1)/d) * (ZZ(1)/2) * (Real(K(g_disc).norm()).abs().log()) / (g_deg**2) + if abs(temp) > noise_multiplier * Real(g_deg).log() / Real(g_deg): + AZ_pairing += temp + + if res.is_rational(): + AZ_pairing -= (Real(res).abs().log()) / (f_deg * g_deg) + else: + AZ_pairing -= (ZZ(1)/d) * (Real(K(res).norm()).abs().log()) / (f_deg * g_deg) + + if old_prec is None: + Real = RealField() + else: + Real = RealField(old_prec) + + return Real(-AZ_pairing) + def degree_sequence(self, iterates=2): r""" Return sequence of degrees of normalized iterates starting with diff --git a/src/sage/features/join_feature.py b/src/sage/features/join_feature.py index b29241eb462..92e9851d635 100644 --- a/src/sage/features/join_feature.py +++ b/src/sage/features/join_feature.py @@ -9,6 +9,17 @@ class JoinFeature(Feature): r""" Join of several :class:`~sage.features.Feature` instances. + This creates a new feature as the union of the given features. Typically + these are executables of an SPKG. For an example, see + :class:`~sage.features.rubiks.Rubiks`. + + Furthermore, this can be the union of a single feature. This is used to map + the given feature to a more convenient name to be used in ``optional`` tags + of doctests. Thus you can equip a feature such as a + :class:`~sage.features.PythonModule` with a tag name that differs from the + systematic tag name. As an example for this use case, see + :class:`~sage.features.meataxe.Meataxe`. + EXAMPLES:: sage: from sage.features import Executable diff --git a/src/sage/functions/airy.py b/src/sage/functions/airy.py index cf32fb8f1c8..eceb9e6eafc 100644 --- a/src/sage/functions/airy.py +++ b/src/sage/functions/airy.py @@ -1,5 +1,5 @@ r""" -Airy Functions +Airy functions This module implements Airy functions and their generalized derivatives. It supports symbolic functionality through Maxima and numeric evaluation through diff --git a/src/sage/functions/bessel.py b/src/sage/functions/bessel.py index de1401dde68..d6c5c4ed4bc 100644 --- a/src/sage/functions/bessel.py +++ b/src/sage/functions/bessel.py @@ -1,5 +1,5 @@ r""" -Bessel Functions +Bessel functions This module provides symbolic Bessel and Hankel functions, and their spherical versions. These functions use the `mpmath library`_ for numerical diff --git a/src/sage/functions/error.py b/src/sage/functions/error.py index 06f0b244736..ca665622f20 100644 --- a/src/sage/functions/error.py +++ b/src/sage/functions/error.py @@ -1,5 +1,5 @@ r""" -Error Functions +Error functions This module provides symbolic error functions. These functions use the `mpmath library` for numerical evaluation and Maxima, Pynac for diff --git a/src/sage/functions/exp_integral.py b/src/sage/functions/exp_integral.py index 7ef74d9ed49..3f193cf5f1b 100644 --- a/src/sage/functions/exp_integral.py +++ b/src/sage/functions/exp_integral.py @@ -1,5 +1,5 @@ r""" -Exponential Integrals +Exponential integrals AUTHORS: diff --git a/src/sage/functions/generalized.py b/src/sage/functions/generalized.py index a24268c9b6b..d912ea23719 100644 --- a/src/sage/functions/generalized.py +++ b/src/sage/functions/generalized.py @@ -1,5 +1,5 @@ r""" -Generalized Functions +Generalized functions Sage implements several generalized functions (also known as distributions) such as Dirac delta, Heaviside step functions. These diff --git a/src/sage/functions/hyperbolic.py b/src/sage/functions/hyperbolic.py index 4487a3b3641..9a362b8882f 100644 --- a/src/sage/functions/hyperbolic.py +++ b/src/sage/functions/hyperbolic.py @@ -1,5 +1,5 @@ r""" -Hyperbolic Functions +Hyperbolic functions The full set of hyperbolic and inverse hyperbolic functions is available: diff --git a/src/sage/functions/hypergeometric.py b/src/sage/functions/hypergeometric.py index 795a1ab7228..50c60b25638 100644 --- a/src/sage/functions/hypergeometric.py +++ b/src/sage/functions/hypergeometric.py @@ -1,5 +1,5 @@ r""" -Hypergeometric Functions +Hypergeometric functions This module implements manipulation of infinite hypergeometric series represented in standard parametric form (as `\,_pF_q` functions). diff --git a/src/sage/functions/jacobi.py b/src/sage/functions/jacobi.py index af67d857f27..6fe3b2ade89 100644 --- a/src/sage/functions/jacobi.py +++ b/src/sage/functions/jacobi.py @@ -1,5 +1,5 @@ r""" -Jacobi Elliptic Functions +Jacobi elliptic functions This module implements the 12 Jacobi elliptic functions, along with their inverses and the Jacobi amplitude function. diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index 46cc279a287..6f9133841a3 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -1,5 +1,5 @@ """ -Logarithmic Functions +Logarithmic functions AUTHORS: diff --git a/src/sage/functions/min_max.py b/src/sage/functions/min_max.py index 9b7d6d99f62..f783de0ba96 100644 --- a/src/sage/functions/min_max.py +++ b/src/sage/functions/min_max.py @@ -1,5 +1,5 @@ r""" -Symbolic Minimum and Maximum +Symbolic minimum and maximum Sage provides a symbolic maximum and minimum due to the fact that the Python builtin max and min are not able to deal with variables as users might expect. diff --git a/src/sage/functions/orthogonal_polys.py b/src/sage/functions/orthogonal_polys.py index 77b7e06b909..7398c763971 100644 --- a/src/sage/functions/orthogonal_polys.py +++ b/src/sage/functions/orthogonal_polys.py @@ -1,5 +1,5 @@ r""" -Orthogonal Polynomials +Orthogonal polynomials Chebyshev polynomials --------------------- diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index 688db13a3b8..10d82e3709a 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- r""" -Piecewise-defined Functions +Piecewise functions This module implement piecewise functions in a single variable. See :mod:`sage.sets.real_set` for more information about how to construct diff --git a/src/sage/functions/prime_pi.pyx b/src/sage/functions/prime_pi.pyx index 0a576734777..38c68a2d4b4 100644 --- a/src/sage/functions/prime_pi.pyx +++ b/src/sage/functions/prime_pi.pyx @@ -1,5 +1,13 @@ r""" -Counting Primes +Counting primes + +EXAMPLES:: + + sage: z = sage.functions.prime_pi.PrimePi() + sage: loads(dumps(z)) + prime_pi + sage: loads(dumps(z)) == z + True AUTHORS: @@ -12,14 +20,6 @@ AUTHORS: - Dima Pasechnik (2021): removed buggy cython code, replaced it with calls to primecount/primecountpy spkg - -EXAMPLES:: - - sage: z = sage.functions.prime_pi.PrimePi() - sage: loads(dumps(z)) - prime_pi - sage: loads(dumps(z)) == z - True """ # **************************************************************************** diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 02596e49620..56f96f2ef53 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -1,20 +1,5 @@ r""" -Miscellaneous Special Functions - -AUTHORS: - -- David Joyner (2006-13-06): initial version - -- David Joyner (2006-30-10): bug fixes to pari wrappers of Bessel - functions, hypergeometric_U - -- William Stein (2008-02): Impose some sanity checks. - -- David Joyner (2008-04-23): addition of elliptic integrals - -- Eviatar Bach (2013): making elliptic integrals symbolic - -- Eric Gourgoulhon (2022): add Condon-Shortley phase to spherical harmonics +Miscellaneous special functions This module provides easy access to many of Maxima and PARI's special functions. @@ -104,6 +89,11 @@ and the complete ones are obtained by taking `\phi =\pi/2`. +.. WARNING:: + + SciPy's versions are poorly documented and seem less accurate than the + Maxima and PARI versions. Typically they are limited by hardware floats + precision. REFERENCES: @@ -118,16 +108,20 @@ AUTHORS: -- David Joyner and William Stein +- David Joyner (2006-13-06): initial version + +- David Joyner (2006-30-10): bug fixes to pari wrappers of Bessel + functions, hypergeometric_U + +- William Stein (2008-02): Impose some sanity checks. + +- David Joyner (2008-02-16): optional calls to scipy and replace all ``#random`` by ``...`` -Added 16-02-2008 (wdj): optional calls to scipy and replace all -'#random' by '...' (both at the request of William Stein) +- David Joyner (2008-04-23): addition of elliptic integrals -.. warning:: +- Eviatar Bach (2013): making elliptic integrals symbolic - SciPy's versions are poorly documented and seem less - accurate than the Maxima and PARI versions; typically they are limited - by hardware floats precision. +- Eric Gourgoulhon (2022): add Condon-Shortley phase to spherical harmonics """ # **************************************************************************** @@ -849,7 +843,7 @@ class EllipticF(BuiltinFunction): - :wikipedia:`Elliptic_integral#Incomplete_elliptic_integral_of_the_first_kind` """ def __init__(self): - """ + r""" EXAMPLES:: sage: loads(dumps(elliptic_f)) diff --git a/src/sage/functions/spike_function.py b/src/sage/functions/spike_function.py index 2118c1b2dcc..83fde81b0ca 100644 --- a/src/sage/functions/spike_function.py +++ b/src/sage/functions/spike_function.py @@ -1,5 +1,5 @@ r""" -Spike Functions +Spike functions AUTHORS: diff --git a/src/sage/functions/transcendental.py b/src/sage/functions/transcendental.py index a470e9ed67d..b76e3a1bbbe 100644 --- a/src/sage/functions/transcendental.py +++ b/src/sage/functions/transcendental.py @@ -1,5 +1,5 @@ """ -Number-Theoretic Functions +Number-theoretic functions """ # **************************************************************************** # Copyright (C) 2005 William Stein diff --git a/src/sage/functions/trig.py b/src/sage/functions/trig.py index fb97a5e8c58..16aeeae43ab 100644 --- a/src/sage/functions/trig.py +++ b/src/sage/functions/trig.py @@ -1,5 +1,5 @@ r""" -Trigonometric Functions +Trigonometric functions """ from sage.symbolic.function import GinacFunction import math diff --git a/src/sage/geometry/polyhedron/backend_field.py b/src/sage/geometry/polyhedron/backend_field.py index 6b921d23a68..93c46c66309 100644 --- a/src/sage/geometry/polyhedron/backend_field.py +++ b/src/sage/geometry/polyhedron/backend_field.py @@ -162,66 +162,76 @@ def _init_from_Vrepresentation_and_Hrepresentation(self, Vrep, Hrep): self._init_Hrepresentation(*Hrep) def _init_from_Vrepresentation(self, vertices, rays, lines, - minimize=True, verbose=False): + minimize=True, verbose=False, + internal_base_ring=None): """ Construct polyhedron from V-representation data. INPUT: - ``vertices`` -- list of points. Each point can be specified - as any iterable container of - :meth:`~sage.geometry.polyhedron.base.base_ring` elements. + as any iterable container of ``internal_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. + iterable container of ``internal_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. + - ``lines`` -- list of lines. Each line can be specified asinternal_base_ring + any iterable container of ``internal_base_ring`` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. + - ``internal_base_ring`` -- the base ring of the generators' components. + Default is ``None``, in which case, it is set to + :meth:`~sage.geometry.polyhedron.base.base_ring`. + EXAMPLES:: sage: p = Polyhedron(ambient_dim=2, backend='field') sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field sage: Polyhedron_field._init_from_Vrepresentation(p, [(0,0)], [], []) """ + if internal_base_ring is None: + internal_base_ring = self.base_ring() from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep, Vrep2Hrep - H = Vrep2Hrep(self.base_ring(), self.ambient_dim(), vertices, rays, lines) - V = Hrep2Vrep(self.base_ring(), self.ambient_dim(), + H = Vrep2Hrep(internal_base_ring, self.ambient_dim(), vertices, rays, lines) + V = Hrep2Vrep(internal_base_ring, self.ambient_dim(), H.inequalities, H.equations) self._init_Vrepresentation_backend(V) self._init_Hrepresentation_backend(H) - def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): + def _init_from_Hrepresentation(self, ieqs, eqns, + minimize=True, verbose=False, + internal_base_ring=None): """ 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. + as any iterable container of ``internal_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. + as any iterable container of ``internal_base_ring`` elements. - ``verbose`` -- boolean (default: ``False``). Whether to print verbose output for debugging purposes. + - ``internal_base_ring`` -- the base ring of the generators' components. + Default is ``None``, in which case, it is set to + :meth:`~sage.geometry.polyhedron.base.base_ring`. + TESTS:: sage: p = Polyhedron(ambient_dim=2, backend='field') sage: from sage.geometry.polyhedron.backend_field import Polyhedron_field sage: Polyhedron_field._init_from_Hrepresentation(p, [(1, 2, 3)], []) """ + if internal_base_ring is None: + internal_base_ring = self.base_ring() from sage.geometry.polyhedron.double_description_inhomogeneous import Hrep2Vrep, Vrep2Hrep - V = Hrep2Vrep(self.base_ring(), self.ambient_dim(), ieqs, eqns) - H = Vrep2Hrep(self.base_ring(), self.ambient_dim(), + V = Hrep2Vrep(internal_base_ring, self.ambient_dim(), ieqs, eqns) + H = Vrep2Hrep(internal_base_ring, self.ambient_dim(), V.vertices, V.rays, V.lines) self._init_Vrepresentation_backend(V) self._init_Hrepresentation_backend(H) diff --git a/src/sage/geometry/polyhedron/backend_normaliz.py b/src/sage/geometry/polyhedron/backend_normaliz.py index f38498aa597..af0c2c459a7 100644 --- a/src/sage/geometry/polyhedron/backend_normaliz.py +++ b/src/sage/geometry/polyhedron/backend_normaliz.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ The Normaliz backend for polyhedral computations @@ -13,7 +12,15 @@ - Jean-Philippe Labbé (2019-04): Expose normaliz features and added functionalities """ # **************************************************************************** -# Copyright (C) 2016 Matthias Köppe +# Copyright (C) 2016-2022 Matthias Köppe +# 2016-2018 Travis Scrimshaw +# 2017 Jeroen Demeyer +# 2018-2020 Jean-Philippe Labbé +# 2019 Vincent Delecroix +# 2019-2021 Jonathan Kliem +# 2019-2021 Sophia Elia +# 2020 Frédéric Chapoton +# 2022 Yuan Zhou # # 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 @@ -36,33 +43,9 @@ from sage.misc.functional import denominator from sage.matrix.constructor import vector -from .base import Polyhedron_base from .base_QQ import Polyhedron_QQ from .base_ZZ import Polyhedron_ZZ - - -def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds): - r""" - Like `number_field_elements_from_algebraics`, but for a list of lists of lists. - - EXAMPLES:: - - sage: rt2 = AA(sqrt(2)); rt2 # optional - sage.rings.number_field - 1.414213562373095? - sage: rt3 = AA(sqrt(3)); rt3 # optional - sage.rings.number_field - 1.732050807568878? - sage: from sage.geometry.polyhedron.backend_normaliz import _number_field_elements_from_algebraics_list_of_lists_of_lists - sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results # optional - sage.rings.number_field - [[[-a^3 + 3*a], [1]], [[-a^2 + 2]], [[1], []]] - """ - from sage.rings.qqbar import number_field_elements_from_algebraics - numbers = [] - for lists in listss: - for list in lists: - numbers.extend(list) - K, K_numbers, hom = number_field_elements_from_algebraics(numbers, **kwds) - g = iter(K_numbers) - return K, [ [ [ next(g) for _ in list ] for list in lists ] for lists in listss ], hom +from .base_number_field import Polyhedron_base_number_field def _format_function_call(fn_name, *v, **k): @@ -82,7 +65,7 @@ def _format_function_call(fn_name, *v, **k): ######################################################################### -class Polyhedron_normaliz(Polyhedron_base): +class Polyhedron_normaliz(Polyhedron_base_number_field): """ Polyhedra with normaliz @@ -208,7 +191,7 @@ class Polyhedron_normaliz(Polyhedron_base): (A vertex at (2^(1/3)), A vertex at (sqrt(2))) """ - def __init__(self, parent, Vrep, Hrep, normaliz_cone=None, normaliz_data=None, normaliz_field=None, **kwds): + def __init__(self, parent, Vrep, Hrep, normaliz_cone=None, normaliz_data=None, internal_base_ring=None, **kwds): """ Initializes the polyhedron. @@ -230,16 +213,16 @@ def __init__(self, parent, Vrep, Hrep, normaliz_cone=None, normaliz_data=None, n if Hrep is not None or Vrep is not None or normaliz_data is not None: raise ValueError("only one of Vrep, Hrep, normaliz_cone, or normaliz_data can be different from None") Element.__init__(self, parent=parent) - self._init_from_normaliz_cone(normaliz_cone, normaliz_field) + self._init_from_normaliz_cone(normaliz_cone, internal_base_ring) elif normaliz_data: if Hrep is not None or Vrep is not None: raise ValueError("only one of Vrep, Hrep, normaliz_cone, or normaliz_data can be different from None") Element.__init__(self, parent=parent) - self._init_from_normaliz_data(normaliz_data, normaliz_field) + self._init_from_normaliz_data(normaliz_data, internal_base_ring) else: - if normaliz_field: - raise ValueError("if Vrep or Hrep are given, cannot provide normaliz_field") - Polyhedron_base.__init__(self, parent, Vrep, Hrep, **kwds) + if internal_base_ring: + raise ValueError("if Vrep or Hrep are given, cannot provide internal_base_ring") + Polyhedron_base_number_field.__init__(self, parent, Vrep, Hrep, **kwds) def _nmz_result(self, normaliz_cone, property): """ @@ -277,13 +260,13 @@ def rational_handler(list): def nfelem_handler(coords): # coords might be too short which is not accepted by Sage number field - v = list(coords) + [0] * (self._normaliz_field.degree() - len(coords)) - return self._normaliz_field(v) + v = list(coords) + [0] * (self._internal_base_ring.degree() - len(coords)) + return self._internal_base_ring(v) return NmzResult(normaliz_cone, property, RationalHandler=rational_handler, NumberfieldElementHandler=nfelem_handler) - def _init_from_normaliz_cone(self, normaliz_cone, normaliz_field): + def _init_from_normaliz_cone(self, normaliz_cone, internal_base_ring): """ Construct polyhedron from a PyNormaliz wrapper of a normaliz cone. @@ -293,9 +276,9 @@ def _init_from_normaliz_cone(self, normaliz_cone, normaliz_field): sage: from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz # optional - pynormaliz sage: Polyhedron_normaliz._init_from_Hrepresentation(p, [], []) # indirect doctest # optional - pynormaliz """ - if normaliz_field is None: - normaliz_field = QQ - self._normaliz_field = normaliz_field + if internal_base_ring is None: + internal_base_ring = QQ + self._internal_base_ring = internal_base_ring if normaliz_cone and self._nmz_result(normaliz_cone, "AffineDim") < 0: # Empty polyhedron. Special case because Normaliz defines the @@ -356,7 +339,7 @@ def _QQ_pair(x): # number field return [ _QQ_pair(c) for c in x.list() ] - def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): + def _init_from_normaliz_data(self, data, internal_base_ring=None, verbose=False): """ Construct polyhedron from normaliz ``data`` (a dictionary). @@ -377,15 +360,15 @@ def _init_from_normaliz_data(self, data, normaliz_field=None, verbose=False): sage: from sage.geometry.polyhedron.parent import Polyhedra_normaliz # optional - pynormaliz sage: parent = Polyhedra_normaliz(AA, 2, 'normaliz') # optional - pynormaliz # optional - sage.rings.number_field sage: Polyhedron_normaliz(parent, None, None, normaliz_data=data, # indirect doctest, optional - pynormaliz # optional - sage.rings.number_field - ....: normaliz_field=QuadraticField(2)) + ....: internal_base_ring=QuadraticField(2)) A 2-dimensional polyhedron in AA^2 defined as the convex hull of 1 vertex and 2 rays sage: _.inequalities_list() # optional - pynormaliz # optional - sage.rings.number_field [[0, -1/2, 1], [0, 2, -1]] """ - if normaliz_field is None: - normaliz_field = QQ + if internal_base_ring is None: + internal_base_ring = QQ cone = self._cone_from_normaliz_data(data, verbose) - self._init_from_normaliz_cone(cone, normaliz_field) + self._init_from_normaliz_cone(cone, internal_base_ring) def _cone_from_normaliz_data(self, data, verbose=False): """ @@ -543,10 +526,9 @@ def vert_ray_line_NF(vertices, rays, lines): if lines is None: lines = [] - (nmz_vertices, nmz_rays, nmz_lines), normaliz_field \ - = self._compute_nmz_data_lists_and_field((vertices, rays, lines), - vert_ray_line_QQ, - vert_ray_line_NF) + (nmz_vertices, nmz_rays, nmz_lines), internal_base_ring \ + = self._compute_data_lists_and_internal_base_ring( + (vertices, rays, lines), vert_ray_line_QQ, vert_ray_line_NF) if not nmz_vertices and not nmz_rays and not nmz_lines: # Special case to avoid: @@ -557,10 +539,10 @@ def vert_ray_line_NF(vertices, rays, lines): data = {"vertices": nmz_vertices, "cone": nmz_rays, "subspace": nmz_lines} - number_field_data = self._number_field_triple(normaliz_field) + number_field_data = self._number_field_triple(internal_base_ring) if number_field_data: data["number_field"] = number_field_data - self._init_from_normaliz_data(data, normaliz_field=normaliz_field, verbose=verbose) + self._init_from_normaliz_data(data, internal_base_ring=internal_base_ring, verbose=verbose) def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): r""" @@ -642,10 +624,9 @@ def nmz_ieqs_eqns_QQ(ieqs, eqns): if eqns is None: eqns = [] - (nmz_ieqs, nmz_eqns), normaliz_field \ - = self._compute_nmz_data_lists_and_field((ieqs, eqns), - nmz_ieqs_eqns_QQ, - nmz_ieqs_eqns_NF) + (nmz_ieqs, nmz_eqns), internal_base_ring \ + = self._compute_data_lists_and_internal_base_ring( + (ieqs, eqns), nmz_ieqs_eqns_QQ, nmz_ieqs_eqns_NF) if not nmz_ieqs: # If normaliz gets an empty list of inequalities, it adds # nonnegativities. So let's add a tautological inequality to work @@ -653,10 +634,10 @@ def nmz_ieqs_eqns_QQ(ieqs, eqns): nmz_ieqs.append([0] * self.ambient_dim() + [0]) data = {"inhom_equations": nmz_eqns, "inhom_inequalities": nmz_ieqs} - number_field_data = self._number_field_triple(normaliz_field) + number_field_data = self._number_field_triple(internal_base_ring) if number_field_data: data["number_field"] = number_field_data - self._init_from_normaliz_data(data, normaliz_field=normaliz_field, verbose=verbose) + self._init_from_normaliz_data(data, internal_base_ring=internal_base_ring, verbose=verbose) def _cone_from_Vrepresentation_and_Hrepresentation(self, vertices, rays, lines, ieqs, eqns=None, verbose=False, homogeneous=False): r""" @@ -850,10 +831,10 @@ def rays_subspace_lattice_ieqs_NF(vertices, rays, lines, ieqs): return nmz_vertices + nmz_rays, nmz_lines, nmz_lattice, nmz_ieqs - (nmz_extreme_rays, nmz_subspace, nmz_lattice, nmz_ieqs), normaliz_field \ - = self._compute_nmz_data_lists_and_field((vertices, rays, lines, ieqs), - rays_subspace_lattice_ieqs_QQ, - rays_subspace_lattice_ieqs_NF) + (nmz_extreme_rays, nmz_subspace, nmz_lattice, nmz_ieqs), internal_base_ring \ + = self._compute_data_lists_and_internal_base_ring( + (vertices, rays, lines, ieqs), rays_subspace_lattice_ieqs_QQ, + rays_subspace_lattice_ieqs_NF) data = {"extreme_rays": nmz_extreme_rays, "maximal_subspace": nmz_subspace, @@ -864,7 +845,7 @@ def rays_subspace_lattice_ieqs_NF(vertices, rays, lines, ieqs): if not homogeneous: data["dehomogenization"] = [[0] * (ambient_dim - 1) + [1]] - number_field_data = self._number_field_triple(normaliz_field) + number_field_data = self._number_field_triple(internal_base_ring) if number_field_data: data["number_field"] = number_field_data return self._cone_from_normaliz_data(data, verbose=verbose) @@ -910,71 +891,6 @@ def _test_far_facet_condition(self, tester=None, **options): tester.assertEqual(self.n_inequalities() + 1, len(nmz_ieqs)) tester.assertTrue(any(ieq == [0] * self.ambient_dim() + [1] for ieq in nmz_ieqs)) - def _compute_nmz_data_lists_and_field(self, data_lists, convert_QQ, convert_NF): - r""" - Compute data lists in Normaliz format and the number field to use with Normaliz. - - EXAMPLES:: - - sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], # optional - pynormaliz - ....: base_ring=AA, backend='normaliz') - sage: def convert_QQ(ieqs, eqs): # optional - pynormaliz - ....: return [ [ 1000*x for x in ieq ] for ieq in ieqs], \ - ....: [ [ 1000*x for x in eq ] for eq in eqs] - sage: def convert_NF(ieqs, eqs): # optional - pynormaliz - ....: return ieqs, eqs - sage: p._compute_nmz_data_lists_and_field([[[1]], [[1/2]]], # optional - pynormaliz - ....: convert_QQ, convert_NF) - (([[1000]], [[500]]), Rational Field) - sage: p._compute_nmz_data_lists_and_field([[[AA(1)]], [[1/2]]], # optional - pynormaliz - ....: convert_QQ, convert_NF) - (([[1000]], [[500]]), Rational Field) - sage: p._compute_nmz_data_lists_and_field([[[AA(sqrt(2))]], [[1/2]]], # optional - pynormaliz # optional - sage.rings.number_field - ....: convert_QQ, convert_NF) - ([[[a]], [[1/2]]], - Number Field in a with defining polynomial y^2 - 2 with a = 1.414213562373095?) - - TESTS:: - - sage: K. = QuadraticField(-5) # optional - sage.rings.number_field - sage: p = Polyhedron(vertices=[(a,1/2),(2,0),(4,5/6)], # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field - ....: base_ring=K, backend='normaliz') - Traceback (most recent call last): - ... - ValueError: invalid base ring: Number Field in a ... is not real embedded - - Checks that :trac:`30248` is fixed:: - - sage: q = Polyhedron(backend='normaliz', base_ring=AA, # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field - ....: rays=[(0, 0, 1), (0, 1, -1), (1, 0, -1)]); q - A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays - sage: -q # optional - pynormaliz # optional - sage.rings.number_field - A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays - """ - from sage.categories.number_fields import NumberFields - from sage.rings.real_double import RDF - - if self.base_ring() in (QQ, ZZ): - normaliz_field = QQ - nmz_data_lists = convert_QQ(*data_lists) - else: - # Allows to re-iterate if K is QQ below when data_lists contain - # iterators: - data_lists = [tuple(_) for _ in data_lists] - nmz_data_lists = convert_NF(*data_lists) - if self.base_ring() in NumberFields(): - if not RDF.has_coerce_map_from(self.base_ring()): - raise ValueError("invalid base ring: {} is a number field that is not real embedded".format(self.base_ring())) - normaliz_field = self.base_ring() - else: - K, nmz_data_lists, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists(nmz_data_lists, embedded=True) - normaliz_field = K - if K is QQ: - # Compute it with Normaliz, not QNormaliz - nmz_data_lists = convert_QQ(*[ [ [ QQ(x) for x in v ] for v in l] - for l in data_lists ]) - return nmz_data_lists, normaliz_field - def _init_Vrepresentation_from_normaliz(self): r""" Create the Vrepresentation objects from the normaliz polyhedron. @@ -1057,7 +973,7 @@ def _init_empty_polyhedron(self): self._normaliz_cone = None @classmethod - def _from_normaliz_cone(cls, parent, normaliz_cone, normaliz_field=None): + def _from_normaliz_cone(cls, parent, normaliz_cone, internal_base_ring=None): r""" Initializes a polyhedron from a PyNormaliz wrapper of a normaliz cone. @@ -1067,12 +983,12 @@ def _from_normaliz_cone(cls, parent, normaliz_cone, normaliz_field=None): ....: backend='normaliz') sage: PI = P.integral_hull() # indirect doctest; optional - pynormaliz """ - return cls(parent, None, None, normaliz_cone=normaliz_cone, normaliz_field=normaliz_field) + return cls(parent, None, None, normaliz_cone=normaliz_cone, internal_base_ring=internal_base_ring) @staticmethod - def _number_field_triple(normaliz_field): + def _number_field_triple(internal_base_ring): r""" - Construct the PyNormaliz triple that describes the number field ``normaliz_field``. + Construct the PyNormaliz triple that describes ``internal_base_ring``. TESTS:: @@ -1082,7 +998,7 @@ def _number_field_triple(normaliz_field): sage: Pn._number_field_triple(QuadraticField(5)) # optional - sage.rings.number_field ['a^2 - 5', 'a', '[2.236067977499789 +/- 8.06e-16]'] """ - R = normaliz_field + R = internal_base_ring if R is QQ: return None from sage.rings.real_arb import RealBallField @@ -1263,7 +1179,7 @@ def __getstate__(self): A vertex at (0, 0, 1, 0), A vertex at (0, 1, 0, 0), A vertex at (1, 0, 0, 0)), - '_normaliz_field': Rational Field, + '_internal_base_ring': Rational Field, '_pickle_equations': [(-1, 1, 1, 1, 1)], '_pickle_inequalities': [(0, 0, 0, 0, 1), (0, 0, 0, 1, 0), @@ -1330,7 +1246,7 @@ def __setstate__(self, state): sage: P = polytopes.dodecahedron(backend='normaliz') # optional - pynormaliz # optional - sage.rings.number_field sage: P1 = loads(dumps(P)) # optional - pynormaliz # optional - sage.rings.number_field - sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone, normaliz_field=P1._normaliz_field) # optional - pynormaliz # optional - sage.rings.number_field + sage: P2 = Polyhedron_normaliz(P1.parent(), None, None, P1._normaliz_cone, internal_base_ring=P1._internal_base_ring) # optional - pynormaliz # optional - sage.rings.number_field sage: P == P2 # optional - pynormaliz # optional - sage.rings.number_field True @@ -1537,7 +1453,7 @@ def _volume_normaliz(self, measure='euclidean'): if measure == 'euclidean': return self._nmz_result(cone, 'EuclideanVolume') elif measure == 'induced_lattice': - if self._normaliz_field in (ZZ, QQ): + if self._internal_base_ring in (ZZ, QQ): return self._nmz_result(cone, 'Volume') else: return self._nmz_result(cone, 'RenfVolume') @@ -2286,8 +2202,9 @@ class functions. sage: S = polytopes.simplex(3, backend = 'normaliz'); S # optional - pynormaliz A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices - sage: G = S.restricted_automorphism_group(output = 'permutation'); G # optional - pynormaliz - Permutation Group with generators [(2,3), (1,2), (0,1)] + sage: G = S.restricted_automorphism_group(output = 'permutation'); # optional - pynormaliz + sage: G.is_isomorphic(SymmetricGroup(4)) # optional - pynormaliz + True sage: len(G) # optional - pynormaliz 24 sage: Hstar = S._Hstar_function_normaliz(G); Hstar # optional - pynormaliz @@ -2307,10 +2224,9 @@ class functions. sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz sage: K = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: G = K.subgroup(gens = [K[6]]); G # optional - pynormaliz - Subgroup generated by [(0,2)(1,3)(4,6)(5,7)] of (Permutation Group with generators [(2,4)(3,5), (1,2)(5,6), (0,1)(2,3)(4,5)(6,7), (0,7)(1,3)(2,5)(4,6)]) + sage: G = K.subgroup(gens = [K([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz sage: conj_reps = G.conjugacy_classes_representatives() # optional - pynormaliz - sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz + sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz sage: list(Dict.keys())[0] # optional - pynormaliz (0,2)(1,3)(4,6)(5,7) sage: list(Dict.values())[0] # optional - pynormaliz @@ -2517,13 +2433,15 @@ class functions of the acting group. A character `\rho` is effective if The `H^*` series of the two-dimensional permutahedron under the action of the symmetric group is effective:: - sage: p2 = polytopes.permutahedron(3, backend = 'normaliz') # optional - pynormaliz - sage: G = p2.restricted_automorphism_group(output='permutation') # optional - pynormaliz - sage: H = G.subgroup(gens=[G.gens()[1],G.gens()[2]]) # optional - pynormaliz - sage: H.order() # optional - pynormaliz - 6 - sage: [Hstar, Hlin] = [p2.Hstar_function(H), p2.Hstar_function(H, output = 'Hstar_as_lin_comb')] # optional - pynormaliz - sage: p2._is_effective_normaliz(Hstar,Hlin) # optional - pynormaliz + sage: p3 = polytopes.permutahedron(3, backend = 'normaliz') # optional - pynormaliz + sage: G = p3.restricted_automorphism_group(output='permutation') # optional - pynormaliz + sage: reflection12 = G([(0,2),(1,4),(3,5)]) # optional - pynormaliz + sage: reflection23 = G([(0,1),(2,3),(4,5)]) # optional - pynormaliz + sage: S3 = G.subgroup(gens=[reflection12, reflection23]) # optional - pynormaliz + sage: S3.is_isomorphic(SymmetricGroup(3)) # optional - pynormaliz + True + sage: [Hstar, Hlin] = [p3.Hstar_function(S3), p3.Hstar_function(S3, output = 'Hstar_as_lin_comb')] # optional - pynormaliz + sage: p3._is_effective_normaliz(Hstar,Hlin) # optional - pynormaliz True If the `H^*`-series is not polynomial, then it is not effective:: @@ -2531,7 +2449,7 @@ class functions of the acting group. A character `\rho` is effective if sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz sage: G = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: H = G.subgroup(gens = [G[6]]) # optional - pynormaliz + sage: H = G.subgroup(gens = [G([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz sage: Hstar = P.Hstar_function(H); Hstar # optional - pynormaliz (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) sage: Hstar_lin = P.Hstar_function(H, output = 'Hstar_as_lin_comb') # optional - pynormaliz diff --git a/src/sage/geometry/polyhedron/backend_number_field.py b/src/sage/geometry/polyhedron/backend_number_field.py new file mode 100644 index 00000000000..437550de3aa --- /dev/null +++ b/src/sage/geometry/polyhedron/backend_number_field.py @@ -0,0 +1,166 @@ +r""" +The Python backend, using number fields internally +""" + +# **************************************************************************** +# Copyright (C) 2016-2022 Matthias Köppe +# 2016-2018 Travis Scrimshaw +# 2017 Jeroen Demeyer +# 2018-2020 Jean-Philippe Labbé +# 2019 Vincent Delecroix +# 2019-2021 Jonathan Kliem +# 2019-2021 Sophia Elia +# 2020 Frédéric Chapoton +# 2022 Yuan Zhou +# +# 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 .backend_field import Polyhedron_field +from .base_number_field import Polyhedron_base_number_field + + +class Polyhedron_number_field(Polyhedron_field, Polyhedron_base_number_field): + r""" + Polyhedra whose data can be converted to number field elements + + All computations are done internally using a fixed real embedded number field, + which is determined automatically. + + INPUT: + + - ``Vrep`` -- a list ``[vertices, rays, lines]`` or ``None``. + + - ``Hrep`` -- a list ``[ieqs, eqns]`` or ``None``. + + EXAMPLES:: + + sage: P = Polyhedron(vertices=[[1], [sqrt(2)]], backend='number_field') # optional - sage.rings.number_field + sage: P # optional - sage.rings.number_field + A 1-dimensional polyhedron + in (Symbolic Ring)^1 defined as the convex hull of 2 vertices + sage: P.vertices() # optional - sage.rings.number_field + (A vertex at (1), A vertex at (sqrt(2))) + + sage: P = polytopes.icosahedron(exact=True, backend='number_field') # optional - sage.rings.number_field + sage: P # 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 12 vertices + + sage: x = polygen(ZZ); P = Polyhedron( # optional - sage.rings.number_field + ....: vertices=[[sqrt(2)], [AA.polynomial_root(x^3-2, RIF(0,3))]], + ....: backend='number_field') + sage: P # optional - sage.rings.number_field + A 1-dimensional polyhedron + in (Symbolic Ring)^1 defined as the convex hull of 2 vertices + sage: P.vertices() # optional - sage.rings.number_field + (A vertex at (sqrt(2)), A vertex at (2^(1/3))) + + TESTS: + + Tests from :class:`~sage.geometry.polyhedron.backend_field.Polyhedron_field` -- + here the data are already either in a number field or in ``AA``:: + + sage: p = Polyhedron(vertices=[(0,0),(AA(2).sqrt(),0),(0,AA(3).sqrt())], # optional - sage.rings.number_field + ....: rays=[(1,1)], lines=[], backend='number_field', base_ring=AA) + sage: TestSuite(p).run() # optional - sage.rings.number_field + + sage: K. = QuadraticField(3) # optional - sage.rings.number_field + sage: p = Polyhedron([(0,0), (1,0), (1/2, sqrt3/2)], backend='number_field') # optional - sage.rings.number_field + sage: TestSuite(p).run() # optional - sage.rings.number_field + + sage: K. = NumberField(x^2-x-1, embedding=1.618) # optional - sage.rings.number_field + sage: P1 = Polyhedron([[0,1], [1,1], [1,-phi+1]], backend='number_field') # optional - sage.rings.number_field + sage: P2 = Polyhedron(ieqs=[[-1,-phi,0]], backend='number_field') # optional - sage.rings.number_field + sage: P1.intersection(P2) # optional - sage.rings.number_field + The empty polyhedron + in (Number Field in phi with defining polynomial x^2 - x - 1 + with phi = 1.618033988749895?)^2 + + sage: Polyhedron(lines=[[1]], backend='number_field') + A 1-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex and 1 line + """ + + def _init_from_Vrepresentation(self, vertices, rays, lines, + minimize=True, verbose=False): + """ + Construct polyhedron from V-representation data. + + INPUT: + + - ``vertices`` -- list of points. 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. + + - ``verbose`` -- boolean (default: ``False``). Whether to print + verbose output for debugging purposes. + + EXAMPLES:: + + sage: p = Polyhedron(ambient_dim=2, backend='number_field') + sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field + sage: Polyhedron_number_field._init_from_Vrepresentation(p, [(0,0)], [], []) + + TESTS: + + Check that the coordinates of a vertex get simplified in the Symbolic Ring:: + + sage: p = Polyhedron(ambient_dim=2, base_ring=SR, backend='number_field') + sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field + sage: Polyhedron_number_field._init_from_Vrepresentation(p, [(0,1/2),(sqrt(2),0),(4,5/6)], [], []); p + A 2-dimensional polyhedron in (Symbolic Ring)^2 defined as the convex hull of 3 vertices + sage: p.vertices()[0][0] + 0 + """ + (vertices, rays, lines), internal_base_ring \ + = self._compute_data_lists_and_internal_base_ring((vertices, rays, lines), + lambda *x: x, lambda *x: x) + self._internal_base_ring = internal_base_ring + super()._init_from_Vrepresentation(vertices, rays, lines, + minimize=minimize, verbose=verbose, + internal_base_ring=internal_base_ring) + + def _init_from_Hrepresentation(self, ieqs, eqns, minimize=True, verbose=False): + """ + 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. + + - ``verbose`` -- boolean (default: ``False``). Whether to print + verbose output for debugging purposes. + + TESTS:: + + sage: p = Polyhedron(ambient_dim=2, backend='number_field') + sage: from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field + sage: Polyhedron_number_field._init_from_Hrepresentation(p, [(1, 2, 3)], []) + """ + (ieqs, eqns), internal_base_ring \ + = self._compute_data_lists_and_internal_base_ring((ieqs, eqns), + lambda *x: x, lambda *x: x) + self._internal_base_ring = internal_base_ring + super()._init_from_Hrepresentation(ieqs, eqns, + minimize=minimize, verbose=verbose, + internal_base_ring=internal_base_ring) diff --git a/src/sage/geometry/polyhedron/base.py b/src/sage/geometry/polyhedron/base.py index dbf8b4370b0..77a11c53d21 100644 --- a/src/sage/geometry/polyhedron/base.py +++ b/src/sage/geometry/polyhedron/base.py @@ -974,11 +974,12 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona sage: aut_square = square.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz sage: conj_reps = aut_square.conjugacy_classes_representatives() # optional - pynormaliz sage: gens_dict = square.permutations_to_matrices(conj_reps); # optional - pynormaliz - sage: conj_reps[1],gens_dict[conj_reps[1]] # optional - pynormaliz + sage: rotation_180 = aut_square([(0,3),(1,2)]) # optional - pynormaliz + sage: rotation_180,gens_dict[rotation_180] # optional - pynormaliz ( - [0 1 0] - [1 0 0] - (1,2), [0 0 1] + [-1 0 0] + [ 0 -1 0] + (0,3)(1,2), [ 0 0 1] ) This example tests the functionality for additional elements:: @@ -986,8 +987,7 @@ def permutations_to_matrices(self, conj_class_reps, acting_group=None, additiona sage: C = polytopes.cross_polytope(2) sage: G = C.restricted_automorphism_group(output = 'permutation') sage: conj_reps = G.conjugacy_classes_representatives() - sage: add_elt = G[6]; add_elt - (0,2,3,1) + sage: add_elt = G([(0,2,3,1)]) sage: dict = C.permutations_to_matrices(conj_reps,additional_elts = [add_elt]) sage: dict[add_elt] [ 0 1 0] diff --git a/src/sage/geometry/polyhedron/base5.py b/src/sage/geometry/polyhedron/base5.py index f16bce682b9..7a77f9685a3 100644 --- a/src/sage/geometry/polyhedron/base5.py +++ b/src/sage/geometry/polyhedron/base5.py @@ -2440,7 +2440,7 @@ def _test_lawrence(self, tester=None, **options): if self.backend() == 'normaliz' and not self.base_ring() in (ZZ, QQ): # Speeds up the doctest for significantly. - self = self.change_ring(self._normaliz_field) + self = self.change_ring(self._internal_base_ring) if not self.is_compact(): with tester.assertRaises(NotImplementedError): diff --git a/src/sage/geometry/polyhedron/base_QQ.py b/src/sage/geometry/polyhedron/base_QQ.py index 95c4f4e2b1a..0efcb15f1a2 100644 --- a/src/sage/geometry/polyhedron/base_QQ.py +++ b/src/sage/geometry/polyhedron/base_QQ.py @@ -846,13 +846,9 @@ def fixed_subpolytope(self, vertex_permutation): You can obtain non-trivial examples:: - sage: fsp1 = Cube.fixed_subpolytope(reprs[8]);fsp1 # optional - pynormaliz - A 0-dimensional polyhedron in QQ^3 defined as the convex hull of 1 vertex - sage: fsp1.vertices() # optional - pynormaliz - (A vertex at (0, 0, 0),) - sage: fsp2 = Cube.fixed_subpolytope(reprs[3]);fsp2 # optional - pynormaliz + sage: fsp = Cube.fixed_subpolytope(AG([(0,1),(2,3),(4,5),(6,7)]));fsp # optional - pynormaliz A 2-dimensional polyhedron in QQ^3 defined as the convex hull of 4 vertices - sage: fsp2.vertices() # optional - pynormaliz + sage: fsp.vertices() # optional - pynormaliz (A vertex at (-1, -1, 0), A vertex at (-1, 1, 0), A vertex at (1, -1, 0), @@ -860,22 +856,17 @@ def fixed_subpolytope(self, vertex_permutation): The next example shows that fixed_subpolytope works for rational polytopes:: - sage: P = Polyhedron(vertices = [[0,0],[3/2,0],[3/2,3/2],[0,3/2]], backend ='normaliz') # optional - pynormaliz - sage: P.vertices() # optional - pynormaliz - (A vertex at (0, 0), - A vertex at (0, 3/2), - A vertex at (3/2, 0), - A vertex at (3/2, 3/2)) - sage: G = P.restricted_automorphism_group(output = 'permutation');G # optional - pynormaliz - Permutation Group with generators [(1,2), (0,1)(2,3), (0,3)] - sage: len(G) # optional - pynormaliz - 8 - sage: G[2] # optional - pynormaliz - (0,1)(2,3) - sage: fixed_set = P.fixed_subpolytope(G[2]); fixed_set # optional - pynormaliz - A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices - sage: fixed_set.vertices() # optional - pynormaliz - (A vertex at (0, 3/4), A vertex at (3/2, 3/4)) + sage: P = Polyhedron(vertices=[[0],[1/2]], backend='normaliz') # optional - pynormaliz + sage: P.vertices() # optional - pynormaliz + (A vertex at (0), A vertex at (1/2)) + sage: G = P.restricted_automorphism_group(output='permutation');G # optional - pynormaliz + Permutation Group with generators [(0,1)] + sage: len(G) # optional - pynormaliz + 2 + sage: fixed_set = P.fixed_subpolytope(G.gens()[0]); fixed_set # optional - pynormaliz + A 0-dimensional polyhedron in QQ^1 defined as the convex hull of 1 vertex + sage: fixed_set.vertices_list() # optional - pynormaliz + [[1/4]] """ if self.is_empty(): raise NotImplementedError('empty polyhedra are not supported') @@ -943,14 +934,10 @@ def fixed_subpolytopes(self, conj_class_reps): sage: aut_p = p.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz sage: aut_p.order() # optional - pynormaliz 8 - sage: conj_list = aut_p.conjugacy_classes_representatives(); conj_list # optional - pynormaliz - [(), (1,2), (0,1)(2,3), (0,1,3,2), (0,3)(1,2)] - sage: p.fixed_subpolytopes(conj_list) # optional - pynormaliz - {(): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices, - (1,2): A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices, - (0,1)(2,3): A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices, - (0,1,3,2): A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex, - (0,3)(1,2): A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex} + sage: conj_list = aut_p.conjugacy_classes_representatives(); # optional - pynormaliz + sage: fixedpolytopes_dictionary = p.fixed_subpolytopes(conj_list) # optional - pynormaliz + sage: fixedpolytopes_dictionary[aut_p([(0,3),(1,2)])] # optional - pynormaliz + A 0-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex TESTS:: @@ -1025,10 +1012,9 @@ class functions. sage: S = polytopes.simplex(3, backend = 'normaliz'); S # optional - pynormaliz A 3-dimensional polyhedron in ZZ^4 defined as the convex hull of 4 vertices - sage: G = S.restricted_automorphism_group(output = 'permutation'); G # optional - pynormaliz - Permutation Group with generators [(2,3), (1,2), (0,1)] - sage: len(G) # optional - pynormaliz - 24 + sage: G = S.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz + sage: G.is_isomorphic(SymmetricGroup(4)) # optional - pynormaliz + True sage: Hstar = S._Hstar_function_normaliz(G); Hstar # optional - pynormaliz chi_4 sage: G.character_table() # optional - pynormaliz @@ -1046,10 +1032,9 @@ class functions. sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz sage: K = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: G = K.subgroup(gens = [K[6]]); G # optional - pynormaliz - Subgroup generated by [(0,2)(1,3)(4,6)(5,7)] of (Permutation Group with generators [(2,4)(3,5), (1,2)(5,6), (0,1)(2,3)(4,5)(6,7), (0,7)(1,3)(2,5)(4,6)]) + sage: G = K.subgroup(gens = [K([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz sage: conj_reps = G.conjugacy_classes_representatives() # optional - pynormaliz - sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz + sage: Dict = P.permutations_to_matrices(conj_reps, acting_group = G) # optional - pynormaliz sage: list(Dict.keys())[0] # optional - pynormaliz (0,2)(1,3)(4,6)(5,7) sage: list(Dict.values())[0] # optional - pynormaliz @@ -1166,13 +1151,15 @@ class functions of the acting group. A character `\rho` is effective if The `H^*` series of the two-dimensional permutahedron under the action of the symmetric group is effective:: - sage: p2 = polytopes.permutahedron(3, backend = 'normaliz') # optional - pynormaliz - sage: G = p2.restricted_automorphism_group(output='permutation') # optional - pynormaliz - sage: H = G.subgroup(gens=[G.gens()[1],G.gens()[2]]) # optional - pynormaliz - sage: H.order() # optional - pynormaliz - 6 - sage: [Hstar, Hlin] = [p2.Hstar_function(H), p2.Hstar_function(H, output = 'Hstar_as_lin_comb')] # optional - pynormaliz - sage: p2.is_effective(Hstar,Hlin) # optional - pynormaliz + sage: p3 = polytopes.permutahedron(3, backend = 'normaliz') # optional - pynormaliz + sage: G = p3.restricted_automorphism_group(output='permutation') # optional - pynormaliz + sage: reflection12 = G([(0,2),(1,4),(3,5)]) # optional - pynormaliz + sage: reflection23 = G([(0,1),(2,3),(4,5)]) # optional - pynormaliz + sage: S3 = G.subgroup(gens=[reflection12, reflection23]) # optional - pynormaliz + sage: S3.is_isomorphic(SymmetricGroup(3)) # optional - pynormaliz + True + sage: [Hstar, Hlin] = [p3.Hstar_function(S3), p3.Hstar_function(S3, output = 'Hstar_as_lin_comb')] # optional - pynormaliz + sage: p3.is_effective(Hstar,Hlin) # optional - pynormaliz True If the `H^*`-series is not polynomial, then it is not effective:: @@ -1180,7 +1167,7 @@ class functions of the acting group. A character `\rho` is effective if sage: P = Polyhedron(vertices=[[0,0,1],[0,0,-1],[1,0,1],[-1,0,-1],[0,1,1], # optional - pynormaliz ....: [0,-1,-1],[1,1,1],[-1,-1,-1]],backend='normaliz') # optional - pynormaliz sage: G = P.restricted_automorphism_group(output = 'permutation') # optional - pynormaliz - sage: H = G.subgroup(gens = [G[6]]) # optional - pynormaliz + sage: H = G.subgroup(gens = [G([(0,2),(1,3),(4,6),(5,7)])]) # optional - pynormaliz sage: Hstar = P.Hstar_function(H); Hstar # optional - pynormaliz (chi_0*t^4 + (3*chi_0 + 3*chi_1)*t^3 + (8*chi_0 + 2*chi_1)*t^2 + (3*chi_0 + 3*chi_1)*t + chi_0)/(t + 1) sage: Hstar_lin = P.Hstar_function(H, output = 'Hstar_as_lin_comb') # optional - pynormaliz diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py new file mode 100644 index 00000000000..08040db3794 --- /dev/null +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -0,0 +1,118 @@ +r""" +Support for internal use of number fields in backends for polyhedral computations +""" + +# **************************************************************************** +# Copyright (C) 2016-2022 Matthias Köppe +# 2016-2018 Travis Scrimshaw +# 2017 Jeroen Demeyer +# 2018-2020 Jean-Philippe Labbé +# 2019 Vincent Delecroix +# 2019-2021 Jonathan Kliem +# 2019-2021 Sophia Elia +# 2020 Frédéric Chapoton +# 2022 Yuan Zhou +# +# 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.rings.integer_ring import ZZ +from sage.rings.rational_field import QQ + +from .base import Polyhedron_base + + +def _number_field_elements_from_algebraics_list_of_lists_of_lists(listss, **kwds): + r""" + Like `number_field_elements_from_algebraics`, but for a list of lists of lists. + + EXAMPLES:: + + sage: rt2 = AA(sqrt(2)); rt2 # optional - sage.rings.number_field + 1.414213562373095? + sage: rt3 = AA(sqrt(3)); rt3 # optional - sage.rings.number_field + 1.732050807568878? + sage: from sage.geometry.polyhedron.base_number_field import _number_field_elements_from_algebraics_list_of_lists_of_lists + sage: K, results, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists([[[rt2], [1]], [[rt3]], [[1], []]]); results # optional - sage.rings.number_field + [[[-a^3 + 3*a], [1]], [[-a^2 + 2]], [[1], []]] + """ + from sage.rings.qqbar import number_field_elements_from_algebraics + numbers = [] + for lists in listss: + for list in lists: + numbers.extend(list) + K, K_numbers, hom = number_field_elements_from_algebraics(numbers, **kwds) + g = iter(K_numbers) + return K, [ [ [ next(g) for _ in list ] for list in lists ] for lists in listss ], hom + + +class Polyhedron_base_number_field(Polyhedron_base): + + def _compute_data_lists_and_internal_base_ring(self, data_lists, convert_QQ, convert_NF): + r""" + Compute data lists in Normaliz or ``number_field`` backend format and the internal base ring of the data. + + EXAMPLES:: + + sage: p = Polyhedron(vertices=[(0,1/2),(2,0),(4,5/6)], # optional - pynormaliz + ....: base_ring=AA, backend='normaliz') + sage: def convert_QQ(ieqs, eqs): # optional - pynormaliz + ....: return [ [ 1000*x for x in ieq ] for ieq in ieqs], \ + ....: [ [ 1000*x for x in eq ] for eq in eqs] + sage: def convert_NF(ieqs, eqs): # optional - pynormaliz + ....: return ieqs, eqs + sage: p._compute_data_lists_and_internal_base_ring([[[1]], [[1/2]]], # optional - pynormaliz + ....: convert_QQ, convert_NF) + (([[1000]], [[500]]), Rational Field) + sage: p._compute_data_lists_and_internal_base_ring([[[AA(1)]], [[1/2]]], # optional - pynormaliz + ....: convert_QQ, convert_NF) + (([[1000]], [[500]]), Rational Field) + sage: p._compute_data_lists_and_internal_base_ring([[[AA(sqrt(2))]], [[1/2]]], # optional - pynormaliz # optional - sage.rings.number_field + ....: convert_QQ, convert_NF) + ([[[a]], [[1/2]]], + Number Field in a with defining polynomial y^2 - 2 with a = 1.414213562373095?) + + TESTS:: + + sage: K. = QuadraticField(-5) # optional - sage.rings.number_field + sage: p = Polyhedron(vertices=[(a,1/2),(2,0),(4,5/6)], # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field + ....: base_ring=K, backend='normaliz') + Traceback (most recent call last): + ... + ValueError: invalid base ring: Number Field in a ... is not real embedded + + Checks that :trac:`30248` is fixed:: + + sage: q = Polyhedron(backend='normaliz', base_ring=AA, # indirect doctest # optional - pynormaliz # optional - sage.rings.number_field + ....: rays=[(0, 0, 1), (0, 1, -1), (1, 0, -1)]); q + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays + sage: -q # optional - pynormaliz # optional - sage.rings.number_field + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 1 vertex and 3 rays + """ + from sage.categories.number_fields import NumberFields + from sage.rings.real_double import RDF + + if self.base_ring() in (QQ, ZZ): + internal_base_ring = QQ + internal_data_lists = convert_QQ(*data_lists) + else: + # Allows to re-iterate if K is QQ below when data_lists contain + # iterators: + data_lists = [tuple(_) for _ in data_lists] + internal_data_lists = convert_NF(*data_lists) + if self.base_ring() in NumberFields(): + if not RDF.has_coerce_map_from(self.base_ring()): + raise ValueError("invalid base ring: {} is a number field that is not real embedded".format(self.base_ring())) + internal_base_ring = self.base_ring() + else: + K, internal_data_lists, hom = _number_field_elements_from_algebraics_list_of_lists_of_lists(internal_data_lists, embedded=True) + internal_base_ring = K + if K is QQ: + # Compute it with Normaliz, not QNormaliz + internal_data_lists = convert_QQ(*[ [ [ QQ(x) for x in v ] for v in l] + for l in data_lists ]) + return internal_data_lists, internal_base_ring diff --git a/src/sage/geometry/polyhedron/face.py b/src/sage/geometry/polyhedron/face.py index d9dd5a6c4d6..421228813a9 100644 --- a/src/sage/geometry/polyhedron/face.py +++ b/src/sage/geometry/polyhedron/face.py @@ -1066,7 +1066,7 @@ def combinatorial_face_to_polyhedral_face(polyhedron, combinatorial_face): # Equations before inequalities in Hrep. H_indices = tuple(range(n_equations)) H_indices += tuple(x+n_equations for x in combinatorial_face.ambient_H_indices(add_equations=False)) - elif polyhedron.backend() in ('normaliz', 'cdd', 'field', 'polymake'): + elif polyhedron.backend() in ('normaliz', 'cdd', 'field', 'number_field', 'polymake'): # Equations after the inequalities in Hrep. n_ieqs = polyhedron.n_inequalities() H_indices = tuple(x for x in combinatorial_face.ambient_H_indices(add_equations=False)) diff --git a/src/sage/geometry/polyhedron/library.py b/src/sage/geometry/polyhedron/library.py index b71e1e29d2b..880eb4ee008 100644 --- a/src/sage/geometry/polyhedron/library.py +++ b/src/sage/geometry/polyhedron/library.py @@ -2575,7 +2575,6 @@ def tri(m): return parent([verts, [], []], [ieqs, eqns], Vrep_minimal=True, Hrep_minimal=True, pref_rep="Hrep") - def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regular=False, backend=None): r""" Return the generalized permutahedron of type ``coxeter_type`` as the @@ -2638,38 +2637,19 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula A vertex at (1, 0), A vertex at (1, 1)) - Setting ``regular=True`` applies a linear transformation to get - isometric vertex figures and the result is inscribed. Even though there - are traces of small numbers, the internal computations are done using - an exact embedded NumberField:: + It works also with Coxeter types that lead to non-rational coordinates:: - sage: perm_a2_reg = polytopes.generalized_permutahedron(['A',2],regular=True) - sage: V = sorted(perm_a2_reg.vertices()); V # random - [A vertex at (-1, 0), - A vertex at (-1/2, -0.866025403784439?), - A vertex at (-1/2, 0.866025403784439?), - A vertex at (1/2, -0.866025403784439?), - A vertex at (1/2, 0.866025403784439?), - A vertex at (1.000000000000000?, 0.?e-18)] - sage: for v in V: - ....: for x in v: - ....: x.exactify() - sage: V - [A vertex at (-1, 0), - A vertex at (-1/2, -0.866025403784439?), - A vertex at (-1/2, 0.866025403784439?), - A vertex at (1/2, -0.866025403784439?), - A vertex at (1/2, 0.866025403784439?), - A vertex at (1, 0)] - sage: perm_a2_reg.is_inscribed() - True - sage: perm_a3_reg = polytopes.generalized_permutahedron(['A',3],regular=True) # long time - sage: perm_a3_reg.is_inscribed() # long time - True + sage: perm_b3 = polytopes.generalized_permutahedron(['B',3]); perm_b3 # long time # optional - sage.rings.number_field + A 3-dimensional polyhedron + in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^3 + defined as the convex hull of 48 vertices - The same is possible with vertices in ``RDF``:: + Setting ``regular=True`` applies a linear transformation to get + isometric vertex figures and the result is inscribed. This cannot be done using + rational coordinates. We first do the computations using floating point + approximations (``RDF``):: - sage: perm_a2_inexact = polytopes.generalized_permutahedron(['A',2],exact=False) + sage: perm_a2_inexact = polytopes.generalized_permutahedron(['A',2], exact=False) sage: sorted(perm_a2_inexact.vertices()) [A vertex at (-1.0, -1.0), A vertex at (-1.0, 0.0), @@ -2678,7 +2658,7 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula A vertex at (1.0, 0.0), A vertex at (1.0, 1.0)] - sage: perm_a2_inexact_reg = polytopes.generalized_permutahedron(['A',2],exact=False,regular=True) + sage: perm_a2_inexact_reg = polytopes.generalized_permutahedron(['A',2], exact=False, regular=True) sage: sorted(perm_a2_inexact_reg.vertices()) [A vertex at (-1.0, 0.0), A vertex at (-0.5, -0.8660254038), @@ -2687,29 +2667,77 @@ def generalized_permutahedron(self, coxeter_type, point=None, exact=True, regula A vertex at (0.5, 0.8660254038), A vertex at (1.0, 0.0)] - It works also with types with non-rational coordinates:: + We can do the same computation using exact arithmetic with the field ``AA``:: + + sage: perm_a2_reg = polytopes.generalized_permutahedron(['A',2], regular=True) # optional - sage.rings.number_field + sage: V = sorted(perm_a2_reg.vertices()); V # random # optional - sage.rings.number_field + [A vertex at (-1, 0), + A vertex at (-1/2, -0.866025403784439?), + A vertex at (-1/2, 0.866025403784439?), + A vertex at (1/2, -0.866025403784439?), + A vertex at (1/2, 0.866025403784439?), + A vertex at (1.000000000000000?, 0.?e-18)] + + Even though the numbers look like floating point approximations, the computation is + actually exact. We can clean up the display a bit using ``exactify``:: - sage: perm_b3 = polytopes.generalized_permutahedron(['B',3]); perm_b3 # long time - A 3-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^3 defined as the convex hull of 48 vertices + sage: for v in V: # optional - sage.rings.number_field + ....: for x in v: + ....: x.exactify() + sage: V # optional - sage.rings.number_field + [A vertex at (-1, 0), + A vertex at (-1/2, -0.866025403784439?), + A vertex at (-1/2, 0.866025403784439?), + A vertex at (1/2, -0.866025403784439?), + A vertex at (1/2, 0.866025403784439?), + A vertex at (1, 0)] + sage: perm_a2_reg.is_inscribed() # optional - sage.rings.number_field + True + + Larger examples take longer:: - sage: perm_b3_reg = polytopes.generalized_permutahedron(['B',3],regular=True); perm_b3_reg # not tested - long time (12sec on 64 bits). + sage: perm_a3_reg = polytopes.generalized_permutahedron(['A',3], regular=True); perm_a3_reg # long time # optional - sage.rings.number_field + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices + sage: perm_a3_reg.is_inscribed() # long time # optional - sage.rings.number_field + True + sage: perm_b3_reg = polytopes.generalized_permutahedron(['B',3], regular=True); perm_b3_reg # not tested - long time (12sec on 64 bits). A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices - It is faster with the backend ``'normaliz'``:: + It is faster with the backend ``'number_field'``, which internally uses an embedded + number field instead of doing the computations directly with the base ring (``AA``):: - sage: perm_b3_reg_norm = polytopes.generalized_permutahedron(['B',3],regular=True,backend='normaliz') # optional - pynormaliz - sage: perm_b3_reg_norm # optional - pynormaliz + sage: perm_a3_reg_nf = polytopes.generalized_permutahedron( # optional - sage.rings.number_field + ....: ['A',3], regular=True, backend='number_field'); perm_a3_reg_nf + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices + sage: perm_a3_reg_nf.is_inscribed() # optional - sage.rings.number_field + True + sage: perm_b3_reg_nf = polytopes.generalized_permutahedron( # long time # optional - sage.rings.number_field + ....: ['B',3], regular=True, backend='number_field'); perm_b3_reg_nf A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices - The backend ``'normaliz'`` allows further faster computation in the - non-rational case:: + It is even faster with the backend ``'normaliz'``:: + + sage: perm_a3_reg_norm = polytopes.generalized_permutahedron( # optional - pynormaliz + ....: ['A',3], regular=True, backend='normaliz'); perm_a3_reg_norm + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 24 vertices + sage: perm_a3_reg_norm.is_inscribed() # optional - pynormaliz + True + sage: perm_b3_reg_norm = polytopes.generalized_permutahedron( # optional - pynormaliz + ....: ['B',3], regular=True, backend='normaliz'); perm_b3_reg_norm + A 3-dimensional polyhedron in AA^3 defined as the convex hull of 48 vertices - sage: perm_h3 = polytopes.generalized_permutahedron(['H',3],backend='normaliz') # optional - pynormaliz - sage: perm_h3 # optional - pynormaliz - A 3-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^3 defined as the convex hull of 120 vertices - sage: perm_f4 = polytopes.generalized_permutahedron(['F',4],backend='normaliz') # optional - pynormaliz, long time - sage: perm_f4 # optional - pynormaliz, long time - A 4-dimensional polyhedron in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^4 defined as the convex hull of 1152 vertices + The speedups from using backend ``'normaliz'`` allow us to go even further:: + + sage: perm_h3 = polytopes.generalized_permutahedron(['H',3], backend='normaliz') # optional - pynormaliz + sage: perm_h3 # optional - pynormaliz + A 3-dimensional polyhedron + in (Number Field in a with defining polynomial x^2 - 5 with a = 2.236067977499790?)^3 + defined as the convex hull of 120 vertices + sage: perm_f4 = polytopes.generalized_permutahedron(['F',4], backend='normaliz') # long time # optional - pynormaliz + sage: perm_f4 # long time # optional - pynormaliz + A 4-dimensional polyhedron + in (Number Field in a with defining polynomial x^2 - 2 with a = 1.414213562373095?)^4 + defined as the convex hull of 1152 vertices .. SEEALSO:: diff --git a/src/sage/geometry/polyhedron/parent.py b/src/sage/geometry/polyhedron/parent.py index ba1987b1fe2..24cf406df7e 100644 --- a/src/sage/geometry/polyhedron/parent.py +++ b/src/sage/geometry/polyhedron/parent.py @@ -121,6 +121,10 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * sage: SCR = SR.subring(no_variables=True) # optional - sage.symbolic sage: Polyhedra(SCR, 2, backend='normaliz') # optional - pynormaliz # optional - sage.symbolic Polyhedra in (Symbolic Constants Subring)^2 + + sage: Polyhedra(SCR, 2, backend='number_field') # optional - sage.symbolic + Polyhedra in (Symbolic Constants Subring)^2 + """ if ambient_space_or_base_ring is not None: if ambient_space_or_base_ring in Rings(): @@ -180,6 +184,8 @@ def Polyhedra(ambient_space_or_base_ring=None, ambient_dim=None, backend=None, * except TypeError: raise ValueError(f"the 'polymake' backend for polyhedron cannot be used with {base_field}") return Polyhedra_polymake(base_field, ambient_dim, backend) + elif backend == 'number_field': + return Polyhedra_number_field(base_ring.fraction_field(), ambient_dim, backend) elif backend == 'field': if not base_ring.is_exact(): raise ValueError("the 'field' backend for polyhedron cannot be used with non-exact fields") @@ -1158,13 +1164,14 @@ def _make_Line(self, polyhedron, data): return obj - from sage.geometry.polyhedron.backend_cdd import Polyhedron_QQ_cdd lazy_import('sage.geometry.polyhedron.backend_cdd_rdf', 'Polyhedron_RDF_cdd') from sage.geometry.polyhedron.backend_ppl import Polyhedron_ZZ_ppl, Polyhedron_QQ_ppl from sage.geometry.polyhedron.backend_normaliz import Polyhedron_normaliz, Polyhedron_ZZ_normaliz, Polyhedron_QQ_normaliz from sage.geometry.polyhedron.backend_polymake import Polyhedron_polymake from sage.geometry.polyhedron.backend_field import Polyhedron_field +from sage.geometry.polyhedron.backend_number_field import Polyhedron_number_field + class Polyhedra_ZZ_ppl(Polyhedra_base): Element = Polyhedron_ZZ_ppl @@ -1245,6 +1252,9 @@ class Polyhedra_polymake(Polyhedra_base): class Polyhedra_field(Polyhedra_base): Element = Polyhedron_field +class Polyhedra_number_field(Polyhedra_base): + Element = Polyhedron_number_field + @cached_function def does_backend_handle_base_ring(base_ring, backend): r""" diff --git a/src/sage/graphs/base/graph_backends.pyx b/src/sage/graphs/base/graph_backends.pyx index 9daf0702185..3ff36d5cee2 100644 --- a/src/sage/graphs/base/graph_backends.pyx +++ b/src/sage/graphs/base/graph_backends.pyx @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- r""" -Backends for Sage (di)graphs. +Backends for Sage (di)graphs This module implements :class:`GenericGraphBackend` (the base class for backends). diff --git a/src/sage/graphs/base/static_sparse_graph.pyx b/src/sage/graphs/base/static_sparse_graph.pyx index 23fe59aa8e3..6c4bc1b7edd 100644 --- a/src/sage/graphs/base/static_sparse_graph.pyx +++ b/src/sage/graphs/base/static_sparse_graph.pyx @@ -1,7 +1,7 @@ # cython: binding=True # distutils: language = c++ r""" -Static Sparse Graphs +Static sparse graphs What is the point ? ------------------- diff --git a/src/sage/graphs/chrompoly.pyx b/src/sage/graphs/chrompoly.pyx index d3afec0e278..441ba58643d 100644 --- a/src/sage/graphs/chrompoly.pyx +++ b/src/sage/graphs/chrompoly.pyx @@ -1,6 +1,6 @@ # cython: binding=True """ -Chromatic Polynomial +Chromatic polynomial AUTHORS: diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 93cf637b8dd..1b0f4cd9d4d 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -805,19 +805,7 @@ def RandomHolmeKim(n, m, p, seed=None): may not be all linked to a new node on the first iteration like the BA model. - EXAMPLES: - - We check that a random graph on 8 nodes with 2 random edges per node and a - probability `p = 0.5` of forming triangles contains a triangle:: - - sage: G = graphs.RandomHolmeKim(8, 2, 0.5) - sage: G.order(), G.size() - (8, 12) - sage: C3 = graphs.CycleGraph(3) - sage: G.subgraph_search(C3) - Subgraph of (): Graph on 3 vertices - - :: + EXAMPLES:: sage: G = graphs.RandomHolmeKim(12, 3, .3) sage: G.show() # long time diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 0070705f781..23e66648fb2 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -12000,7 +12000,11 @@ def set_edge_label(self, u, v, l): EXAMPLES:: - sage: SD = DiGraph({1:[18,2], 2:[5,3], 3:[4,6], 4:[7,2], 5:[4], 6:[13,12], 7:[18,8,10], 8:[6,9,10], 9:[6], 10:[11,13], 11:[12], 12:[13], 13:[17,14], 14:[16,15], 15:[2], 16:[13], 17:[15,13], 18:[13]}, sparse=True) + sage: d = {1: [18, 2], 2: [5, 3], 3: [4, 6], 4: [7, 2], 5: [4], + ....: 6: [13, 12], 7: [18, 8, 10], 8: [6, 9, 10], 9: [6], + ....: 10: [11, 13], 11: [12], 12: [13], 13: [17, 14], + ....: 14: [16, 15], 15: [2], 16: [13], 17: [15, 13], 18: [13]} + sage: SD = DiGraph(d, sparse=True) sage: SD.set_edge_label(1, 18, 'discrete') sage: SD.set_edge_label(4, 7, 'discrete') sage: SD.set_edge_label(2, 5, 'h = 0') @@ -12013,7 +12017,11 @@ def set_edge_label(self, u, v, l): sage: SD.set_edge_label(13, 14, 'k = h') sage: SD.set_edge_label(17, 15, 'v_k finite') sage: SD.set_edge_label(14, 15, 'v_k m.c.r.') - sage: posn = {1:[ 3,-3], 2:[0,2], 3:[0, 13], 4:[3,9], 5:[3,3], 6:[16, 13], 7:[6,1], 8:[6,6], 9:[6,11], 10:[9,1], 11:[10,6], 12:[13,6], 13:[16,2], 14:[10,-6], 15:[0,-10], 16:[14,-6], 17:[16,-10], 18:[6,-4]} + sage: posn = {1: [3, -3], 2: [0, 2], 3: [0, 13], 4: [3, 9], + ....: 5: [3, 3], 6: [16, 13], 7: [6, 1], 8: [6, 6], + ....: 9: [6, 11], 10: [9, 1], 11: [10, 6], 12: [13, 6], + ....: 13: [16, 2], 14: [10, -6], 15: [0, -10], 16: [14, -6], + ....: 17: [16, -10], 18: [6, -4]} sage: SD.plot(pos=posn, vertex_size=400, vertex_colors={'#FFFFFF':list(range(1,19))}, edge_labels=True).show() # long time :: @@ -12066,7 +12074,8 @@ def set_edge_label(self, u, v, l): """ if self.allows_multiple_edges(): if len(self.edge_label(u, v)) > 1: - raise RuntimeError("cannot set edge label, since there are multiple edges from %s to %s"%(u,v)) + raise RuntimeError("cannot set edge label, since there are " + "multiple edges from %s to %s" % (u, v)) self._backend.set_edge_label(u, v, l, self._directed) def has_edge(self, u, v=None, label=None): @@ -12102,7 +12111,8 @@ def has_edge(self, u, v=None, label=None): label = None return self._backend.has_edge(u, v, label) - def edges(self, vertices=None, labels=True, sort=None, key=None, ignore_direction=False, sort_vertices=True): + def edges(self, vertices=None, labels=True, sort=None, key=None, + ignore_direction=False, sort_vertices=True): r""" Return a :class:`~EdgesView` of edges. @@ -12162,20 +12172,53 @@ def edges(self, vertices=None, labels=True, sort=None, key=None, ignore_directio EXAMPLES:: sage: graphs.DodecahedralGraph().edges(sort=True) - [(0, 1, None), (0, 10, None), (0, 19, None), (1, 2, None), (1, 8, None), (2, 3, None), (2, 6, None), (3, 4, None), (3, 19, None), (4, 5, None), (4, 17, None), (5, 6, None), (5, 15, None), (6, 7, None), (7, 8, None), (7, 14, None), (8, 9, None), (9, 10, None), (9, 13, None), (10, 11, None), (11, 12, None), (11, 18, None), (12, 13, None), (12, 16, None), (13, 14, None), (14, 15, None), (15, 16, None), (16, 17, None), (17, 18, None), (18, 19, None)] + [(0, 1, None), (0, 10, None), (0, 19, None), (1, 2, None), + (1, 8, None), (2, 3, None), (2, 6, None), (3, 4, None), + (3, 19, None), (4, 5, None), (4, 17, None), (5, 6, None), + (5, 15, None), (6, 7, None), (7, 8, None), (7, 14, None), + (8, 9, None), (9, 10, None), (9, 13, None), (10, 11, None), + (11, 12, None), (11, 18, None), (12, 13, None), (12, 16, None), + (13, 14, None), (14, 15, None), (15, 16, None), (16, 17, None), + (17, 18, None), (18, 19, None)] :: sage: graphs.DodecahedralGraph().edges(sort=True, labels=False) - [(0, 1), (0, 10), (0, 19), (1, 2), (1, 8), (2, 3), (2, 6), (3, 4), (3, 19), (4, 5), (4, 17), (5, 6), (5, 15), (6, 7), (7, 8), (7, 14), (8, 9), (9, 10), (9, 13), (10, 11), (11, 12), (11, 18), (12, 13), (12, 16), (13, 14), (14, 15), (15, 16), (16, 17), (17, 18), (18, 19)] + [(0, 1), (0, 10), (0, 19), (1, 2), (1, 8), (2, 3), (2, 6), (3, 4), + (3, 19), (4, 5), (4, 17), (5, 6), (5, 15), (6, 7), (7, 8), (7, 14), + (8, 9), (9, 10), (9, 13), (10, 11), (11, 12), (11, 18), (12, 13), + (12, 16), (13, 14), (14, 15), (15, 16), (16, 17), (17, 18), + (18, 19)] :: sage: D = graphs.DodecahedralGraph().to_directed() sage: D.edges(sort=True) - [(0, 1, None), (0, 10, None), (0, 19, None), (1, 0, None), (1, 2, None), (1, 8, None), (2, 1, None), (2, 3, None), (2, 6, None), (3, 2, None), (3, 4, None), (3, 19, None), (4, 3, None), (4, 5, None), (4, 17, None), (5, 4, None), (5, 6, None), (5, 15, None), (6, 2, None), (6, 5, None), (6, 7, None), (7, 6, None), (7, 8, None), (7, 14, None), (8, 1, None), (8, 7, None), (8, 9, None), (9, 8, None), (9, 10, None), (9, 13, None), (10, 0, None), (10, 9, None), (10, 11, None), (11, 10, None), (11, 12, None), (11, 18, None), (12, 11, None), (12, 13, None), (12, 16, None), (13, 9, None), (13, 12, None), (13, 14, None), (14, 7, None), (14, 13, None), (14, 15, None), (15, 5, None), (15, 14, None), (15, 16, None), (16, 12, None), (16, 15, None), (16, 17, None), (17, 4, None), (17, 16, None), (17, 18, None), (18, 11, None), (18, 17, None), (18, 19, None), (19, 0, None), (19, 3, None), (19, 18, None)] + [(0, 1, None), (0, 10, None), (0, 19, None), (1, 0, None), + (1, 2, None), (1, 8, None), (2, 1, None), (2, 3, None), + (2, 6, None), (3, 2, None), (3, 4, None), (3, 19, None), + (4, 3, None), (4, 5, None), (4, 17, None), (5, 4, None), + (5, 6, None), (5, 15, None), (6, 2, None), (6, 5, None), + (6, 7, None), (7, 6, None), (7, 8, None), (7, 14, None), + (8, 1, None), (8, 7, None), (8, 9, None), (9, 8, None), + (9, 10, None), (9, 13, None), (10, 0, None), (10, 9, None), + (10, 11, None), (11, 10, None), (11, 12, None), (11, 18, None), + (12, 11, None), (12, 13, None), (12, 16, None), (13, 9, None), + (13, 12, None), (13, 14, None), (14, 7, None), (14, 13, None), + (14, 15, None), (15, 5, None), (15, 14, None), (15, 16, None), + (16, 12, None), (16, 15, None), (16, 17, None), (17, 4, None), + (17, 16, None), (17, 18, None), (18, 11, None), (18, 17, None), + (18, 19, None), (19, 0, None), (19, 3, None), (19, 18, None)] sage: D.edges(sort=True, labels=False) - [(0, 1), (0, 10), (0, 19), (1, 0), (1, 2), (1, 8), (2, 1), (2, 3), (2, 6), (3, 2), (3, 4), (3, 19), (4, 3), (4, 5), (4, 17), (5, 4), (5, 6), (5, 15), (6, 2), (6, 5), (6, 7), (7, 6), (7, 8), (7, 14), (8, 1), (8, 7), (8, 9), (9, 8), (9, 10), (9, 13), (10, 0), (10, 9), (10, 11), (11, 10), (11, 12), (11, 18), (12, 11), (12, 13), (12, 16), (13, 9), (13, 12), (13, 14), (14, 7), (14, 13), (14, 15), (15, 5), (15, 14), (15, 16), (16, 12), (16, 15), (16, 17), (17, 4), (17, 16), (17, 18), (18, 11), (18, 17), (18, 19), (19, 0), (19, 3), (19, 18)] + [(0, 1), (0, 10), (0, 19), (1, 0), (1, 2), (1, 8), (2, 1), (2, 3), + (2, 6), (3, 2), (3, 4), (3, 19), (4, 3), (4, 5), (4, 17), (5, 4), + (5, 6), (5, 15), (6, 2), (6, 5), (6, 7), (7, 6), (7, 8), (7, 14), + (8, 1), (8, 7), (8, 9), (9, 8), (9, 10), (9, 13), (10, 0), (10, 9), + (10, 11), (11, 10), (11, 12), (11, 18), (12, 11), (12, 13), + (12, 16), (13, 9), (13, 12), (13, 14), (14, 7), (14, 13), (14, 15), + (15, 5), (15, 14), (15, 16), (16, 12), (16, 15), (16, 17), (17, 4), + (17, 16), (17, 18), (18, 11), (18, 17), (18, 19), (19, 0), (19, 3), + (19, 18)] The default is to sort the returned list in the default fashion, as in the above examples. This can be overridden by specifying a key @@ -12263,7 +12306,7 @@ def edges(self, vertices=None, labels=True, sort=None, key=None, ignore_directio vertices = [vertices] return EdgesView(self, vertices=vertices, labels=labels, sort=sort, key=key, - ignore_direction=ignore_direction, sort_vertices=sort_vertices) + ignore_direction=ignore_direction, sort_vertices=sort_vertices) def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): r""" @@ -12322,19 +12365,19 @@ def edge_boundary(self, vertices1, vertices2=None, labels=True, sort=False): if vertices2 is not None: vertices2 = set(v for v in vertices2 if v in self) output = [e for e in self.outgoing_edge_iterator(vertices1, labels=labels) - if e[1] in vertices2] + if e[1] in vertices2] else: output = [e for e in self.outgoing_edge_iterator(vertices1, labels=labels) - if e[1] not in vertices1] + if e[1] not in vertices1] else: if vertices2 is not None: vertices2 = set(v for v in vertices2 if v in self) output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False) - if (e[0] in vertices1 and e[1] in vertices2) or - (e[1] in vertices1 and e[0] in vertices2)] + if (e[0] in vertices1 and e[1] in vertices2) or + (e[1] in vertices1 and e[0] in vertices2)] else: output = [e for e in self.edges(vertices=vertices1, labels=labels, sort=False) - if e[1] not in vertices1 or e[0] not in vertices1] + if e[1] not in vertices1 or e[0] not in vertices1] if sort: output.sort() return output @@ -12509,7 +12552,7 @@ def edge_label(self, u, v): sage: g.edge_label(2, 3) is None True """ - return self._backend.get_edge_label(u,v) + return self._backend.get_edge_label(u, v) def edge_labels(self): """ @@ -12611,7 +12654,7 @@ def remove_loops(self, vertices=None): if self.has_edge(v, v): self.delete_multiedge(v, v) - ### Modifications + # Modifications def clear(self): """ @@ -12646,7 +12689,7 @@ def clear(self): self.name('') self.delete_vertices(self.vertex_iterator()) - ### Degree functions + # Degree functions def degree(self, vertices=None, labels=False): """ @@ -12944,11 +12987,11 @@ def is_regular(self, k=None): return True - ### Substructures + # Substructures def subgraph(self, vertices=None, edges=None, inplace=False, - vertex_property=None, edge_property=None, algorithm=None, - immutable=None): + vertex_property=None, edge_property=None, algorithm=None, + immutable=None): r""" Return the subgraph containing the given vertices and edges. @@ -13227,7 +13270,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm """ G = self.__class__(weighted=self._weighted, loops=self.allows_loops(), multiedges=self.allows_multiple_edges()) - G.name("Subgraph of (%s)"%self.name()) + G.name("Subgraph of (%s)" % self.name()) if edges is None and edge_property is None: self._backend.subgraph_given_vertices(G._backend, vertices) else: @@ -13254,7 +13297,7 @@ def _subgraph_by_adding(self, vertices=None, edges=None, edge_property=None, imm else: s_vertices = set(vertices) edges_to_keep = [e for e in self.edges(vertices=vertices, sort=False, sort_vertices=False) - if e[0] in s_vertices and e[1] in s_vertices] + if e[0] in s_vertices and e[1] in s_vertices] if edge_property is not None: edges_to_keep = [e for e in edges_to_keep if edge_property(e)] @@ -13409,7 +13452,7 @@ def _subgraph_by_deleting(self, vertices=None, edges=None, inplace=False, if vertices is not None: vertices = set(vertices) G.delete_vertices([v for v in G if v not in vertices]) - G.name("Subgraph of (%s)"%self.name()) + G.name("Subgraph of (%s)" % self.name()) else: G = self._subgraph_by_adding(vertices) @@ -13849,7 +13892,7 @@ def subgraph_search_iterator(self, G, induced=False, return_graphs=True): G._scream_if_not_simple() if self.is_directed() and not G.is_directed(): raise ValueError("cannot search for a graph in a digraph") - if not self.is_directed() and G.is_directed(): + if not self.is_directed() and G.is_directed(): raise ValueError("cannot search for a digraph in a graph") DoG = self.__class__ if not G.order(): @@ -14056,7 +14099,7 @@ def is_chordal(self, certificate=False, algorithm="B"): if algorithm == "A": - peo,t_peo = self.lex_BFS(tree=True) + peo, t_peo = self.lex_BFS(tree=True) peo.reverse() # Iteratively removing vertices and checking everything is fine. @@ -14100,7 +14143,7 @@ def is_chordal(self, certificate=False, algorithm="B"): elif algorithm == "B": - peo,t_peo = self.lex_BFS(reverse=True, tree=True) + peo, t_peo = self.lex_BFS(reverse=True, tree=True) # Remembering the (closed) neighborhoods of each vertex neighbors_subsets = {v: frozenset(self.neighbors(v) + [v]) for v in g} @@ -14145,7 +14188,6 @@ def is_chordal(self, certificate=False, algorithm="B"): else: return False - # Returning values # ---------------- @@ -14161,7 +14203,6 @@ def is_chordal(self, certificate=False, algorithm="B"): return (False, hole) - # 2- The graph is chordal if certificate: return True, peo @@ -14253,9 +14294,9 @@ def is_circulant(self, certificate=False): # The automorphism group, the translation between the vertices of self # and 1..n, and the orbits. ag, orbits = self.automorphism_group([list(self)], - order=False, - return_group=True, - orbits=True) + order=False, + return_group=True, + orbits=True) # Not transitive ? Not a circulant graph ! if len(orbits) != 1: @@ -14268,8 +14309,7 @@ def is_circulant(self, certificate=False): # If the automorphism is not the identity and has exactly one # cycle that contains all vertices. - if ((not cycles) or - len(cycles[0]) != self.order()): + if not cycles or len(cycles[0]) != self.order(): continue # From now on the graph is a circulant graph ! @@ -14370,7 +14410,10 @@ def is_interval(self, certificate=False): Test certificate on a larger graph by re-doing isomorphic graph:: - sage: g = Graph(':S__@_@A_@AB_@AC_@ACD_@ACDE_ACDEF_ACDEFG_ACDEGH_ACDEGHI_ACDEGHIJ_ACDEGIJK_ACDEGIJKL_ACDEGIJKLMaCEGIJKNaCEGIJKNaCGIJKNPaCIP', loops=False, multiedges=False) + sage: s6 = ':S__@_@A_@AB_@AC_@ACD_@ACDE_ACDEF_ACDEFG_ACDEGH_ACDEGHI' + sage: s6 += '_ACDEGHIJ_ACDEGIJK_ACDEGIJKL_ACDEGIJKLMaCEGIJKNaCEGIJK' + sage: s6 += 'NaCGIJKNPaCIP' + sage: g = Graph(s6, loops=False, multiedges=False) sage: d = g.is_interval(certificate=True)[1] sage: g2 = graphs.IntervalGraph(d.values()) sage: g2.is_isomorphic(g) @@ -14633,13 +14676,15 @@ def is_clique(self, vertices=None, directed_clique=False, induced=True, loops=Fa # We check that we have edges between all pairs of vertices v_to_int = {v: i for i, v in enumerate(self)} if G.is_directed() and not directed_clique: - R = lambda u,v: (u, v) if u <= v else (v, u) + def R(u, v): + return (u, v) if u <= v else (v, u) else: - R = lambda u,v:(u,v) + def R(u, v): + return (u, v) if loops: - edges = set(R(v_to_int[u], v_to_int[v]) for u,v in G.edge_iterator(labels=False)) + edges = set(R(v_to_int[u], v_to_int[v]) for u, v in G.edge_iterator(labels=False)) else: - edges = set(R(v_to_int[u], v_to_int[v]) for u,v in G.edge_iterator(labels=False) if u != v) + edges = set(R(v_to_int[u], v_to_int[v]) for u, v in G.edge_iterator(labels=False) if u != v) # If induced == True, we already know that G.size() == M, so # we only need to check that we have the right set of edges. @@ -14872,7 +14917,7 @@ def is_subgraph(self, other, induced=True, up_to_isomorphism=False): else: return self._backend.is_subgraph(other._backend, self) - ### Cluster + # Cluster def cluster_triangles(self, nbunch=None, implementation=None): r""" @@ -14938,7 +14983,7 @@ def cluster_triangles(self, nbunch=None, implementation=None): elif implementation == 'sparse_copy': from sage.graphs.base.static_sparse_graph import triangles_count - elif implementation =="dense_copy": + elif implementation == "dense_copy": from sage.graphs.base.static_dense_graph import triangles_count else: @@ -15131,8 +15176,7 @@ def clustering_coeff(self, raise ValueError("the implementation can only be 'networkx', " "'boost', 'sparse_copy', 'dense_copy' or None") - if ((self.is_directed() or weight) and - implementation != 'networkx'): + if (self.is_directed() or weight) and implementation != 'networkx': raise ValueError("this value of 'implementation' is invalid for directed/weighted graphs") if (implementation in ['sparse_copy', 'dense_copy'] and nodes is not None): @@ -15157,7 +15201,7 @@ def coeff_from_triangle_count(v, count): from sage.graphs.base.static_sparse_graph import triangles_count return {v: coeff_from_triangle_count(v, count) for v, count in triangles_count(self).items()} - elif implementation =="dense_copy": + elif implementation == "dense_copy": from sage.graphs.base.static_dense_graph import triangles_count return {v: coeff_from_triangle_count(v, count) for v, count in triangles_count(self).items()} @@ -15180,7 +15224,7 @@ def cluster_transitivity(self): import networkx return networkx.transitivity(self.networkx_graph()) - ### Distance + # Distance def distance(self, u, v, by_weight=False, weight_function=None, check_weight=True): """ @@ -15301,7 +15345,16 @@ def distance_all_pairs(self, by_weight=False, algorithm=None, sage: g = graphs.PetersenGraph() sage: print(g.distance_all_pairs()) - {0: {0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 2, 5: 2, 6: 1, 7: 2, 8: 2, 9: 2}, 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 2, 5: 2, 6: 2, 7: 1, 8: 2, 9: 2}, 3: {0: 2, 1: 2, 2: 1, 3: 0, 4: 1, 5: 2, 6: 2, 7: 2, 8: 1, 9: 2}, 4: {0: 1, 1: 2, 2: 2, 3: 1, 4: 0, 5: 2, 6: 2, 7: 2, 8: 2, 9: 1}, 5: {0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 0, 6: 2, 7: 1, 8: 1, 9: 2}, 6: {0: 2, 1: 1, 2: 2, 3: 2, 4: 2, 5: 2, 6: 0, 7: 2, 8: 1, 9: 1}, 7: {0: 2, 1: 2, 2: 1, 3: 2, 4: 2, 5: 1, 6: 2, 7: 0, 8: 2, 9: 1}, 8: {0: 2, 1: 2, 2: 2, 3: 1, 4: 2, 5: 1, 6: 1, 7: 2, 8: 0, 9: 2}, 9: {0: 2, 1: 2, 2: 2, 3: 2, 4: 1, 5: 2, 6: 1, 7: 1, 8: 2, 9: 0}} + {0: {0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2}, + 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 2, 5: 2, 6: 1, 7: 2, 8: 2, 9: 2}, + 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 2, 5: 2, 6: 2, 7: 1, 8: 2, 9: 2}, + 3: {0: 2, 1: 2, 2: 1, 3: 0, 4: 1, 5: 2, 6: 2, 7: 2, 8: 1, 9: 2}, + 4: {0: 1, 1: 2, 2: 2, 3: 1, 4: 0, 5: 2, 6: 2, 7: 2, 8: 2, 9: 1}, + 5: {0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 0, 6: 2, 7: 1, 8: 1, 9: 2}, + 6: {0: 2, 1: 1, 2: 2, 3: 2, 4: 2, 5: 2, 6: 0, 7: 2, 8: 1, 9: 1}, + 7: {0: 2, 1: 2, 2: 1, 3: 2, 4: 2, 5: 1, 6: 2, 7: 0, 8: 2, 9: 1}, + 8: {0: 2, 1: 2, 2: 2, 3: 1, 4: 2, 5: 1, 6: 1, 7: 2, 8: 0, 9: 2}, + 9: {0: 2, 1: 2, 2: 2, 3: 2, 4: 1, 5: 2, 6: 1, 7: 1, 8: 2, 9: 0}} Testing on Random Graphs:: @@ -15634,7 +15687,7 @@ def _girth_bfs(self, odd=False, certificate=False): else: return best - ### Centrality + # Centrality def centrality_betweenness(self, k=None, normalized=True, weight=None, endpoints=False, seed=None, exact=False, @@ -15719,10 +15772,10 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, if algorithm == "NetworkX" and exact: raise ValueError("'exact' is not available with the NetworkX implementation") if (algorithm is None and - seed is None and - weight is None and - endpoints is False and - k is None): + seed is None and + weight is None and + endpoints is False and + k is None): algorithm = "Sage" elif algorithm is None: algorithm = "NetworkX" @@ -15741,7 +15794,6 @@ def centrality_betweenness(self, k=None, normalized=True, weight=None, else: raise ValueError("'algorithm' can be \"NetworkX\", \"Sage\" or None") - def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, weight_function=None, check_weight=True): r""" @@ -15832,7 +15884,12 @@ def centrality_closeness(self, vert=None, by_weight=False, algorithm=None, Standard examples:: sage: (graphs.ChvatalGraph()).centrality_closeness() - {0: 0.61111111111111..., 1: 0.61111111111111..., 2: 0.61111111111111..., 3: 0.61111111111111..., 4: 0.61111111111111..., 5: 0.61111111111111..., 6: 0.61111111111111..., 7: 0.61111111111111..., 8: 0.61111111111111..., 9: 0.61111111111111..., 10: 0.61111111111111..., 11: 0.61111111111111...} + {0: 0.61111111111111..., 1: 0.61111111111111..., + 2: 0.61111111111111..., 3: 0.61111111111111..., + 4: 0.61111111111111..., 5: 0.61111111111111..., + 6: 0.61111111111111..., 7: 0.61111111111111..., + 8: 0.61111111111111..., 9: 0.61111111111111..., + 10: 0.61111111111111..., 11: 0.61111111111111...} sage: D = DiGraph({0:[1,2,3], 1:[2], 3:[0,1]}) sage: D.show(figsize=[2,2]) sage: D.centrality_closeness(vert=[0,1]) @@ -16276,7 +16333,12 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, [] [] [] - """ # TODO- multiple edges?? + + .. TODO:: + + Add options to return a path as a list of edges with or without edge + labels. This can be useful in (di)graphs with multiple edges. + """ if not self.has_vertex(u): raise ValueError("vertex '{}' is not in the (di)graph".format(u)) if not self.has_vertex(v): @@ -16693,7 +16755,12 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, sage: D = graphs.DodecahedralGraph() sage: D.shortest_paths(0) - {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 4: [0, 19, 3, 4], 5: [0, 1, 2, 6, 5], 6: [0, 1, 2, 6], 7: [0, 1, 8, 7], 8: [0, 1, 8], 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 12: [0, 10, 11, 12], 13: [0, 10, 9, 13], 14: [0, 1, 8, 7, 14], 15: [0, 19, 18, 17, 16, 15], 16: [0, 19, 18, 17, 16], 17: [0, 19, 18, 17], 18: [0, 19, 18], 19: [0, 19]} + {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 4: [0, 19, 3, 4], + 5: [0, 1, 2, 6, 5], 6: [0, 1, 2, 6], 7: [0, 1, 8, 7], 8: [0, 1, 8], + 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 12: [0, 10, 11, 12], + 13: [0, 10, 9, 13], 14: [0, 1, 8, 7, 14], + 15: [0, 19, 18, 17, 16, 15], 16: [0, 19, 18, 17, 16], + 17: [0, 19, 18, 17], 18: [0, 19, 18], 19: [0, 19]} All these paths are obviously induced graphs:: @@ -16703,7 +16770,9 @@ def shortest_paths(self, u, by_weight=False, algorithm=None, :: sage: D.shortest_paths(0, cutoff=2) - {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 8: [0, 1, 8], 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 18: [0, 19, 18], 19: [0, 19]} + {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 8: [0, 1, 8], + 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 18: [0, 19, 18], + 19: [0, 19]} sage: G = Graph( { 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} }, sparse=True) sage: G.plot(edge_labels=True).show() # long time sage: G.shortest_paths(0, by_weight=True) @@ -16894,7 +16963,7 @@ def _path_length(self, path, by_weight=False, weight_function=None): weight_function=weight_function, check_weight=False) return sum(weight_function((u, v, self.edge_label(u, v))) - for u, v in zip(path[:-1], path[1:])) + for u, v in zip(path[:-1], path[1:])) else: return len(path) - 1 @@ -17116,17 +17185,33 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, sage: G.plot(edge_labels=True).show() # long time sage: dist, pred = G.shortest_path_all_pairs(by_weight = True) sage: dist - {0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 3}, 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, 4: {0: 2, 1: 3, 2: 3, 3: 2, 4: 0}} + {0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, + 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, + 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 3}, + 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, + 4: {0: 2, 1: 3, 2: 3, 3: 2, 4: 0}} sage: pred - {0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, 2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3}, 4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}} + {0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, + 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, + 2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, + 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3}, + 4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}} sage: pred[0] {0: None, 1: 0, 2: 1, 3: 2, 4: 0} sage: G = Graph( { 0: {1: {'weight':1}}, 1: {2: {'weight':1}}, 2: {3: {'weight':1}}, 3: {4: {'weight':2}}, 4: {0: {'weight':2}} }, sparse=True) sage: dist, pred = G.shortest_path_all_pairs(weight_function = lambda e:e[2]['weight']) sage: dist - {0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 3}, 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, 4: {0: 2, 1: 3, 2: 3, 3: 2, 4: 0}} + {0: {0: 0, 1: 1, 2: 2, 3: 3, 4: 2}, + 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 3}, + 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 3}, + 3: {0: 3, 1: 2, 2: 1, 3: 0, 4: 2}, + 4: {0: 2, 1: 3, 2: 3, 3: 2, 4: 0}} sage: pred - {0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, 2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3}, 4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}} + {0: {0: None, 1: 0, 2: 1, 3: 2, 4: 0}, + 1: {0: 1, 1: None, 2: 1, 3: 2, 4: 0}, + 2: {0: 1, 1: 2, 2: None, 3: 2, 4: 3}, + 3: {0: 1, 1: 2, 2: 3, 3: None, 4: 3}, + 4: {0: 4, 1: 0, 2: 3, 3: 4, 4: None}} So for example the shortest weighted path from `0` to `3` is obtained as follows. The predecessor of `3` is ``pred[0][3] == 2``, the predecessor @@ -17344,11 +17429,12 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, return_predecessors=True, unweighted=not by_weight) # and format the result - dist = {int_to_vertex[i]: {int_to_vertex[j]: dd[i, j] for j in range(n) if dd[i, j] != +Infinity} - for i in range(n)} + dist = {int_to_vertex[i]: {int_to_vertex[j]: dd[i, j] + for j in range(n) if dd[i, j] != +Infinity} + for i in range(n)} pred = {int_to_vertex[i]: {int_to_vertex[j]: (int_to_vertex[pp[i, j]] if i != j else None) - for j in range(n) if (i == j or pp[i, j] != -9999)} - for i in range(n)} + for j in range(n) if (i == j or pp[i, j] != -9999)} + for i in range(n)} return dist, pred elif algorithm == "Johnson_Boost": @@ -17367,9 +17453,9 @@ def shortest_path_all_pairs(self, by_weight=False, algorithm=None, dist = dict() pred = dict() for u in self: - paths=self.shortest_paths(u, by_weight=by_weight, - algorithm=algorithm, - weight_function=weight_function) + paths = self.shortest_paths(u, by_weight=by_weight, + algorithm=algorithm, + weight_function=weight_function) dist[u] = {v: self._path_length(p, by_weight=by_weight, weight_function=weight_function) for v, p in paths.items()} @@ -17605,7 +17691,7 @@ def wiener_index(self, by_weight=False, algorithm=None, G = networkx.Graph(list(self.edges(labels=False, sort=False))) G.add_nodes_from(self) total = sum(sum(networkx.single_source_dijkstra_path_length(G, u).values()) - for u in G) + for u in G) WI = total if self.is_directed() else (total / 2) else: @@ -17687,14 +17773,14 @@ def average_distance(self, by_weight=False, algorithm=None, """ if self.order() < 2: raise ValueError("average distance is not defined for empty or one-element graph") - WI = self.wiener_index(by_weight=by_weight, algorithm=algorithm, - weight_function=weight_function, check_weight=check_weight) + WI = self.wiener_index(by_weight=by_weight, algorithm=algorithm, + weight_function=weight_function, check_weight=check_weight) f = 1 if self.is_directed() else 2 if WI in ZZ: return QQ((f * WI, self.order() * (self.order() - 1))) return f * WI / (self.order() * (self.order() - 1)) - ### Searches + # Searches def breadth_first_search(self, start, ignore_direction=False, distance=None, neighbors=None, @@ -18038,7 +18124,7 @@ def depth_first_search(self, start, ignore_direction=False, if x not in seen: queue.append((w, x, d + 1)) - ### Constructors + # Constructors def add_clique(self, vertices, loops=False): """ @@ -18543,7 +18629,9 @@ def cartesian_product(self, other): sage: H = Graph([('a', 'b')]) sage: C1 = G.cartesian_product(H) sage: C1.edges(sort=True, labels=None) - [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] + [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'b'), (1, 'b')), + ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'b'), (2, 'b')), + ((2, 'a'), (2, 'b'))] sage: C2 = H.cartesian_product(G) sage: C1.is_isomorphic(C2) True @@ -18562,7 +18650,16 @@ def cartesian_product(self, other): sage: B = digraphs.DeBruijn(['a', 'b'], 2) sage: Q = P.cartesian_product(B) sage: Q.edges(sort=True, labels=None) - [((0, 'aa'), (0, 'aa')), ((0, 'aa'), (0, 'ab')), ((0, 'aa'), (1, 'aa')), ((0, 'ab'), (0, 'ba')), ((0, 'ab'), (0, 'bb')), ((0, 'ab'), (1, 'ab')), ((0, 'ba'), (0, 'aa')), ((0, 'ba'), (0, 'ab')), ((0, 'ba'), (1, 'ba')), ((0, 'bb'), (0, 'ba')), ((0, 'bb'), (0, 'bb')), ((0, 'bb'), (1, 'bb')), ((1, 'aa'), (1, 'aa')), ((1, 'aa'), (1, 'ab')), ((1, 'ab'), (1, 'ba')), ((1, 'ab'), (1, 'bb')), ((1, 'ba'), (1, 'aa')), ((1, 'ba'), (1, 'ab')), ((1, 'bb'), (1, 'ba')), ((1, 'bb'), (1, 'bb'))] + [((0, 'aa'), (0, 'aa')), ((0, 'aa'), (0, 'ab')), + ((0, 'aa'), (1, 'aa')), ((0, 'ab'), (0, 'ba')), + ((0, 'ab'), (0, 'bb')), ((0, 'ab'), (1, 'ab')), + ((0, 'ba'), (0, 'aa')), ((0, 'ba'), (0, 'ab')), + ((0, 'ba'), (1, 'ba')), ((0, 'bb'), (0, 'ba')), + ((0, 'bb'), (0, 'bb')), ((0, 'bb'), (1, 'bb')), + ((1, 'aa'), (1, 'aa')), ((1, 'aa'), (1, 'ab')), + ((1, 'ab'), (1, 'ba')), ((1, 'ab'), (1, 'bb')), + ((1, 'ba'), (1, 'aa')), ((1, 'ba'), (1, 'ab')), + ((1, 'bb'), (1, 'ba')), ((1, 'bb'), (1, 'bb'))] sage: Q.strongly_connected_components_digraph().num_verts() 2 sage: V = Q.strongly_connected_component_containing_vertex((0, 'aa')) @@ -18709,7 +18806,10 @@ def lexicographic_product(self, other): sage: H = Graph([('a', 'b')]) sage: T = G.lexicographic_product(H) sage: T.edges(sort=True, labels=None) - [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] + [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), + ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (1, 'b')), + ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), + ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] sage: T.is_isomorphic(H.lexicographic_product(G)) False @@ -18719,7 +18819,10 @@ def lexicographic_product(self, other): sage: J = DiGraph([('a', 'b')]) sage: T = I.lexicographic_product(J) sage: T.edges(sort=True, labels=None) - [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] + [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), + ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (1, 'b')), + ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), + ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] sage: T.is_isomorphic(J.lexicographic_product(I)) False """ @@ -18861,7 +18964,11 @@ def disjunctive_product(self, other): sage: H = Graph([('a', 'b')]) sage: T = G.disjunctive_product(H) sage: T.edges(sort=True, labels=None) - [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), ((0, 'a'), (2, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((0, 'b'), (2, 'a')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), ((2, 'a'), (2, 'b'))] + [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), + ((0, 'a'), (2, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), + ((0, 'b'), (2, 'a')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), + ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), + ((2, 'a'), (2, 'b'))] sage: T.is_isomorphic(H.disjunctive_product(G)) True @@ -18871,7 +18978,11 @@ def disjunctive_product(self, other): sage: J = DiGraph([('a', 'b')]) sage: T = I.disjunctive_product(J) sage: T.edges(sort=True, labels=None) - [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), ((0, 'a'), (2, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), ((1, 'a'), (0, 'b')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), ((2, 'a'), (0, 'b')), ((2, 'a'), (1, 'b')), ((2, 'a'), (2, 'b'))] + [((0, 'a'), (0, 'b')), ((0, 'a'), (1, 'a')), ((0, 'a'), (1, 'b')), + ((0, 'a'), (2, 'b')), ((0, 'b'), (1, 'a')), ((0, 'b'), (1, 'b')), + ((1, 'a'), (0, 'b')), ((1, 'a'), (1, 'b')), ((1, 'a'), (2, 'a')), + ((1, 'a'), (2, 'b')), ((1, 'b'), (2, 'a')), ((1, 'b'), (2, 'b')), + ((2, 'a'), (0, 'b')), ((2, 'a'), (1, 'b')), ((2, 'a'), (2, 'b'))] sage: T.is_isomorphic(J.disjunctive_product(I)) True """ @@ -19047,8 +19158,7 @@ def is_transitively_reduced(self): return self.is_forest() - - ### Visualization + # Visualization def _color_by_label(self, format='hex', as_function=False, default_color="black"): """ @@ -19149,7 +19259,8 @@ def _color_by_label(self, format='hex', as_function=False, default_color="black" color_of_label = dict(zip(labels, colors)) color_of_label = color_of_label.__getitem__ elif isinstance(format, dict): - color_of_label = lambda label: format.get(label, default_color) + def color_of_label(label): + return format.get(label, default_color) else: # This assumes that ``format`` is already a function color_of_label = format @@ -19218,7 +19329,6 @@ def set_latex_options(self, **kwds): opts = self.latex_options() opts.set_options(**kwds) - def layout(self, layout=None, pos=None, dim=2, save_pos=False, **options): """ Return a layout for the vertices of this graph. @@ -19341,10 +19451,10 @@ def layout(self, layout=None, pos=None, dim=2, save_pos=False, **options): if pos is None: layout = 'default' - if hasattr(self, "layout_%s"%layout): - pos = getattr(self, "layout_%s"%layout)(dim=dim, **options) + if hasattr(self, "layout_%s" % layout): + pos = getattr(self, "layout_%s" % layout)(dim=dim, **options) elif layout is not None: - raise ValueError("unknown layout algorithm: %s"%layout) + raise ValueError("unknown layout algorithm: %s" % layout) if len(pos) < self.order(): pos = self.layout_extend_randomly(pos, dim=dim) @@ -19353,7 +19463,6 @@ def layout(self, layout=None, pos=None, dim=2, save_pos=False, **options): self.set_pos(pos, dim=dim) return pos - def layout_spring(self, by_component=True, **options): """ Return a spring layout for this graph. @@ -19490,11 +19599,11 @@ def layout_extend_randomly(self, pos, dim=2): sage: (xmin, ymin) == (0, 0) and (xmax, ymax) == (1, 1) True """ - assert dim == 2 # 3d not yet implemented + assert dim == 2 # 3d not yet implemented from sage.misc.randstate import current_randstate random = current_randstate().python_random().random - xmin, xmax,ymin, ymax = self._layout_bounding_box(pos) + xmin, xmax, ymin, ymax = self._layout_bounding_box(pos) dx = xmax - xmin dy = ymax - ymin @@ -19505,7 +19614,6 @@ def layout_extend_randomly(self, pos, dim=2): pos[v] = [xmin + dx * random(), ymin + dy * random()] return pos - def layout_circular(self, dim=2, center=(0, 0), radius=1, shift=0, angle=0, **options): r""" Return a circular layout for this graph @@ -19947,9 +20055,9 @@ def _layout_bounding_box(self, pos): ys = [pos[v][1] for v in pos] if not xs: xmin = -1 - xmax = 1 + xmax = 1 ymin = -1 - ymax = 1 + ymax = 1 else: xmin = min(xs) xmax = max(xs) @@ -20047,7 +20155,7 @@ def _circle_embedding(self, vertices, center=(0, 0), radius=1, shift=0, angle=0, pos = self._pos = {} from math import sin, cos, pi - for i,v in enumerate(vertices): + for i, v in enumerate(vertices): i += shift # We round cos and sin to avoid results like 1.2246467991473532e-16 # when asking for sin(pi) @@ -20365,7 +20473,11 @@ def plot(self, **options): :: - sage: D = DiGraph( { 0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], 12: [16, 13], 13: [14], 14: [15], 15: [16], 16: [17], 17: [18], 18: [19], 19: []} , sparse=True) + sage: D = DiGraph({0: [1, 10, 19], 1: [8, 2], 2: [3, 6], 3: [19, 4], + ....: 4: [17, 5], 5: [6, 15], 6: [7], 7: [8, 14], + ....: 8: [9], 9: [10, 13], 10: [11], 11: [12, 18], + ....: 12: [16, 13], 13: [14], 14: [15], 15: [16], + ....: 16: [17], 17: [18], 18: [19]}, sparse=True) sage: for u,v,l in D.edges(sort=False): ....: D.set_edge_label(u, v, '(' + str(u) + ',' + str(v) + ')') sage: D.plot(edge_labels=True, layout='circular').show() @@ -20559,7 +20671,7 @@ def show(self, method="matplotlib", **kwds): return from sage.misc.viewer import browser import os - os.system('%s %s 2>/dev/null 1>/dev/null &'% (browser(), filename)) + os.system('%s %s 2>/dev/null 1>/dev/null &' % (browser(), filename)) return from .graph_plot import graphplot_options diff --git a/src/sage/graphs/generic_graph_pyx.pyx b/src/sage/graphs/generic_graph_pyx.pyx index a2f98dd755c..022c02c3b06 100644 --- a/src/sage/graphs/generic_graph_pyx.pyx +++ b/src/sage/graphs/generic_graph_pyx.pyx @@ -120,30 +120,6 @@ def layout_split(layout_function, G, **options): return pos -def spring_layout_fast_split(G, **options): - """ - Graph each component of ``G`` separately, placing them adjacent to each - other. - - In ticket :trac:`29522` the function was modified so that it can - work with any layout method and renamed ``layout_split``. - Please use :func:`layout_split` from now on. - - TESTS:: - - sage: from sage.graphs.generic_graph_pyx import spring_layout_fast_split - sage: G = Graph(4) - sage: _ = spring_layout_fast_split(G) - doctest:...: DeprecationWarning: spring_layout_fast_split is deprecated, please use layout_split instead - See https://trac.sagemath.org/29522 for details. - - """ - from sage.misc.superseded import deprecation - deprecation(29522, ('spring_layout_fast_split is deprecated, please use ' - 'layout_split instead'), stacklevel=3) - return layout_split(spring_layout_fast, G, **options) - - def spring_layout_fast(G, iterations=50, int dim=2, vpos=None, bint rescale=True, bint height=False, by_component=False, **options): """ diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 9b571953fed..34df7dd3c76 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -1,5 +1,5 @@ r""" -Functions for reading/building graphs/digraphs. +Functions for reading/building graphs/digraphs This module gathers functions needed to build a graph from any other data. diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 16fd32608d8..5d646060add 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- r""" -Graph Plotting +Graph plotting *(For LaTeX drawings of graphs, see the* :mod:`~sage.graphs.graph_latex` *module.)* diff --git a/src/sage/graphs/matchpoly.pyx b/src/sage/graphs/matchpoly.pyx index 444d99ebee3..4a8c24be8ca 100644 --- a/src/sage/graphs/matchpoly.pyx +++ b/src/sage/graphs/matchpoly.pyx @@ -1,6 +1,6 @@ # cython: binding=True """ -Matching Polynomial +Matching polynomial This module contains the following methods: diff --git a/src/sage/graphs/path_enumeration.pyx b/src/sage/graphs/path_enumeration.pyx index 2e3122b6134..0ef63dd0c17 100644 --- a/src/sage/graphs/path_enumeration.pyx +++ b/src/sage/graphs/path_enumeration.pyx @@ -2,7 +2,7 @@ # cython: binding=True # distutils: language = c++ r""" -Path Enumeration +Path enumeration This module is meant for all functions related to path enumeration in graphs. diff --git a/src/sage/graphs/schnyder.py b/src/sage/graphs/schnyder.py index a29bce8dd3c..5816d1c7952 100644 --- a/src/sage/graphs/schnyder.py +++ b/src/sage/graphs/schnyder.py @@ -1,5 +1,5 @@ """ -Schnyder's Algorithm for straight-line planar embeddings +Schnyder's algorithm for straight-line planar embeddings A module for computing the (x,y) coordinates for a straight-line planar embedding of any connected planar graph with at least three vertices. Uses diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index a4eff7ecff8..1e01738662d 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -47,6 +47,7 @@ from libc.stdint cimport uint_fast32_t cdef dict _brouwer_database = None _small_srg_database = None + @cached_function def is_paley(int v, int k, int l, int mu): r""" @@ -72,12 +73,13 @@ def is_paley(int v, int k, int l, int mu): (13, 6, 2, 3) sage: t = is_paley(5,5,5,5); t """ - if (v%4 == 1 and is_prime_power(v) and - k == (v-1)//2 and - l == (v-5)//4 and - mu == (v-1)//4): + if (v % 4 == 1 and is_prime_power(v) and + k == (v - 1)//2 and + l == (v - 5)//4 and + mu == (v - 1)//4): from sage.graphs.generators.families import PaleyGraph - return (PaleyGraph,v) + return (PaleyGraph, v) + @cached_function def is_mathon_PC_srg(int v, int k, int l, int mu): @@ -119,21 +121,21 @@ def is_mathon_PC_srg(int v, int k, int l, int mu): sage: t = is_mathon_PC_srg(4*mu+1,2*mu,mu-1,mu); t """ cdef int t - if (v%4 == 1 and - k == (v-1)//2 and - l == (v-5)//4 and - mu == (v-1)//4): + if (v % 4 == 1 and + k == (v - 1)//2 and + l == (v - 5)//4 and + mu == (v - 1)//4): from sage.rings.integer_ring import ZZ K = ZZ['x'] x = K.gen() - rpoly = (w for w in (x*(4*x*(4*x-1)-1) - mu).roots() if w[0] > 0) + rpoly = (w for w in (x*(4*x*(4*x - 1) - 1) - mu).roots() if w[0] > 0) try: t = next(rpoly)[0] - if (is_prime_power(4*t-1) and - is_prime_power(4*t+1)): # extra assumption in TODO! + if (is_prime_power(4*t - 1) and + is_prime_power(4*t + 1)): # extra assumption in TODO! from sage.graphs.generators.families import \ MathonPseudocyclicStronglyRegularGraph - return (MathonPseudocyclicStronglyRegularGraph,t) + return (MathonPseudocyclicStronglyRegularGraph, t) except StopIteration: pass @@ -167,16 +169,19 @@ def is_muzychuk_S6(int v, int k, int l, int mu): """ cdef int n, d from sage.rings.integer_ring import ZZ - n_list = [n for n in range(l-1) if ZZ(n).is_prime_power()] + n_list = [n for n in range(l - 1) if ZZ(n).is_prime_power()] for n in n_list: d = 2 - while n**d * ((n**d-1)//(n-1)+1) <= v: - if v == n**d * ((n**d-1)//(n-1)+1) and k == n**(d-1)*(n**d-1)//(n-1) - 1\ - and l == mu - 2 and mu == n**(d-1) * (n**(d-1)-1) // (n-1): + while n**d * ((n**d - 1)//(n - 1) + 1) <= v: + if (v == n**d * ((n**d - 1)//(n - 1) + 1) and + k == n**(d - 1)*(n**d - 1)//(n - 1) - 1 and + l == mu - 2 and + mu == n**(d - 1) * (n**(d - 1) - 1)//(n - 1)): from sage.graphs.generators.families import MuzychukS6Graph return (MuzychukS6Graph, n, d) d += 1 + @cached_function def is_orthogonal_array_block_graph(int v, int k, int l, int mu): r""" @@ -232,19 +237,20 @@ def is_orthogonal_array_block_graph(int v, int k, int l, int mu): m, n = latin_squares_graph_parameters(v, k, l, mu) except Exception: return - if orthogonal_array(m,n,existence=True) is True: + if orthogonal_array(m, n, existence=True) is True: from sage.graphs.generators.intersection import OrthogonalArrayBlockGraph - return (lambda m,n : OrthogonalArrayBlockGraph(m, n), m,n) + return (lambda m, n: OrthogonalArrayBlockGraph(m, n), m, n) - elif n>2 and skew_hadamard_matrix(n+1, existence=True) is True: - if m==(n+1)/2: + elif n > 2 and skew_hadamard_matrix(n+1, existence=True) is True: + if m == (n + 1)/2: from sage.graphs.generators.families import SquaredSkewHadamardMatrixGraph as G - elif m==(n-1)//2: + elif m == (n - 1)//2: from sage.graphs.generators.families import PasechnikGraph as G else: return return (G, (n+1)//4) + @cached_function def is_johnson(int v, int k, int l, int mu): r""" @@ -276,10 +282,11 @@ def is_johnson(int v, int k, int l, int mu): # J(n,m) has parameters v = m(m – 1)/2, k = 2(m – 2), λ = m – 2, μ = 4. m = l + 2 if (mu == 4 and - k == 2*(m-2) and - v == m*(m-1)//2): + k == 2*(m - 2) and + v == m*(m - 1)//2): from sage.graphs.generators.families import JohnsonGraph - return (lambda m: JohnsonGraph(m,2), m) + return (lambda m: JohnsonGraph(m, 2), m) + @cached_function def is_steiner(int v, int k, int l, int mu): @@ -317,15 +324,16 @@ def is_steiner(int v, int k, int l, int mu): if mu <= 1 or not is_square(mu): return m = int(sqrt(mu)) - n = (k*(m-1))//m+m + n = (k*(m - 1))//m + m - if (v == (n*(n-1))/(m*(m-1)) and - k == m*(n-m)/(m-1) and - l == (m-1)**2 + (n-1)/(m-1)-2 and - balanced_incomplete_block_design(n,m,existence=True) is True): + if (v == (n*(n - 1))/(m*(m - 1)) and + k == m*(n - m)/(m - 1) and + l == (m - 1)**2 + (n - 1)/(m - 1) - 2 and + balanced_incomplete_block_design(n, m, existence=True) is True): from sage.graphs.generators.intersection import IntersectionGraph return (lambda n, m: IntersectionGraph([frozenset(b) for b in balanced_incomplete_block_design(n, m)]), n, m) + @cached_function def is_affine_polar(int v, int k, int l, int mu): r""" @@ -361,25 +369,25 @@ def is_affine_polar(int v, int k, int l, int mu): # # VO−(2e,q) has parameters v = q^(2e), k = (q^(e−1) - 1)(q^e + 1), λ = # q(q^(e−2) - 1)(q^(e−1) + 1) + q − 2, μ = q^(e−1)(q^(e−1) - 1) - if (not is_square(v) or - not is_prime_power(v)): + if not is_square(v) or not is_prime_power(v): return - prime,power = is_prime_power(v,get_data=True) - if power%2: + prime, power = is_prime_power(v, get_data=True) + if power % 2: return for e in divisors(power/2): q = prime**(power//(2*e)) assert v == q**(2*e) - if (k == (q**(e-1) + 1)*(q**e-1) and - l == q*(q**(e-2) + 1)*(q**(e-1)-1)+q-2 and - mu== q**(e-1)*(q**(e-1) + 1)): + if (k == (q**(e - 1) + 1)*(q**e - 1) and + l == q*(q**(e - 2) + 1)*(q**(e - 1) - 1) + q - 2 and + mu == q**(e - 1)*(q**(e - 1) + 1)): from sage.graphs.generators.classical_geometries import AffineOrthogonalPolarGraph - return (lambda d,q : AffineOrthogonalPolarGraph(d,q,sign='+'),2*e,q) - if (k == (q**(e-1) - 1)*(q**e+1) and - l == q*(q**(e-2)- 1)*(q**(e-1)+1)+q-2 and - mu== q**(e-1)*(q**(e-1) - 1)): + return (lambda d, q: AffineOrthogonalPolarGraph(d, q, sign='+'), 2*e, q) + if (k == (q**(e - 1) - 1)*(q**e + 1) and + l == q*(q**(e - 2) - 1)*(q**(e - 1) + 1) + q - 2 and + mu == q**(e - 1)*(q**(e - 1) - 1)): from sage.graphs.generators.classical_geometries import AffineOrthogonalPolarGraph - return (lambda d,q : AffineOrthogonalPolarGraph(d,q,sign='-'),2*e,q) + return (lambda d, q: AffineOrthogonalPolarGraph(d, q, sign='-'), 2*e, q) + @cached_function def is_orthogonal_polar(int v, int k, int l, int mu): @@ -427,35 +435,36 @@ def is_orthogonal_polar(int v, int k, int l, int mu): q_pow_m_minus_one = -s-1 if abs(s) > r else r+1 if is_prime_power(q_pow_m_minus_one): - prime,power = is_prime_power(q_pow_m_minus_one,get_data=True) + prime, power = is_prime_power(q_pow_m_minus_one, get_data=True) for d in divisors(power): q = prime**d - m = (power//d)+1 + m = (power//d) + 1 # O(2m+1,q) - if (v == (q**(2*m)-1)//(q-1) and - k == q*(q**(2*m-2)-1)//(q-1) and - l == q**2*(q**(2*m-4)-1)//(q-1) + q-1 and - mu== (q**(2*m-2)-1)//(q-1)): + if (v == (q**(2*m) - 1)//(q - 1) and + k == q*(q**(2*m - 2) - 1)//(q - 1) and + l == q**2*(q**(2*m - 4) - 1)//(q - 1) + q - 1 and + mu == (q**(2*m - 2) - 1)//(q - 1)): from sage.graphs.generators.classical_geometries import OrthogonalPolarGraph return (OrthogonalPolarGraph, 2*m+1, q, "") # O^+(2m,q) - if (v == (q**(2*m-1)-1)//(q-1) + q**(m-1) and - k == q*(q**(2*m-3)-1)//(q-1) + q**(m-1) and - k == q**(2*m-3) + l + 1 and - mu== k//q): + if (v == (q**(2*m - 1) - 1)//(q - 1) + q**(m - 1) and + k == q*(q**(2*m - 3) - 1)//(q - 1) + q**(m - 1) and + k == q**(2*m - 3) + l + 1 and + mu == k//q): from sage.graphs.generators.classical_geometries import OrthogonalPolarGraph return (OrthogonalPolarGraph, 2*m, q, "+") # O^+(2m+1,q) - if (v == (q**(2*m-1)-1)//(q-1) - q**(m-1) and - k == q*(q**(2*m-3)-1)//(q-1) - q**(m-1) and - k == q**(2*m-3) + l + 1 and - mu== k//q): + if (v == (q**(2*m - 1) - 1)//(q - 1) - q**(m - 1) and + k == q*(q**(2*m - 3) - 1)//(q - 1) - q**(m - 1) and + k == q**(2*m - 3) + l + 1 and + mu == k//q): from sage.graphs.generators.classical_geometries import OrthogonalPolarGraph return (OrthogonalPolarGraph, 2*m, q, "-") + @cached_function def is_goethals_seidel(int v, int k, int l, int mu): r""" @@ -520,15 +529,15 @@ def is_goethals_seidel(int v, int k, int l, int mu): # - the number of vertices v is equal to v_bibd*(r_bibd+1) # - the degree k of the graph is equal to k=(v+r_bibd-1)/2 - r_bibd = k - (v-1-k) - v_bibd = v//(r_bibd+1) - k_bibd = (v_bibd-1)//r_bibd + 1 if r_bibd>0 else -1 + r_bibd = k - (v - 1 - k) + v_bibd = v//(r_bibd + 1) + k_bibd = (v_bibd - 1)//r_bibd + 1 if r_bibd > 0 else -1 - if (v == v_bibd*(r_bibd+1) and - 2*k == v+r_bibd-1 and - 4*l == -2*v + 6*k -v_bibd -k_bibd and - hadamard_matrix(r_bibd+1, existence=True) is True and - balanced_incomplete_block_design(v_bibd, k_bibd, existence = True) is True): + if (v == v_bibd*(r_bibd + 1) and + 2*k == v + r_bibd - 1 and + 4*l == -2*v + 6*k - v_bibd - k_bibd and + hadamard_matrix(r_bibd + 1, existence=True) is True and + balanced_incomplete_block_design(v_bibd, k_bibd, existence=True) is True): from sage.graphs.generators.families import GoethalsSeidelGraph return [GoethalsSeidelGraph, k_bibd, r_bibd] diff --git a/src/sage/graphs/traversals.pyx b/src/sage/graphs/traversals.pyx index 14374831be8..a16ac6d701e 100644 --- a/src/sage/graphs/traversals.pyx +++ b/src/sage/graphs/traversals.pyx @@ -2,7 +2,7 @@ # cython: binding=True # distutils: language = c++ r""" -Graph traversals. +Graph traversals **This module implements the following graph traversals** diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index 90f8e07ba2c..4866cdc4f85 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -2028,19 +2028,17 @@ def cubic_braid_subgroup(self, nstrands=None): True """ if nstrands is None: - nstrands = self.strands() -1 + nstrands = self.strands() - 1 n = self.strands() nstrands = Integer(nstrands) if nstrands >= n or nstrands <= 0: - raise ValueError("nstrands must be positive and less than %s" %(self.strands())) - + raise ValueError("nstrands must be positive and less than %s" % (self.strands())) names = self.variable_names() - names_red = names[:nstrands-1] + names_red = names[:nstrands - 1] subgrp = CubicBraidGroup(names=names_red, cbg_type=self._cbg_type) subgrp._ambient = self return subgrp - diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index a02305df78e..9fa0fe07974 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -31,15 +31,15 @@ Classes and Methods =================== """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2018 Daniel Krenn # # 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/ +# **************************************************************************** from sage.structure.element import MultiplicativeGroupElement from sage.structure.factory import UniqueFactory @@ -48,6 +48,7 @@ from sage.structure.unique_representation import UniqueRepresentation import sage.rings.abc + class AbstractArgument(MultiplicativeGroupElement): r""" An element of :class:`AbstractArgumentGroup`. This abstract class @@ -488,7 +489,7 @@ def _symbolic_(self, R=None): if R is None: R = SR - return exp(2*R('pi')*R('I') * self.exponent) + return exp(2 * R('pi') * R('I') * self.exponent) def _mul_(self, other): r""" @@ -609,7 +610,7 @@ def is_minus_one(self): False """ from sage.rings.rational_field import QQ - return self.exponent == QQ(1)/QQ(2) + return self.exponent == QQ((1, 2)) class UnitCircleGroup(AbstractArgumentGroup): @@ -750,7 +751,7 @@ def _element_constructor_(self, data, exponent=None, **kwds): exponent = 0 elif data == -1 or data == '-1': - exponent = QQ(1)/QQ(2) + exponent = QQ((1, 2)) else: try: @@ -762,7 +763,7 @@ def _element_constructor_(self, data, exponent=None, **kwds): if data.is_one(): exponent = 0 elif data.is_minus_one(): - exponent = QQ(1)/QQ(2) + exponent = QQ((1, 2)) elif isinstance(P, UnitCircleGroup): exponent = data.exponent @@ -961,11 +962,11 @@ def _repr_(self): from sage.rings.rational_field import QQ if self.exponent == 0: return '1' - if self.exponent == QQ(1)/QQ(2): + if self.exponent == QQ((1, 2)): return '-1' - if self.exponent == QQ(1)/QQ(4): + if self.exponent == QQ((1, 4)): return 'I' - if self.exponent == QQ(3)/QQ(4): + if self.exponent == QQ((3, 4)): return '-I' num = self.exponent_numerator() den = self.exponent_denominator() @@ -1008,8 +1009,7 @@ def __classcall__(cls, category=None): Category of commutative groups """ category = cls._determine_category_(category) - return super(AbstractArgumentGroup, cls).__classcall__( - cls, category) + return super(AbstractArgumentGroup, cls).__classcall__(cls, category) def __init__(self, category): r""" @@ -1143,7 +1143,7 @@ def _symbolic_(self, R=None): if R is None: R = SR - return exp(R('I')*arg(self._element_)) + return exp(R('I') * arg(self._element_)) def _mul_(self, other): r""" @@ -1624,9 +1624,9 @@ def __classcall__(cls, category=None): sage: from sage.groups.misc_gps.argument_groups import SignGroup sage: S = SignGroup() sage: S.category() # indirect doctest - Category of commutative groups + Category of finite commutative groups """ - category = cls._determine_category_(category) + category = cls._determine_category_(category).Finite() return super(AbstractArgumentGroup, cls).__classcall__( cls, category) diff --git a/src/sage/groups/perm_gps/permgroup.py b/src/sage/groups/perm_gps/permgroup.py index 0a447179cf8..7723ec25260 100644 --- a/src/sage/groups/perm_gps/permgroup.py +++ b/src/sage/groups/perm_gps/permgroup.py @@ -135,7 +135,7 @@ # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # **************************************************************************** - +from __future__ import annotations from functools import wraps from sage.misc.randstate import current_randstate @@ -492,7 +492,7 @@ def __init__(self, gens=None, gap_group=None, canonicalize=True, if isinstance(gap_group, LibGapElement): self._libgap = gap_group - #Handle the case where only the GAP group is specified. + # Handle the case where only the GAP group is specified. if gens is None: gens = [gen for gen in gap_group.GeneratorsOfGroup()] @@ -509,9 +509,9 @@ def __init__(self, gens=None, gap_group=None, canonicalize=True, # Fallback (not ideal: find a better solution?) domain = sorted(domain, key=str) - #Here we need to check if all of the points are integers - #to make the domain contain all integers up to the max. - #This is needed for backward compatibility + # Here we need to check if all of the points are integers + # to make the domain contain all integers up to the max. + # This is needed for backward compatibility if all(isinstance(p, (int, Integer)) for p in domain): domain = list(range(min([1] + domain), max([1] + domain)+1)) @@ -1237,9 +1237,11 @@ def elements(SGS): else: raise ValueError("the input algorithm (='%s') must be 'SGS', 'BFS' or 'DFS'" % algorithm) - def gens(self): + def gens(self) -> tuple: """ - Return tuple of generators of this group. These need not be + Return tuple of generators of this group. + + These need not be minimal, as they are the generators used in defining this group. EXAMPLES:: @@ -1270,14 +1272,14 @@ def gens(self): We make sure that the trivial group gets handled correctly:: sage: SymmetricGroup(1).gens() - [()] + ((),) """ return self._gens - def gens_small(self): """ For this group, returns a generating set which has few elements. + As neither irredundancy nor minimal length is proven, it is fast. EXAMPLES:: @@ -3358,8 +3360,7 @@ def character_table(self): sage: G = PermutationGroup([[(1,2),(3,4)], [(1,2,3)]]) sage: CT = gap(G).CharacterTable() - Type ``print(gap.eval("Display(%s)"%CT.name()))`` to display this - nicely. + Type ``CT.Display()`` to display this nicely. :: @@ -3374,8 +3375,7 @@ def character_table(self): [ 2 0 0 0 -2] sage: CT = gap(G).CharacterTable() - Again, type ``print(gap.eval("Display(%s)"%CT.name()))`` to display this - nicely. + Again, type ``CT.Display()`` to display this nicely. :: diff --git a/src/sage/groups/perm_gps/permgroup_element.pyx b/src/sage/groups/perm_gps/permgroup_element.pyx index 840273a3eea..620ca2a71bd 100644 --- a/src/sage/groups/perm_gps/permgroup_element.pyx +++ b/src/sage/groups/perm_gps/permgroup_element.pyx @@ -88,7 +88,7 @@ We create element of a permutation group of large degree:: (1,30)(2,29)(3,28)(4,27)(5,26)(6,25)(7,24)(8,23)(9,22)(10,21)(11,20)(12,19)(13,18)(14,17)(15,16) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2006 David Joyner # Copyright (C) 2019 Vincent Delecroix <20100.delecroix@gmail.com> @@ -97,8 +97,8 @@ We create element of a permutation group of large degree:: # 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 copy import random @@ -944,7 +944,7 @@ cdef class PermutationGroupElement(MultiplicativeGroupElement): sage: S = SymmetricGroup(['a', 'b']) sage: latex(S.gens()) - \left[(\text{\texttt{a}},\text{\texttt{b}})\right] + \left((\text{\texttt{a}},\text{\texttt{b}})\right) """ from sage.misc.latex import latex return "".join(("(" + ",".join(latex(x) for x in cycle) + ")") diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index d5078f03b40..a3be9f974fe 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -272,8 +272,8 @@ def __init__(self, domain=None): gens = [tuple(self._domain)] if len(self._domain) > 2: gens.append(tuple(self._domain[:2])) - self._gens = [self.element_class(g, self, check=False) - for g in gens] + self._gens = tuple([self.element_class(g, self, check=False) + for g in gens]) def _gap_init_(self, gap=None): """ diff --git a/src/sage/groups/raag.py b/src/sage/groups/raag.py index 59b78c6d757..e8d626a32a4 100644 --- a/src/sage/groups/raag.py +++ b/src/sage/groups/raag.py @@ -857,4 +857,3 @@ class Element(CohomologyRAAGElement): """ An element in the cohomology ring of a right-angled Artin group. """ - diff --git a/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py b/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py index 6119a36d3ed..78c485bfc02 100644 --- a/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py +++ b/src/sage/groups/semimonomial_transformations/semimonomial_transformation_group.py @@ -51,6 +51,7 @@ sage: TestSuite(S).run() sage: TestSuite(S.an_element()).run() """ +from __future__ import annotations from sage.rings.integer import Integer from sage.groups.group import FiniteGroup @@ -285,7 +286,7 @@ def __contains__(self, item) -> bool: return False return True - def gens(self): + def gens(self) -> tuple: r""" Return a tuple of generators of ``self``. @@ -293,11 +294,11 @@ def gens(self): sage: F. = GF(4) sage: SemimonomialTransformationGroup(F, 3).gens() - [((a, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2 + (((a, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), ((1, 1, 1); (1,2,3), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), ((1, 1, 1); (1,2), Ring endomorphism of Finite Field in a of size 2^2 Defn: a |--> a), ((1, 1, 1); (), Ring endomorphism of Finite Field in a of size 2^2 - Defn: a |--> a + 1)] + Defn: a |--> a + 1)) """ from sage.groups.perm_gps.permgroup_named import SymmetricGroup R = self.base_ring() @@ -306,7 +307,7 @@ def gens(self): l.append(self(perm=Permutation(g))) if R.is_field() and not R.is_prime_field(): l.append(self(autom=R.hom([R.primitive_element()**R.characteristic()]))) - return l + return tuple(l) def order(self) -> Integer: r""" diff --git a/src/sage/homology/free_resolution.py b/src/sage/homology/free_resolution.py index 7d3ea29057e..424086d283e 100644 --- a/src/sage/homology/free_resolution.py +++ b/src/sage/homology/free_resolution.py @@ -891,4 +891,3 @@ def _maps(self): r = minres(res(std(mod), 0)) return si2sa_resolution(r) - diff --git a/src/sage/homology/graded_resolution.py b/src/sage/homology/graded_resolution.py index 97a3cb9624b..940d24d160d 100644 --- a/src/sage/homology/graded_resolution.py +++ b/src/sage/homology/graded_resolution.py @@ -572,4 +572,3 @@ def _maps(self): self._res_shifts = res_shifts return res_mats - diff --git a/src/sage/interfaces/magma.py b/src/sage/interfaces/magma.py index bd75a6a1850..e34e5a13aa3 100644 --- a/src/sage/interfaces/magma.py +++ b/src/sage/interfaces/magma.py @@ -197,7 +197,7 @@ magma.functions... """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -210,8 +210,8 @@ # The full text of the GPL is available at: # # http://www.gnu.org/licenses/ -#***************************************************************************** - +# **************************************************************************** +from __future__ import annotations import re import sys @@ -2133,14 +2133,14 @@ def gen(self, n): """ if n <= 0: raise IndexError("index must be positive since Magma indexes are 1-based") - return self.gens()[n-1] + return self.gens()[n - 1] - def gens(self): + def gens(self) -> tuple: """ - Return generators for self. + Return generators for ``self``. If self is named X in Magma, this function evaluates X.1, X.2, - etc., in Magma until an error occurs. It then returns a Sage list + etc., in Magma until an error occurs. It then returns a Sage tuple of the resulting X.i. Note - I don't think there is a Magma command that returns the list of valid X.i. There are numerous ad hoc functions for various classes but nothing systematic. This function @@ -2154,9 +2154,9 @@ def gens(self): EXAMPLES:: sage: magma("VectorSpace(RationalField(),3)").gens() # optional - magma - [(1 0 0), (0 1 0), (0 0 1)] + ((1 0 0), (0 1 0), (0 0 1)) sage: magma("AbelianGroup(EllipticCurve([1..5]))").gens() # optional - magma - [$.1] + ($.1,) """ try: return self._magma_gens @@ -2172,8 +2172,9 @@ def gens(self): except (RuntimeError, TypeError): break i += 1 - self._magma_gens = G - return G + tG = tuple(G) + self._magma_gens = tG + return tG def gen_names(self): """ diff --git a/src/sage/lfunctions/pari.py b/src/sage/lfunctions/pari.py index d2b20f1891b..da783d28310 100644 --- a/src/sage/lfunctions/pari.py +++ b/src/sage/lfunctions/pari.py @@ -108,7 +108,7 @@ def __init__(self, conductor, gammaV, weight, eps, poles=[], if args or kwds: self.init_coeffs(*args, **kwds) - def init_coeffs(self, v, cutoff=None, w=1, *args, **kwds): + def init_coeffs(self, v, cutoff=None, w=1): """ Set the coefficients `a_n` of the `L`-series. @@ -126,7 +126,7 @@ def init_coeffs(self, v, cutoff=None, w=1, *args, **kwds): EXAMPLES:: sage: from sage.lfunctions.pari import lfun_generic, LFunction - sage: lf = lfun_generic(conductor=1, gammaV=[0,1], weight=12, eps=1) + sage: lf = lfun_generic(conductor=1, gammaV=[0, 1], weight=12, eps=1) sage: pari_coeffs = pari('k->vector(k,n,(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5)))') sage: lf.init_coeffs(pari_coeffs) @@ -144,7 +144,7 @@ def init_coeffs(self, v, cutoff=None, w=1, *args, **kwds): Illustrate that one can give a list of complex numbers for v (see :trac:`10937`):: - sage: l2 = lfun_generic(conductor=1, gammaV=[0,1], weight=12, eps=1) + sage: l2 = lfun_generic(conductor=1, gammaV=[0, 1], weight=12, eps=1) sage: l2.init_coeffs(list(delta_qexp(1000))[1:]) sage: L2 = LFunction(l2) sage: L2(14) @@ -155,20 +155,9 @@ def init_coeffs(self, v, cutoff=None, w=1, *args, **kwds): Verify that setting the `w` parameter does not raise an error (see :trac:`10937`):: - sage: L2 = lfun_generic(conductor=1, gammaV=[0,1], weight=12, eps=1) + sage: L2 = lfun_generic(conductor=1, gammaV=[0, 1], weight=12, eps=1) sage: L2.init_coeffs(list(delta_qexp(1000))[1:], w=[1..1000]) - - Additional arguments are ignored for compatibility with the old - Dokchitser script:: - - sage: L2.init_coeffs(list(delta_qexp(1000))[1:], foo="bar") - doctest:...: DeprecationWarning: additional arguments for initializing an lfun_generic are ignored - See https://trac.sagemath.org/26098 for details. """ - if args or kwds: - from sage.misc.superseded import deprecation - deprecation(26098, "additional arguments for initializing an lfun_generic are ignored") - v = pari(v) if v.type() not in ('t_CLOSURE', 't_VEC'): raise TypeError("v (coefficients) must be a list or a function") @@ -250,12 +239,12 @@ def lfun_character(chi): Check the values:: - sage: chi = DirichletGroup(24)([1,-1,-1]); chi + sage: chi = DirichletGroup(24)([1, -1, -1]); chi Dirichlet character modulo 24 of conductor 24 mapping 7 |--> 1, 13 |--> -1, 17 |--> -1 sage: Lchi = lfun_character(chi) sage: v = [0] + Lchi.lfunan(30).sage() - sage: all(v[i] == chi(i) for i in (7,13,17)) + sage: all(v[i] == chi(i) for i in (7, 13, 17)) True """ if not chi.is_primitive(): @@ -285,7 +274,7 @@ def lfun_elliptic_curve(E): Over number fields:: sage: K. = QuadraticField(2) - sage: E = EllipticCurve([1,a]) + sage: E = EllipticCurve([1, a]) sage: L = LFunction(lfun_elliptic_curve(E)) sage: L(3) 1.00412346717019 @@ -309,7 +298,7 @@ def lfun_number_field(K): sage: L(3) 1.20205690315959 - sage: K = NumberField(x**2-2, 'a') + sage: K = NumberField(x**2 - 2, 'a') sage: L = LFunction(lfun_number_field(K)) sage: L(3) 1.15202784126080 @@ -338,10 +327,10 @@ def lfun_eta_quotient(scalings, exponents): sage: L(1) 0.0374412812685155 - sage: lfun_eta_quotient([6],[4]) + sage: lfun_eta_quotient([6], [4]) [[Vecsmall([7]), [Vecsmall([6]), Vecsmall([4])]], 0, [0, 1], 2, 36, 1] - sage: lfun_eta_quotient([2,1,4], [5,-2,-2]) + sage: lfun_eta_quotient([2, 1, 4], [5, -2, -2]) Traceback (most recent call last): ... PariError: sorry, noncuspidal eta quotient is not yet implemented @@ -377,7 +366,7 @@ def lfun_quadratic_form(qf): EXAMPLES:: sage: from sage.lfunctions.pari import lfun_quadratic_form, LFunction - sage: Q = QuadraticForm(ZZ,2,[2,3,4]) + sage: Q = QuadraticForm(ZZ, 2, [2, 3, 4]) sage: L = LFunction(lfun_quadratic_form(Q)) sage: L(3) 0.377597233183583 @@ -409,7 +398,7 @@ def lfun_genus2(C): sage: L(3) 0.965946926261520 - sage: C = HyperellipticCurve(x^2+x, x^3+x^2+1) + sage: C = HyperellipticCurve(x^2 + x, x^3 + x^2 + 1) sage: L = LFunction(lfun_genus2(C)) sage: L(2) 0.364286342944359 @@ -445,11 +434,11 @@ class LFunction(SageObject): 0.000000000000000 sage: L.derivative(1) 0.305999773834052 - sage: L.derivative(1,2) + sage: L.derivative(1, 2) 0.373095594536324 sage: L.num_coeffs() 50 - sage: L.taylor_series(1,4) + sage: L.taylor_series(1, 4) 0.000000000000000 + 0.305999773834052*z + 0.186547797268162*z^2 - 0.136791463097188*z^3 + O(z^4) sage: L.check_functional_equation() # abs tol 4e-19 1.08420217248550e-19 @@ -463,9 +452,9 @@ class LFunction(SageObject): sage: L = E.lseries().dokchitser(algorithm="pari") sage: L.num_coeffs() 163 - sage: L.derivative(1,E.rank()) + sage: L.derivative(1, E.rank()) 1.51863300057685 - sage: L.taylor_series(1,4) + sage: L.taylor_series(1, 4) ...e-19 + (...e-19)*z + 0.759316500288427*z^2 - 0.430302337583362*z^3 + O(z^4) .. RUBRIC:: Number field @@ -481,7 +470,7 @@ class LFunction(SageObject): 348 sage: L(2) 1.10398438736918 - sage: L.taylor_series(2,3) + sage: L.taylor_series(2, 3) 1.10398438736918 - 0.215822638498759*z + 0.279836437522536*z^2 + O(z^3) .. RUBRIC:: Ramanujan `\Delta` L-function @@ -489,7 +478,7 @@ class LFunction(SageObject): The coefficients are given by Ramanujan's tau function:: sage: from sage.lfunctions.pari import lfun_generic, LFunction - sage: lf = lfun_generic(conductor=1, gammaV=[0,1], weight=12, eps=1) + sage: lf = lfun_generic(conductor=1, gammaV=[0, 1], weight=12, eps=1) sage: tau = pari('k->vector(k,n,(5*sigma(n,3)+7*sigma(n,5))*n/12 - 35*sum(k=1,n-1,(6*k-4*(n-k))*sigma(k,3)*sigma(n-k,5)))') sage: lf.init_coeffs(tau) sage: L = LFunction(lf) @@ -498,7 +487,7 @@ class LFunction(SageObject): sage: L(1) 0.0374412812685155 - sage: L.taylor_series(1,3) + sage: L.taylor_series(1, 3) 0.0374412812685155 + 0.0709221123619322*z + 0.0380744761270520*z^2 + O(z^3) """ def __init__(self, lfun, prec=None): @@ -608,7 +597,7 @@ def Lambda(self, s): sage: L = LFunction(lfun_number_field(QQ)) sage: L.Lambda(2) 0.523598775598299 - sage: L.Lambda(1-2) + sage: L.Lambda(1 - 2) 0.523598775598299 """ s = self._CCin(s) @@ -630,7 +619,7 @@ def hardy(self, t): TESTS:: - sage: L.hardy(.4+.3*I) + sage: L.hardy(.4 + .3*I) Traceback (most recent call last): ... PariError: incorrect type in lfunhardy (t_COMPLEX) @@ -694,7 +683,7 @@ def taylor_series(self, s, k=6, var='z'): sage: E = EllipticCurve('389a') sage: L = E.lseries().dokchitser(200,algorithm="pari") - sage: L.taylor_series(1,3) + sage: L.taylor_series(1, 3) 2...e-63 + (...e-63)*z + 0.75931650028842677023019260789472201907809751649492435158581*z^2 + O(z^3) Check that :trac:`25402` is fixed:: @@ -757,7 +746,7 @@ def __call__(self, s): sage: L = E.lseries().dokchitser(100, algorithm="pari") sage: L(1) 0.00000000000000000000000000000 - sage: L(1+I) + sage: L(1 + I) -1.3085436607849493358323930438 + 0.81298000036784359634835412129*I """ s = self._CC(s) diff --git a/src/sage/libs/eclib/mwrank.pyx b/src/sage/libs/eclib/mwrank.pyx index 7df61a54f12..119d4d49dd4 100644 --- a/src/sage/libs/eclib/mwrank.pyx +++ b/src/sage/libs/eclib/mwrank.pyx @@ -83,7 +83,7 @@ mwrank_set_precision(150) def get_precision(): """ - Returns the working floating point bit precision of mwrank, which is + Return the working floating point bit precision of mwrank, which is equal to the global NTL real number precision. OUTPUT: @@ -119,7 +119,7 @@ def set_precision(n): This change is global and affects *all* future calls of eclib functions by Sage. - .. note:: + .. NOTE:: The minimal value to which the precision may be set is 53. Lower values will be increased to 53. @@ -335,7 +335,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class return string_sigoff(Curvedata_repr(self.x))[:-1] def silverman_bound(self): - """ + r""" The Silverman height bound for this elliptic curve. OUTPUT: @@ -345,7 +345,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class + B`, where `h(P)` is the naive height and `\hat{h}(P)` the canonical height. - .. note:: + .. NOTE:: Since eclib can compute this to arbitrary precision, we could return a Sage real, but this is only a bound and in @@ -364,7 +364,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class return Curvedata_silverman_bound(self.x) def cps_bound(self): - """ + r""" The Cremona-Prickett-Siksek height bound for this elliptic curve. OUTPUT: @@ -374,12 +374,11 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class + B`, where `h(P)` is the naive height and `\hat{h}(P)` the canonical height. - .. note:: + .. NOTE:: - Since eclib can compute this to arbitrary precision, we + Since ``eclib`` can compute this to arbitrary precision, we could return a Sage real, but this is only a bound and in - the contexts in which it is used extra precision is - irrelevant. + the contexts in which it is used extra precision is irrelevant. EXAMPLES:: @@ -399,7 +398,7 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class return x def height_constant(self): - """ + r""" A height bound for this elliptic curve. OUTPUT: @@ -410,12 +409,11 @@ cdef class _Curvedata: # cython class wrapping eclib's Curvedata class canonical height. This is the minimum of the Silverman and Cremona_Prickett-Siksek height bounds. - .. note:: + .. NOTE:: - Since eclib can compute this to arbitrary precision, we + Since ``eclib`` can compute this to arbitrary precision, we could return a Sage real, but this is only a bound and in - the contexts in which it is used extra precision is - irrelevant. + the contexts in which it is used extra precision is irrelevant. EXAMPLES:: @@ -542,7 +540,7 @@ cdef class _mw: cdef int verb def __init__(self, _Curvedata curve, verb=False, pp=1, maxr=999): - """ + r""" Constructor for mw class. INPUT: @@ -704,10 +702,10 @@ cdef class _mw: .. NOTE:: - The eclib function which implements this only carries out - any saturation if the rank of the points increases upon - adding the new point. This is because it is assumed that - one saturates as ones goes along. + The eclib function which implements this only carries out + any saturation if the rank of the points increases upon + adding the new point. This is because it is assumed that + one saturates as ones goes along. EXAMPLES:: @@ -753,7 +751,7 @@ cdef class _mw: def getbasis(self): """ - Returns the current basis of the mw structure. + Return the current basis of the mw structure. OUTPUT: @@ -778,7 +776,7 @@ cdef class _mw: def regulator(self): """ - Returns the regulator of the current basis of the mw group. + Return the regulator of the current basis of the mw group. OUTPUT: @@ -810,7 +808,7 @@ cdef class _mw: def rank(self): """ - Returns the rank of the current basis of the mw group. + Return the rank of the current basis of the mw group. OUTPUT: @@ -908,7 +906,7 @@ cdef class _mw: return ok, index, unsat def search(self, h_lim, int moduli_option=0, int verb=0): - """ + r""" Search for points in the mw group. INPUT: @@ -926,17 +924,16 @@ cdef class _mw: .. NOTE:: - The effect of the search is also governed by the class - options, notably whether the points found are processed: - meaning that linear relations are found and saturation is - carried out, with the result that the list of generators - will always contain a `\ZZ`-span of the saturation of the - points found, modulo torsion. + The effect of the search is also governed by the class + options, notably whether the points found are processed: + meaning that linear relations are found and saturation is + carried out, with the result that the list of generators + will always contain a `\ZZ`-span of the saturation of the + points found, modulo torsion. OUTPUT: - None. The effect of the search is to update the list of - generators. + None. The effect of the search is to update the list of generators. EXAMPLES:: @@ -1069,7 +1066,7 @@ cdef class _two_descent: def getrank(self): """ - Returns the rank (after doing a 2-descent). + Return the rank (after doing a 2-descent). OUTPUT: @@ -1102,7 +1099,7 @@ cdef class _two_descent: def getrankbound(self): """ - Returns the rank upper bound (after doing a 2-descent). + Return the rank upper bound (after doing a 2-descent). OUTPUT: @@ -1135,7 +1132,7 @@ cdef class _two_descent: def getselmer(self): """ - Returns the 2-Selmer rank (after doing a 2-descent). + Return the 2-Selmer rank (after doing a 2-descent). OUTPUT: @@ -1167,7 +1164,7 @@ cdef class _two_descent: def ok(self): """ - Returns the success flag (after doing a 2-descent). + Return the success flag (after doing a 2-descent). OUTPUT: @@ -1196,7 +1193,7 @@ cdef class _two_descent: def getcertain(self): """ - Returns the certainty flag (after doing a 2-descent). + Return the certainty flag (after doing a 2-descent). OUTPUT: @@ -1273,8 +1270,8 @@ cdef class _two_descent: sig_off() def getbasis(self): - """ - Returns the basis of points found by doing a 2-descent. + r""" + Return the basis of points found by doing a 2-descent. If the success and certain flags are 1, this will be a `\ZZ/2\ZZ`-basis for `E(\QQ)/2E(\QQ)` (modulo torsion), @@ -1282,7 +1279,8 @@ cdef class _two_descent: .. NOTE:: - You must call ``saturate()`` first, or a RunTimeError will be raised. + You must call ``saturate()`` first, or a ``RunTimeError`` + will be raised. OUTPUT: @@ -1320,7 +1318,7 @@ cdef class _two_descent: def regulator(self): """ - Returns the regulator of the points found by doing a 2-descent. + Return the regulator of the points found by doing a 2-descent. OUTPUT: diff --git a/src/sage/libs/eclib/newforms.pyx b/src/sage/libs/eclib/newforms.pyx index d30ac0e3758..2d35716c4db 100644 --- a/src/sage/libs/eclib/newforms.pyx +++ b/src/sage/libs/eclib/newforms.pyx @@ -22,7 +22,7 @@ from sage.modular.all import Cusp cdef class ECModularSymbol: - """ + r""" Modular symbol associated with an elliptic curve, using John Cremona's newforms class. EXAMPLES:: diff --git a/src/sage/libs/ntl/ntl_GF2.pyx b/src/sage/libs/ntl/ntl_GF2.pyx index c88034ff5c4..8af0d6caf9a 100644 --- a/src/sage/libs/ntl/ntl_GF2.pyx +++ b/src/sage/libs/ntl/ntl_GF2.pyx @@ -116,6 +116,8 @@ cdef class ntl_GF2(): def __mul__(self, other): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: o*o @@ -137,6 +139,8 @@ cdef class ntl_GF2(): def __truediv__(self, other): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: o/o @@ -159,6 +163,8 @@ cdef class ntl_GF2(): def __sub__(self, other): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: o-o @@ -180,6 +186,8 @@ cdef class ntl_GF2(): def __add__(self, other): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: o+o @@ -201,6 +209,8 @@ cdef class ntl_GF2(): def __neg__(ntl_GF2 self): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: -z @@ -214,6 +224,8 @@ cdef class ntl_GF2(): def __pow__(ntl_GF2 self, long e, ignored): """ + EXAMPLES:: + sage: o = ntl.GF2(1) sage: z = ntl.GF2(0) sage: z^2 diff --git a/src/sage/libs/ntl/ntl_GF2E.pyx b/src/sage/libs/ntl/ntl_GF2E.pyx index bc6a32ce0d3..54c7eef492a 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_GF2E.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # Copyright (C) 2007 Martin Albrecht # @@ -18,8 +18,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.ext.cplusplus cimport ccrepr @@ -73,7 +73,7 @@ def ntl_GF2E_random(ntl_GF2EContext_class ctx): cdef class ntl_GF2E(): r""" - The \\class{GF2E} represents a finite extension field over GF(2) + The :class:`GF2E` represents a finite extension field over GF(2) using NTL. Elements are represented as polynomials over GF(2) modulo a modulus. @@ -164,6 +164,8 @@ cdef class ntl_GF2E(): def __reduce__(self): """ + EXAMPLES:: + sage: ctx = ntl.GF2EContext( ntl.GF2X([1,1,0,1,1,0,0,0,1]) ) sage: a = ntl.GF2E(ntl.ZZ_pX([1,1,3],2), ctx) sage: loads(dumps(a)) == a @@ -439,17 +441,20 @@ cdef class ntl_GF2E(): return l def _sage_(ntl_GF2E self, k=None): - """ - Returns a \class{FiniteFieldElement} representation - of this element. If a \class{FiniteField} k is provided - it is constructed in this field if possible. A \class{FiniteField} - will be constructed if none is provided. + r""" + Return a :class:`FiniteFieldElement` representation of this element. + + If a :class:`FiniteField` `k` is provided, it is constructed + in this field if possible. A :class:`FiniteField` will be + constructed if none is provided. INPUT: - k -- optional GF(2**deg) + + - `k` -- (optional) a field `\GF{2^d}` OUTPUT: - FiniteFieldElement over k + + :class:`FiniteFieldElement` over `k` EXAMPLES:: diff --git a/src/sage/libs/ntl/ntl_ZZ.pyx b/src/sage/libs/ntl/ntl_ZZ.pyx index 39a98da2101..6f9d15f780e 100644 --- a/src/sage/libs/ntl/ntl_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_ZZ.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -17,8 +17,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr, ccreadstr @@ -176,6 +176,8 @@ cdef class ntl_ZZ(): def __mul__(self, other): """ + EXAMPLES:: + sage: n=ntl.ZZ(2983)*ntl.ZZ(2) sage: n 5966 @@ -192,6 +194,8 @@ cdef class ntl_ZZ(): def __sub__(self, other): """ + EXAMPLES:: + sage: n=ntl.ZZ(2983)-ntl.ZZ(2) sage: n 2981 @@ -208,6 +212,8 @@ cdef class ntl_ZZ(): def __add__(self, other): """ + EXAMPLES:: + sage: n=ntl.ZZ(2983)+ntl.ZZ(2) sage: n 2985 @@ -224,6 +230,8 @@ cdef class ntl_ZZ(): def __neg__(ntl_ZZ self): """ + EXAMPLES:: + sage: x = ntl.ZZ(38) sage: -x -38 @@ -236,6 +244,8 @@ cdef class ntl_ZZ(): def __pow__(ntl_ZZ self, long e, ignored): """ + EXAMPLES:: + sage: ntl.ZZ(23)^50 122008981252869411022491112993141891091036959856659100591281395343249 """ @@ -266,6 +276,7 @@ cdef class ntl_ZZ(): cdef int get_as_int(ntl_ZZ self): r""" Returns value as C int. + Return value is only valid if the result fits into an int. AUTHOR: David Harvey (2006-08-05) @@ -278,12 +289,14 @@ cdef class ntl_ZZ(): r""" This method exists solely for automated testing of get_as_int(). - sage: x = ntl.ZZ(42) - sage: i = x.get_as_int_doctest() - sage: i - 42 - sage: type(i) - <... 'int'> + EXAMPLES:: + + sage: x = ntl.ZZ(42) + sage: i = x.get_as_int_doctest() + sage: i + 42 + sage: type(i) + <... 'int'> """ return self.get_as_int() @@ -291,9 +304,11 @@ cdef class ntl_ZZ(): r""" Gets the value as a sage int. - sage: n=ntl.ZZ(2983) - sage: type(n._integer_()) - + EXAMPLES:: + + sage: n=ntl.ZZ(2983) + sage: type(n._integer_()) + AUTHOR: Joel B. Mohler """ @@ -332,10 +347,12 @@ cdef class ntl_ZZ(): r""" This method exists solely for automated testing of set_from_int(). - sage: x = ntl.ZZ() - sage: x.set_from_int_doctest(42) - sage: x - 42 + EXAMPLES:: + + sage: x = ntl.ZZ() + sage: x.set_from_int_doctest(42) + sage: x + 42 """ self.set_from_int(int(value)) diff --git a/src/sage/libs/ntl/ntl_ZZX.pyx b/src/sage/libs/ntl/ntl_ZZX.pyx index 8d38fcb7f8f..e369f7152e4 100644 --- a/src/sage/libs/ntl/ntl_ZZX.pyx +++ b/src/sage/libs/ntl/ntl_ZZX.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -17,8 +17,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off @@ -144,10 +144,12 @@ cdef class ntl_ZZX(): def __reduce__(self): """ - sage: from sage.libs.ntl.ntl_ZZX import ntl_ZZX - sage: f = ntl_ZZX([1,2,0,4]) - sage: loads(dumps(f)) == f - True + EXAMPLES:: + + sage: from sage.libs.ntl.ntl_ZZX import ntl_ZZX + sage: f = ntl_ZZX([1,2,0,4]) + sage: loads(dumps(f)) == f + True """ return unpickle_class_value, (ntl_ZZX, self.list()) @@ -183,6 +185,8 @@ cdef class ntl_ZZX(): def __setitem__(self, long i, a): """ + EXAMPLES:: + sage: n=ntl.ZZX([1,2,3]) sage: n [1 2 3] @@ -692,12 +696,14 @@ cdef class ntl_ZZX(): return (self*other).quo_rem(g)[0] def xgcd(self, ntl_ZZX other, proof=None): - """ - If self and other are coprime over the rationals, return r, s, - t such that r = s*self + t*other. Otherwise return 0. This - is \emph{not} the same as the \sage function on polynomials - over the integers, since here the return value r is always an - integer. + r""" + If ``self`` and ``other`` are coprime over the rationals, + return ``r, s, t`` such that ``r = s*self + t*other``. + Otherwise return 0. + + This is \emph{not} the same as the \sage function on + polynomials over the integers, since here the return value r + is always an integer. Here r is the resultant of a and b; if r != 0, then this function computes s and t such that: a*s + b*t = r; otherwise @@ -709,7 +715,6 @@ cdef class ntl_ZZX(): randomized strategy that errors with probability no more than `2^{-80}`. - EXAMPLES:: sage: f = ntl.ZZX([1,2,3]) * ntl.ZZX([4,5])**2 @@ -717,7 +722,8 @@ cdef class ntl_ZZX(): sage: f.xgcd(g) # nothing since they are not coprime (0, [], []) - In this example the input quadratic polynomials have a common root modulo 13. + In this example the input quadratic polynomials have a common root modulo 13:: + sage: f = ntl.ZZX([5,0,1]) sage: g = ntl.ZZX([18,0,1]) sage: f.xgcd(g) @@ -805,7 +811,8 @@ cdef class ntl_ZZX(): sage: f == g True - Though f and g are equal, they are not the same objects in memory: + Though f and g are equal, they are not the same objects in memory:: + sage: f is g False """ diff --git a/src/sage/libs/ntl/ntl_ZZ_p.pyx b/src/sage/libs/ntl/ntl_ZZ_p.pyx index 9b90383d50c..469d62f2812 100644 --- a/src/sage/libs/ntl/ntl_ZZ_p.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_p.pyx @@ -166,9 +166,11 @@ cdef class ntl_ZZ_p(): def __reduce__(self): """ - sage: a = ntl.ZZ_p(4,7) - sage: loads(dumps(a)) == a - True + EXAMPLES:: + + sage: a = ntl.ZZ_p(4,7) + sage: loads(dumps(a)) == a + True """ return unpickle_class_args, (ntl_ZZ_p, (self.lift(), self.modulus_context())) diff --git a/src/sage/libs/ntl/ntl_ZZ_pE.pyx b/src/sage/libs/ntl/ntl_ZZ_pE.pyx index 97c658dffb0..9e2d06bb58e 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pE.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pE.pyx @@ -166,9 +166,11 @@ cdef class ntl_ZZ_pE(): def __reduce__(self): """ - sage: a = ntl.ZZ_pE([4],ntl.ZZ_pX([1,1,1],ntl.ZZ(7))) - sage: loads(dumps(a)) == a - True + EXAMPLES:: + + sage: a = ntl.ZZ_pE([4],ntl.ZZ_pX([1,1,1],ntl.ZZ(7))) + sage: loads(dumps(a)) == a + True """ return make_ZZ_pE, (self.get_as_ZZ_pX(), self.get_modulus_context()) diff --git a/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx b/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx index bef581722bd..b6ff3c66b01 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEContext.pyx @@ -37,13 +37,15 @@ cdef class ntl_ZZ_pEContext_class(): """ EXAMPLES: - # You can construct contexts manually. + You can construct contexts manually:: + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([4,1,6],25)) sage: n1=c.ZZ_pE([10,17,12]) sage: n1 [2 15] - # or You can construct contexts implicitly. + Or you can construct contexts implicitly:: + sage: n2=ntl.ZZ_pE(12, ntl.ZZ_pX([1,1,1],7)) sage: n2 [5] @@ -65,9 +67,11 @@ cdef class ntl_ZZ_pEContext_class(): def __reduce__(self): """ - sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1],7)) - sage: loads(dumps(c)) is c - True + EXAMPLES:: + + sage: c=ntl.ZZ_pEContext(ntl.ZZ_pX([1,1,1],7)) + sage: loads(dumps(c)) is c + True """ return ntl_ZZ_pEContext, (self.f,) diff --git a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx index f9d2e982343..d5f10218a77 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pEX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pEX.pyx @@ -5,14 +5,15 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -""" +r""" Wrapper for NTL's polynomials over finite ring extensions of `\Z / p\Z.` AUTHORS: - -- David Roe (2007-10-10) + +- David Roe (2007-10-10) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein # David Roe # @@ -25,8 +26,8 @@ AUTHORS: # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr diff --git a/src/sage/libs/ntl/ntl_ZZ_pX.pyx b/src/sage/libs/ntl/ntl_ZZ_pX.pyx index 95d77f727fa..c2fff88cb0f 100644 --- a/src/sage/libs/ntl/ntl_ZZ_pX.pyx +++ b/src/sage/libs/ntl/ntl_ZZ_pX.pyx @@ -207,11 +207,13 @@ cdef class ntl_ZZ_pX(): def __setitem__(self, long i, a): r""" - sage: c = ntl.ZZ_pContext(23) - sage: x = ntl.ZZ_pX([2, 3, 4], c) - sage: x[1] = 5 - sage: x - [2 5 4] + EXAMPLES:: + + sage: c = ntl.ZZ_pContext(23) + sage: x = ntl.ZZ_pX([2, 3, 4], c) + sage: x[1] = 5 + sage: x + [2 5 4] """ if i < 0: raise IndexError("index (i=%s) must be >= 0" % i) diff --git a/src/sage/libs/ntl/ntl_lzz_pContext.pyx b/src/sage/libs/ntl/ntl_lzz_pContext.pyx index 64301157702..80ff9ac51bc 100644 --- a/src/sage/libs/ntl/ntl_lzz_pContext.pyx +++ b/src/sage/libs/ntl/ntl_lzz_pContext.pyx @@ -60,9 +60,11 @@ cdef class ntl_zz_pContext_class(): def __reduce__(self): """ - sage: c=ntl.zz_pContext(13) - sage: loads(dumps(c)) is c - True + EXAMPLES:: + + sage: c=ntl.zz_pContext(13) + sage: loads(dumps(c)) is c + True """ return ntl_zz_pContext, (self.p,) diff --git a/src/sage/libs/ntl/ntl_mat_GF2.pyx b/src/sage/libs/ntl/ntl_mat_GF2.pyx index 833b7b9ea8e..ee90bf17fce 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -""" +r""" Matrices over the `\GF{2}` via NTL This class is only provided to have a complete NTL interface and for @@ -13,11 +13,11 @@ comparison purposes. Sage's native matrices over `F_2` are much faster for many problems like matrix multiplication and Gaussian elimination. AUTHORS: - - Martin Albrecht - 2008-09: initial version + +- Martin Albrecht 2008-09: initial version """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # Copyright (C) 2008 Martin Albrecht # @@ -30,8 +30,8 @@ AUTHORS: # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr @@ -131,6 +131,8 @@ cdef class ntl_mat_GF2(): def __reduce__(self): """ + EXAMPLES:: + sage: A = random_matrix(GF(2),4,4) sage: B = ntl.mat_GF2(A) sage: loads(dumps(B)) == B # indirect doctest @@ -375,17 +377,18 @@ cdef class ntl_mat_GF2(): sig_off() return r - def gauss(self,ncols=-1): - """ - Performs unitary row operations so as to bring this matrix - into row echelon form (not reduced!). If the optional - argument \code{ncols} is supplied, stops when first ncols - columns are in echelon form. The return value is the rank (or - the rank of the first ncols columns). + def gauss(self, ncols=-1): + r""" + Perform unitary row operations so as to bring this matrix + into row echelon form (not reduced!). + + If the optional argument ``ncols`` is supplied, stops when + first ``ncols`` columns are in echelon form. The return value is + the rank (or the rank of the first ``ncols`` columns). INPUT: - ncols -- number of columns to process (default: all) + - ``ncols`` -- number of columns to process (default: all) EXAMPLES:: diff --git a/src/sage/libs/ntl/ntl_mat_GF2E.pyx b/src/sage/libs/ntl/ntl_mat_GF2E.pyx index e18d150cbda..574ff43c213 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2E.pyx @@ -445,17 +445,18 @@ cdef class ntl_mat_GF2E(): sig_off() return r - def gauss(self,ncols=-1): - """ - Performs unitary row operations so as to bring this matrix - into row echelon form. If the optional argument \code{ncols} - is supplied, stops when first ncols columns are in echelon - form. The return value is the rank (or the rank of the first - ncols columns). + def gauss(self, ncols=-1): + r""" + Perform unitary row operations so as to bring this matrix + into row echelon form. + + If the optional argument ``ncols`` is supplied, stops when + first ``ncols`` columns are in echelon form. The return value + is the rank (or the rank of the first ``ncols`` columns). INPUT: - - ``ncols`` - number of columns to process (default: all) + - ``ncols`` -- number of columns to process (default: all) EXAMPLES:: diff --git a/src/sage/libs/ntl/ntl_mat_ZZ.pyx b/src/sage/libs/ntl/ntl_mat_ZZ.pyx index dac2ca79636..fb1769db352 100644 --- a/src/sage/libs/ntl/ntl_mat_ZZ.pyx +++ b/src/sage/libs/ntl/ntl_mat_ZZ.pyx @@ -73,7 +73,7 @@ cdef class ntl_mat_ZZ(): The \class{mat_ZZ} class implements arithmetic with matrices over `\Z`. """ def __init__(self, nrows=0, ncols=0, v=None): - """ + r""" The \class{mat_ZZ} class implements arithmetic with matrices over `\Z`. EXAMPLES:: @@ -319,6 +319,8 @@ cdef class ntl_mat_ZZ(): def __getitem__(self, ij): """ + EXAMPLES:: + sage: m = ntl.mat_ZZ(3, 2, range(6)) sage: m[0,0] ## indirect doctest 0 diff --git a/src/sage/libs/singular/polynomial.pyx b/src/sage/libs/singular/polynomial.pyx index e012da4573c..b2efc7dfbcb 100644 --- a/src/sage/libs/singular/polynomial.pyx +++ b/src/sage/libs/singular/polynomial.pyx @@ -5,16 +5,15 @@ AUTHOR: - Martin Albrecht (2009-07): refactoring """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Martin Albrecht # # 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/ +# **************************************************************************** from cysignals.signals cimport sig_on, sig_off @@ -22,7 +21,7 @@ cdef extern from *: # hack to get at cython macro int unlikely(int) import re -plusminus_pattern = re.compile("([^\(^])([\+\-])") +plusminus_pattern = re.compile(r"([^\(^])([\+\-])") parenthvar_pattern = re.compile(r"\(([a-zA-Z][a-zA-Z0-9]*)\)") from sage.cpython.string cimport bytes_to_str, str_to_bytes diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index 4e10184fd3e..62fc5710d6f 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -29,7 +29,7 @@ # 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/ # ***************************************************************************** # Lazy import from examples folders: diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 69744a312a5..689760625da 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -271,14 +271,14 @@ """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2021 Michael Jung # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ -#****************************************************************************** +# ***************************************************************************** from sage.algebras.finite_gca import FiniteGCAlgebra from sage.combinat.free_module import IndexedFreeModuleElement @@ -693,10 +693,10 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): Algebra of characteristic cohomology classes of the Tangent bundle TM over the 8-dimensional differentiable manifold M sage: CR.gens() - [Characteristic cohomology class (p_1)(TM) of the Tangent bundle TM over + (Characteristic cohomology class (p_1)(TM) of the Tangent bundle TM over the 8-dimensional differentiable manifold M, Characteristic cohomology class (p_2)(TM) of the Tangent bundle TM - over the 8-dimensional differentiable manifold M] + over the 8-dimensional differentiable manifold M) The default base ring is `\QQ`:: @@ -712,12 +712,12 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): complex vector bundle E -> M of rank 2 over the base space 4-dimensional differentiable manifold M sage: CR_E.gens() - [Characteristic cohomology class (c_1)(E) of the Differentiable complex + (Characteristic cohomology class (c_1)(E) of the Differentiable complex vector bundle E -> M of rank 2 over the base space 4-dimensional differentiable manifold M, Characteristic cohomology class (c_2)(E) of the Differentiable complex vector bundle E -> M of rank 2 over the base space - 4-dimensional differentiable manifold M] + 4-dimensional differentiable manifold M) Characteristic cohomology class ring over an oriented manifold:: @@ -727,9 +727,9 @@ class CharacteristicCohomologyClassRing(FiniteGCAlgebra): True sage: CR = TS2.characteristic_cohomology_class_ring() sage: CR.gens() - [Characteristic cohomology class (e)(TS^2) of the Tangent bundle TS^2 + (Characteristic cohomology class (e)(TS^2) of the Tangent bundle TS^2 over the 2-sphere S^2 of radius 1 smoothly embedded in the Euclidean - space E^3] + space E^3,) """ Element = CharacteristicCohomologyClassRingElement @@ -1043,6 +1043,7 @@ def _repr_(self): repr = f'Algebra of characteristic cohomology classes of the {vbundle}' return repr + # ***************************************************************************** # ALGORITHMS # ***************************************************************************** @@ -1103,6 +1104,7 @@ def multiplicative_sequence(q, n=None): for p in Partitions(k)}) return Sym.e()(mon_pol) + def additive_sequence(q, k, n=None): r""" Turn the polynomial ``q`` into its additive sequence. @@ -1845,4 +1847,4 @@ def get_gen_pow(self, nab, i, n): return nab._domain._one_scalar_field # no computation necessary if i == 0: return fast_wedge_power(EulerAlgorithm().get(nab)[0], n) - return fast_wedge_power(PontryaginAlgorithm().get(nab)[i-1], n) + return fast_wedge_power(PontryaginAlgorithm().get(nab)[i - 1], n) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index 0aa86ce31d5..37feeaa7650 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -12,11 +12,14 @@ (in practice, not parallelizable) differentiable manifold `M` - :class:`DiffFormFreeModule` for differential forms with values on a parallelizable manifold `M` + (the subclass :class:`VectorFieldDualFreeModule` implements the special + case of differential 1-forms on a parallelizable manifold `M`) AUTHORS: - Eric Gourgoulhon (2015): initial version - Travis Scrimshaw (2016): review tweaks +- Matthias Koeppe (2022): :class:`VectorFieldDualFreeModule` REFERENCES: @@ -25,8 +28,10 @@ """ # ***************************************************************************** -# Copyright (C) 2015 Eric Gourgoulhon -# Copyright (C) 2016 Travis Scrimshaw +# Copyright (C) 2015-2021 Eric Gourgoulhon +# 2016 Travis Scrimshaw +# 2020 Michael Jung +# 2022 Matthias Koeppe # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -575,6 +580,8 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): is not parallelizable, the class :class:`DiffFormModule` must be used instead. + For the special case of 1-forms, use the class :class:`VectorFieldDualFreeModule`. + INPUT: - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector @@ -661,18 +668,12 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: L1 is XM.dual() True - Since any tensor field of type `(0,1)` is a 1-form, there is a coercion - map from the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: + Since any tensor field of type `(0,1)` is a 1-form, it is also equal to + the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: sage: T01 = M.tensor_field_module((0,1)) ; T01 - Free module T^(0,1)(M) of type-(0,1) tensors fields on the - 3-dimensional differentiable manifold M - sage: L1.has_coerce_map_from(T01) - True - - There is also a coercion map in the reverse direction:: - - sage: T01.has_coerce_map_from(L1) + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M + sage: L1 is T01 True For a degree `p \geq 2`, the coercion holds only in the direction @@ -686,26 +687,6 @@ class DiffFormFreeModule(ExtPowerDualFreeModule): sage: A.has_coerce_map_from(T02) False - The coercion map `T^{(0,1)}(M) \rightarrow \Omega^1(M)` in action:: - - sage: b = T01([-x,2,3*y], name='b'); b - Tensor field b of type (0,1) on the 3-dimensional differentiable - manifold M - sage: b.display() - b = -x dx + 2 dy + 3*y dz - sage: lb = L1(b) ; lb - 1-form b on the 3-dimensional differentiable manifold M - sage: lb.display() - b = -x dx + 2 dy + 3*y dz - - The coercion map `\Omega^1(M) \rightarrow T^{(0,1)}(M)` in action:: - - sage: tlb = T01(lb); tlb - Tensor field b of type (0,1) on - the 3-dimensional differentiable manifold M - sage: tlb == b - True - The coercion map `\Omega^2(M) \rightarrow T^{(0,2)}(M)` in action:: sage: T02 = M.tensor_field_module((0,2)) ; T02 @@ -905,3 +886,167 @@ def _repr_(self): description += "along the {} mapped into the {}".format( self._domain, self._ambient_domain) return description + + +class VectorFieldDualFreeModule(DiffFormFreeModule): + r""" + Free module of differential 1-forms along a differentiable manifold `U` + with values on a parallelizable manifold `M`. + + Given a differentiable manifold `U` and a differentiable map + `\Phi:\; U \rightarrow M` to a parallelizable manifold `M` of dimension + `n`, the set `\Omega^1(U, \Phi)` of 1-forms along `U` with values on `M` + is a free module of rank `n` over `C^k(U)`, the commutative + algebra of differentiable scalar fields on `U` (see + :class:`~sage.manifolds.differentiable.scalarfield_algebra.DiffScalarFieldAlgebra`). + The standard case of 1-forms *on* a differentiable manifold `M` + corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are + `\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an + open interval of `\RR`). + + .. NOTE:: + + This class implements `\Omega^1(U, \Phi)` in the case where `M` is + parallelizable; `\Omega^1(U, \Phi)` is then a *free* module. If `M` + is not parallelizable, the class :class:`DiffFormModule` must be used + instead. + + INPUT: + + - ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector + fields along `U` associated with the map `\Phi: U \rightarrow V` + + EXAMPLES: + + Free module of 1-forms on a parallelizable 3-dimensional manifold:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: XM = M.vector_field_module() ; XM + Free module X(M) of vector fields on the 3-dimensional differentiable + manifold M + sage: A = M.diff_form_module(1) ; A + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M + sage: latex(A) + \Omega^{1}\left(M\right) + + ``A`` is nothing but the dual of ``XM`` (the free module of vector fields on `M`) + and thus also equal to the 1st exterior + power of the dual, i.e. we have `\Omega^{1}(M) = \Lambda^1(\mathfrak{X}(M)^*) + = \mathfrak{X}(M)^*` (See + :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`):: + + sage: A is XM.dual_exterior_power(1) + True + + `\Omega^{1}(M)` is a module over the algebra `C^k(M)` of (differentiable) + scalar fields on `M`:: + + sage: A.category() + Category of finite dimensional modules over Algebra of differentiable + scalar fields on the 3-dimensional differentiable manifold M + sage: CM = M.scalar_field_algebra() ; CM + Algebra of differentiable scalar fields on the 3-dimensional + differentiable manifold M + sage: A in Modules(CM) + True + sage: A.base_ring() + Algebra of differentiable scalar fields on + the 3-dimensional differentiable manifold M + sage: A.base_module() + Free module X(M) of vector fields on + the 3-dimensional differentiable manifold M + sage: A.base_module() is XM + True + sage: A.rank() + 3 + + Elements can be constructed from `A`. In particular, ``0`` yields + the zero element of `A`:: + + sage: A(0) + 1-form zero on the 3-dimensional differentiable manifold M + sage: A(0) is A.zero() + True + + while non-zero elements are constructed by providing their components + in a given vector frame:: + + sage: comp = [3*x,-z,4] + sage: a = A(comp, frame=X.frame(), name='a') ; a + 1-form a on the 3-dimensional differentiable manifold M + sage: a.display() + a = 3*x dx - z dy + 4 dz + + An alternative is to construct the 1-form from an empty list of + components and to set the nonzero nonredundant components afterwards:: + + sage: a = A([], name='a') + sage: a[0] = 3*x # component in the manifold's default frame + sage: a[1] = -z + sage: a[2] = 4 + sage: a.display() + a = 3*x dx - z dy + 4 dz + + Since any tensor field of type `(0,1)` is a 1-form, there is a coercion + map from the set `T^{(0,1)}(M)` of such tensors to `\Omega^1(M)`:: + + sage: T01 = M.tensor_field_module((0,1)) ; T01 + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M + sage: A.has_coerce_map_from(T01) + True + + There is also a coercion map in the reverse direction:: + + sage: T01.has_coerce_map_from(A) + True + + The coercion map `T^{(0,1)}(M) \rightarrow \Omega^1(M)` in action:: + + sage: b = T01([-x,2,3*y], name='b'); b + 1-form b on the 3-dimensional differentiable manifold M + sage: b.display() + b = -x dx + 2 dy + 3*y dz + sage: lb = A(b) ; lb + 1-form b on the 3-dimensional differentiable manifold M + sage: lb.display() + b = -x dx + 2 dy + 3*y dz + + The coercion map `\Omega^1(M) \rightarrow T^{(0,1)}(M)` in action:: + + sage: tlb = T01(lb); tlb + 1-form b on the 3-dimensional differentiable manifold M + sage: tlb == b + True + """ + + def __init__(self, vector_field_module): + r""" + Construct a free module of differential 1-forms. + + TESTS:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: A = M.vector_field_module().dual(); A + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M + sage: TestSuite(A).run() + + """ + DiffFormFreeModule.__init__(self, vector_field_module, 1) + + def tensor_type(self): + r""" + Return the tensor type of ``self``. + + EXAMPLES:: + + sage: M = Manifold(3, 'M') + sage: X. = M.chart() + sage: A = M.vector_field_module().dual(); A + Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M + sage: A.tensor_type() + (0, 1) + + """ + return (0, 1) diff --git a/src/sage/manifolds/differentiable/examples/euclidean.py b/src/sage/manifolds/differentiable/examples/euclidean.py index 8b3cb23531d..9528d5a5f8a 100644 --- a/src/sage/manifolds/differentiable/examples/euclidean.py +++ b/src/sage/manifolds/differentiable/examples/euclidean.py @@ -717,7 +717,7 @@ def __classcall_private__(cls, n=None, name=None, latex_name=None, start_index=start_index, unique_tag=unique_tag) - return super(cls, EuclideanSpace).__classcall__(cls, + return super().__classcall__(cls, n, name=name, latex_name=latex_name, coordinates=coordinates, symbols=symbols, metric_name=metric_name, diff --git a/src/sage/manifolds/differentiable/examples/real_line.py b/src/sage/manifolds/differentiable/examples/real_line.py index 35636dc0bd7..10a44c7e149 100644 --- a/src/sage/manifolds/differentiable/examples/real_line.py +++ b/src/sage/manifolds/differentiable/examples/real_line.py @@ -320,10 +320,10 @@ def __classcall_private__(cls, lower, upper, ambient_interval=None, coordinate = None names = None start_index = 0 - return super(cls, OpenInterval).__classcall__(cls, lower, upper, - ambient_interval=ambient_interval, name=name, - latex_name=latex_name, coordinate=coordinate, - names=names, start_index=start_index) + return super().__classcall__(cls, lower, upper, + ambient_interval=ambient_interval, name=name, + latex_name=latex_name, coordinate=coordinate, + names=names, start_index=start_index) def __init__(self, lower, upper, ambient_interval=None, name=None, latex_name=None, @@ -495,9 +495,9 @@ def _element_constructor_(self, coords=None, chart=None, name=None, """ if coords in SR: coords = (coords,) - return super(OpenInterval, self)._element_constructor_(coords=coords, - chart=chart, name=name, latex_name=latex_name, - check_coords=check_coords) + return super()._element_constructor_(coords=coords, + chart=chart, name=name, latex_name=latex_name, + check_coords=check_coords) def _Hom_(self, other, category=None): r""" @@ -879,10 +879,10 @@ def __classcall__(cls, name=unicode_mathbbR, latex_name=r'\Bold{R}', True """ - return super(cls, RealLine).__classcall__(cls, name=name, - latex_name=latex_name, - coordinate=coordinate, - names=names, start_index=start_index) + return super().__classcall__(cls, name=name, + latex_name=latex_name, + coordinate=coordinate, + names=names, start_index=start_index) def __init__(self, name=unicode_mathbbR, latex_name=r'\Bold{R}', coordinate=None, names=None, start_index=0): diff --git a/src/sage/manifolds/differentiable/examples/sphere.py b/src/sage/manifolds/differentiable/examples/sphere.py index 1183448251a..4ccc6f7440b 100644 --- a/src/sage/manifolds/differentiable/examples/sphere.py +++ b/src/sage/manifolds/differentiable/examples/sphere.py @@ -320,14 +320,14 @@ def __classcall_private__(cls, n=None, radius=1, ambient_space=None, from sage.misc.prandom import getrandbits from time import time if unique_tag is None: - unique_tag = getrandbits(128)*time() - - return super(cls, Sphere).__classcall__(cls, n, radius=radius, - ambient_space=ambient_space, - center=center, - name=name, latex_name=latex_name, - coordinates=coordinates, names=names, - unique_tag=unique_tag) + unique_tag = getrandbits(128) * time() + + return super().__classcall__(cls, n, radius=radius, + ambient_space=ambient_space, + center=center, + name=name, latex_name=latex_name, + coordinates=coordinates, names=names, + unique_tag=unique_tag) def __init__(self, n, radius=1, ambient_space=None, center=None, name=None, latex_name=None, coordinates='spherical', names=None, diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index 7fa589be987..d650d4eb712 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -1438,9 +1438,9 @@ def tensor_field_module(self, tensor_type, dest_map=None): Free module T^(2,1)(U) of type-(2,1) tensors fields on the Open subset U of the 3-dimensional differentiable manifold M sage: TU.category() - Category of finite dimensional modules over Algebra of - differentiable scalar fields on the Open subset U of the - 3-dimensional differentiable manifold M + Category of tensor products of finite dimensional modules + over Algebra of differentiable scalar fields + on the Open subset U of the 3-dimensional differentiable manifold M sage: TU.base_ring() Algebra of differentiable scalar fields on the Open subset U of the 3-dimensional differentiable manifold M diff --git a/src/sage/manifolds/differentiable/tensorfield_module.py b/src/sage/manifolds/differentiable/tensorfield_module.py index d68264a472c..cbc73f9e520 100644 --- a/src/sage/manifolds/differentiable/tensorfield_module.py +++ b/src/sage/manifolds/differentiable/tensorfield_module.py @@ -652,8 +652,8 @@ class TensorFieldFreeModule(TensorFreeModule): `T^{(2,0)}(\RR^3)` is a module over the algebra `C^k(\RR^3)`:: sage: T20.category() - Category of finite dimensional modules over Algebra of differentiable - scalar fields on the 3-dimensional differentiable manifold R^3 + Category of tensor products of finite dimensional modules over + Algebra of differentiable scalar fields on the 3-dimensional differentiable manifold R^3 sage: T20.base_ring() is M.scalar_field_algebra() True diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 1e097907967..580eec814ab 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -28,9 +28,14 @@ """ # ****************************************************************************** -# Copyright (C) 2015 Eric Gourgoulhon -# Copyright (C) 2015 Michal Bejger -# Copyright (C) 2016 Travis Scrimshaw +# Copyright (C) 2015-2021 Eric Gourgoulhon +# 2015 Michal Bejger +# 2016 Travis Scrimshaw +# 2018 Florentin Jaffredo +# 2019 Hans Fotsing Tetsing +# 2020 Michael Jung +# 2020-2022 Matthias Koeppe +# 2021-2022 Tobias Diez # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of @@ -501,7 +506,7 @@ def destination_map(self): """ return self._dest_map - def tensor_module(self, k, l): + def tensor_module(self, k, l, *, sym=None, antisym=None): r""" Return the module of type-`(k,l)` tensors on ``self``. @@ -547,11 +552,16 @@ def tensor_module(self, k, l): for more examples and documentation. """ - from sage.manifolds.differentiable.tensorfield_module import \ + if sym or antisym: + raise NotImplementedError + try: + return self._tensor_modules[(k,l)] + except KeyError: + from sage.manifolds.differentiable.tensorfield_module import \ TensorFieldModule - if (k,l) not in self._tensor_modules: - self._tensor_modules[(k,l)] = TensorFieldModule(self, (k,l)) - return self._tensor_modules[(k,l)] + T = TensorFieldModule(self, (k,l)) + self._tensor_modules[(k,l)] = T + return T def exterior_power(self, p): r""" @@ -600,13 +610,17 @@ def exterior_power(self, p): for more examples and documentation. """ - from sage.manifolds.differentiable.multivector_module import \ + try: + return self._exterior_powers[p] + except KeyError: + if p == 0: + L = self._ring + else: + from sage.manifolds.differentiable.multivector_module import \ MultivectorModule - if p == 0: - return self._ring - if p not in self._exterior_powers: - self._exterior_powers[p] = MultivectorModule(self, p) - return self._exterior_powers[p] + L = MultivectorModule(self, p) + self._exterior_powers[p] = L + return L def dual_exterior_power(self, p): r""" @@ -654,13 +668,17 @@ def dual_exterior_power(self, p): for more examples and documentation. """ - from sage.manifolds.differentiable.diff_form_module import \ + try: + return self._dual_exterior_powers[p] + except KeyError: + if p == 0: + L = self._ring + else: + from sage.manifolds.differentiable.diff_form_module import \ DiffFormModule - if p == 0: - return self._ring - if p not in self._dual_exterior_powers: - self._dual_exterior_powers[p] = DiffFormModule(self, p) - return self._dual_exterior_powers[p] + L = DiffFormModule(self, p) + self._dual_exterior_powers[p] = L + return L def dual(self): r""" @@ -1715,7 +1733,7 @@ def destination_map(self) -> DiffMap: """ return self._dest_map - def tensor_module(self, k, l): + def tensor_module(self, k, l, *, sym=None, antisym=None): r""" Return the free module of all tensors of type `(k, l)` defined on ``self``. @@ -1764,11 +1782,15 @@ def tensor_module(self, k, l): for more examples and documentation. """ + if sym or antisym: + raise NotImplementedError try: return self._tensor_modules[(k,l)] except KeyError: if (k, l) == (1, 0): T = self + elif (k, l) == (0, 1): + T = self.dual() else: from sage.manifolds.differentiable.tensorfield_module import \ TensorFieldFreeModule @@ -1868,8 +1890,7 @@ def dual_exterior_power(self, p): Free module Omega^2(M) of 2-forms on the 2-dimensional differentiable manifold M sage: XM.dual_exterior_power(1) - Free module Omega^1(M) of 1-forms on the 2-dimensional - differentiable manifold M + Free module Omega^1(M) of 1-forms on the 2-dimensional differentiable manifold M sage: XM.dual_exterior_power(1) is XM.dual() True sage: XM.dual_exterior_power(0) @@ -1889,6 +1910,10 @@ def dual_exterior_power(self, p): except KeyError: if p == 0: L = self._ring + elif p == 1: + from sage.manifolds.differentiable.diff_form_module import \ + VectorFieldDualFreeModule + L = VectorFieldDualFreeModule(self) else: from sage.manifolds.differentiable.diff_form_module import \ DiffFormFreeModule @@ -2010,7 +2035,7 @@ def basis(self, symbol=None, latex_symbol=None, from_frame=None, symbol_dual=symbol_dual, latex_symbol_dual=latex_symbol_dual) - def tensor(self, tensor_type, name=None, latex_name=None, sym=None, + def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None, specific_type=None): r""" Construct a tensor on ``self``. diff --git a/src/sage/manifolds/differentiable/vectorframe.py b/src/sage/manifolds/differentiable/vectorframe.py index 6df9c54c0d1..8f8c26c0c61 100644 --- a/src/sage/manifolds/differentiable/vectorframe.py +++ b/src/sage/manifolds/differentiable/vectorframe.py @@ -452,10 +452,10 @@ def set_name(self, symbol, latex_symbol=None, indices=None, \left(M, \left(e^{\xi},e^{\zeta}\right)\right) """ - super(CoFrame, self).set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, + indices=indices, + latex_indices=latex_indices, + index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain self._name = "({}, {})".format(self._domain._name, self._name) @@ -672,12 +672,12 @@ def __classcall_private__(cls, vector_field_module, symbol, symbol_dual = tuple(symbol_dual) if isinstance(latex_symbol_dual, list): latex_symbol_dual = tuple(latex_symbol_dual) - return super(VectorFrame, cls).__classcall__(cls, vector_field_module, - symbol, latex_symbol=latex_symbol, - from_frame=from_frame, indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + return super().__classcall__(cls, vector_field_module, + symbol, latex_symbol=latex_symbol, + from_frame=from_frame, indices=indices, + latex_indices=latex_indices, + symbol_dual=symbol_dual, + latex_symbol_dual=latex_symbol_dual) def __init__(self, vector_field_module, symbol, latex_symbol=None, from_frame=None, indices=None, latex_indices=None, @@ -1570,10 +1570,10 @@ def set_name(self, symbol, latex_symbol=None, indices=None, \left(M, \left(E_{\alpha},E_{\beta}\right)\right) """ - super(VectorFrame, self).set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, + indices=indices, + latex_indices=latex_indices, + index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain self._name = "({}, {})".format(self._domain._name, self._name) diff --git a/src/sage/manifolds/local_frame.py b/src/sage/manifolds/local_frame.py index 4d7db5c7d55..fffe607efda 100644 --- a/src/sage/manifolds/local_frame.py +++ b/src/sage/manifolds/local_frame.py @@ -162,20 +162,21 @@ """ -#****************************************************************************** +# ***************************************************************************** # Copyright (C) 2013-2018 Eric Gourgoulhon # Copyright (C) 2019 Michael Jung # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.tensor.modules.free_module_basis import (FreeModuleBasis, FreeModuleCoBasis) from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule + class LocalCoFrame(FreeModuleCoBasis): r""" Local coframe on a vector bundle. @@ -398,10 +399,10 @@ def set_name(self, symbol, latex_symbol=None, indices=None, \left(E|_{M}, \left(e^{\xi},e^{\zeta}\right)\right) """ - super(LocalCoFrame, self).set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, + indices=indices, + latex_indices=latex_indices, + index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain self._name = "({}|_{}, {})".format(self._vbundle._name, @@ -597,12 +598,12 @@ def __classcall_private__(cls, section_module, symbol, symbol_dual = tuple(symbol_dual) if isinstance(latex_symbol_dual, list): latex_symbol_dual = tuple(latex_symbol_dual) - return super(LocalFrame, cls).__classcall__(cls, section_module, - symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - symbol_dual=symbol_dual, - latex_symbol_dual=latex_symbol_dual) + return super().__classcall__(cls, section_module, + symbol, latex_symbol=latex_symbol, + indices=indices, + latex_indices=latex_indices, + symbol_dual=symbol_dual, + latex_symbol_dual=latex_symbol_dual) def __init__(self, section_module, symbol, latex_symbol=None, indices=None, latex_indices=None, symbol_dual=None, latex_symbol_dual=None): @@ -1239,10 +1240,10 @@ def set_name(self, symbol, latex_symbol=None, indices=None, \left(E|_{M}, \left(E_{\alpha},E_{\beta}\right)\right) """ - super(LocalFrame, self).set_name(symbol, latex_symbol=latex_symbol, - indices=indices, - latex_indices=latex_indices, - index_position=index_position) + super().set_name(symbol, latex_symbol=latex_symbol, + indices=indices, + latex_indices=latex_indices, + index_position=index_position) if include_domain: # Redefinition of the name and the LaTeX name to include the domain self._name = "({}|_{}, {})".format(self._vbundle._name, diff --git a/src/sage/manifolds/topological_submanifold.py b/src/sage/manifolds/topological_submanifold.py index 828b97703f5..314a6a16a1b 100644 --- a/src/sage/manifolds/topological_submanifold.py +++ b/src/sage/manifolds/topological_submanifold.py @@ -294,8 +294,7 @@ def open_subset(self, name, latex_name=None, coord_def={}, supersets=None): OUTPUT: - - the open subset, as an instance of - :class:`~sage.manifolds.manifold.topological_submanifold.TopologicalSubmanifold` + - the open subset, as an instance of :class:`TopologicalSubmanifold` EXAMPLES:: diff --git a/src/sage/manifolds/utilities.py b/src/sage/manifolds/utilities.py index 75a07519b0d..de83d63326f 100644 --- a/src/sage/manifolds/utilities.py +++ b/src/sage/manifolds/utilities.py @@ -204,7 +204,8 @@ def arithmetic(self, ex, operator): simpl = SR(1)/simpl return simpl # If operator is not a square root, we default to ExpressionTreeWalker: - return super(SimplifySqrtReal, self).arithmetic(ex, operator) + return super().arithmetic(ex, operator) + class SimplifyAbsTrig(ExpressionTreeWalker): r""" @@ -340,7 +341,7 @@ def composition(self, ex, operator): ex = -cos(x) return ex # If no pattern is found, we default to ExpressionTreeWalker: - return super(SimplifyAbsTrig, self).composition(ex, operator) + return super().composition(ex, operator) def simplify_sqrt_real(expr): diff --git a/src/sage/matrix/benchmark.py b/src/sage/matrix/benchmark.py index 86d09a63a49..811a1cbfc98 100644 --- a/src/sage/matrix/benchmark.py +++ b/src/sage/matrix/benchmark.py @@ -1229,12 +1229,10 @@ def nullspace_RDF(n=300, min=0, max=10, system='sage'): t := Cputime(); K := Kernel(A); s := Cputime(t); -"""%(n,min,max) +""" % (n, min, max) if verbose: print(code) magma.eval(code) return float(magma.eval('s')) else: - raise ValueError('unknown system "%s"'%system) - - + raise ValueError('unknown system "%s"' % system) diff --git a/src/sage/matrix/matrix_integer_dense_saturation.py b/src/sage/matrix/matrix_integer_dense_saturation.py index 9ac854ea2d1..01621f6844f 100644 --- a/src/sage/matrix/matrix_integer_dense_saturation.py +++ b/src/sage/matrix/matrix_integer_dense_saturation.py @@ -339,13 +339,11 @@ def index_in_saturation(A, proof=True): """ r = A.rank() if r == 0: - return ZZ(1) + return ZZ.one() if r < A.nrows(): A = A.hermite_form(proof=proof, include_zero_rows=False) if A.is_square(): return abs(A.determinant(proof=proof)) A = A.transpose() - A = A.hermite_form(proof=proof,include_zero_rows=False) + A = A.hermite_form(proof=proof, include_zero_rows=False) return abs(A.determinant(proof=proof)) - - diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 26f058d3aeb..cfb8ce85931 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -49,7 +49,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.misc.superseded import deprecated_function_alias - +from sage.misc.persist import register_unpickle_override from sage.categories.rings import Rings from sage.categories.fields import Fields from sage.categories.enumerated_sets import EnumeratedSets @@ -406,7 +406,6 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): return Matrix_generic_sparse - class MatrixSpace(UniqueRepresentation, Parent): """ The space of matrices of given size and base ring @@ -544,10 +543,10 @@ def __classcall__(cls, base_ring, nrows, ncols=None, sparse=False, implementatio sage: class MyMatrixSpace(MatrixSpace): ....: @staticmethod ....: def __classcall__(cls, base_ring, nrows, ncols=None, my_option=True, sparse=False, implementation=None): - ....: return super(MyMatrixSpace, cls).__classcall__(cls, base_ring, nrows, ncols=ncols, my_option=my_option, sparse=sparse, implementation=implementation) + ....: return super().__classcall__(cls, base_ring, nrows, ncols=ncols, my_option=my_option, sparse=sparse, implementation=implementation) ....: ....: def __init__(self, base_ring, nrows, ncols, sparse, implementation, my_option=True): - ....: super(MyMatrixSpace, self).__init__(base_ring, nrows, ncols, sparse, implementation) + ....: super().__init__(base_ring, nrows, ncols, sparse, implementation) ....: self._my_option = my_option sage: MS1 = MyMatrixSpace(ZZ, 2) @@ -558,7 +557,7 @@ def __classcall__(cls, base_ring, nrows, ncols=None, sparse=False, implementatio False """ if base_ring not in _Rings: - raise TypeError("base_ring (=%s) must be a ring"%base_ring) + raise TypeError("base_ring (=%s) must be a ring" % base_ring) nrows = int(nrows) if ncols is None: ncols = nrows @@ -574,8 +573,8 @@ def __classcall__(cls, base_ring, nrows, ncols=None, sparse=False, implementatio raise OverflowError("number of rows and columns may be at most %s" % sys.maxsize) matrix_cls = get_matrix_class(base_ring, nrows, ncols, sparse, implementation) - return super(MatrixSpace, cls).__classcall__( - cls, base_ring, nrows, ncols, sparse, matrix_cls, **kwds) + return super().__classcall__(cls, base_ring, nrows, + ncols, sparse, matrix_cls, **kwds) def __init__(self, base_ring, nrows, ncols, sparse, implementation): r""" @@ -1261,8 +1260,8 @@ def _repr_(self): s = "sparse" else: s = "dense" - s = "Full MatrixSpace of %s by %s %s matrices over %s"%( - self.__nrows, self.__ncols, s, self.base_ring()) + s = "Full MatrixSpace of %s by %s %s matrices over %s" % ( + self.__nrows, self.__ncols, s, self.base_ring()) if not self._has_default_implementation(): s += " (using {})".format(self.Element.__name__) @@ -1283,7 +1282,7 @@ def _repr_option(self, key): """ if key == 'element_ascii_art': return self.__nrows > 1 - return super(MatrixSpace, self)._repr_option(key) + return super()._repr_option(key) def _latex_(self): r""" @@ -1295,8 +1294,8 @@ def _latex_(self): sage: latex(MS3) \mathrm{Mat}_{6\times 6}(\Bold{Q}) """ - return "\\mathrm{Mat}_{%s\\times %s}(%s)"%(self.nrows(), self.ncols(), - latex.latex(self.base_ring())) + return "\\mathrm{Mat}_{%s\\times %s}(%s)" % (self.nrows(), self.ncols(), + latex.latex(self.base_ring())) def __len__(self): """ @@ -1504,14 +1503,14 @@ def __iter__(self): ... NotImplementedError: len() of an infinite set """ - #Make sure that we can iterate over the base ring + # Make sure that we can iterate over the base ring base_ring = self.base_ring() base_iter = iter(base_ring) - number_of_entries = (self.__nrows*self.__ncols) + number_of_entries = (self.__nrows * self.__ncols) - #If the number of entries is zero, then just - #yield the empty matrix in that case and return + # If the number of entries is zero, then just + # yield the empty matrix in that case and return if number_of_entries == 0: yield self(0) return @@ -1519,11 +1518,11 @@ def __iter__(self): import sage.combinat.integer_vector if not base_ring.is_finite(): - #When the base ring is not finite, then we should go - #through and yield the matrices by "weight", which is - #the total number of iterations that need to be done - #on the base ring to reach the matrix. - base_elements = [ next(base_iter) ] + # When the base ring is not finite, then we should go + # through and yield the matrices by "weight", which is + # the total number of iterations that need to be done + # on the base ring to reach the matrix. + base_elements = [next(base_iter)] weight = 0 while True: for iv in sage.combinat.integer_vector.IntegerVectors(weight, number_of_entries): @@ -1579,7 +1578,7 @@ def __getitem__(self, x): """ if isinstance(x, (integer.Integer, int)): return self.list()[x] - return super(MatrixSpace, self).__getitem__(x) + return super().__getitem__(x) def basis(self): """ @@ -1639,7 +1638,6 @@ def dims(self): """ return (self.__nrows, self.__ncols) - def submodule(self, gens, check=True, already_echelonized=False, unitriangular=False, support_order=None, category=None, *args, **opts): @@ -1733,6 +1731,7 @@ def submodule(self, gens, check=True, already_echelonized=False, category=category, *args, **opts) from sage.misc.cachefunc import cached_method + @cached_method def identity_matrix(self): """ @@ -1903,7 +1902,7 @@ def gen(self, n): r = n // self.__ncols c = n - (r * self.__ncols) z = self.zero_matrix().__copy__() - z[r,c] = 1 + z[r, c] = 1 return z @cached_method @@ -2208,10 +2207,10 @@ def random_element(self, density=None, *args, **kwds): """ Z = self.zero_matrix().__copy__() if density is None: - Z.randomize(density=float(1), nonzero=kwds.pop('nonzero', False), \ + Z.randomize(density=float(1), nonzero=kwds.pop('nonzero', False), *args, **kwds) else: - Z.randomize(density=density, nonzero=kwds.pop('nonzero', True), \ + Z.randomize(density=density, nonzero=kwds.pop('nonzero', True), *args, **kwds) return Z @@ -2328,10 +2327,8 @@ def _magma_init_(self, magma): """ K = magma(self.base_ring()) if self.__nrows == self.__ncols: - s = 'MatrixAlgebra(%s,%s)'%(K.name(), self.__nrows) - else: - s = 'RMatrixSpace(%s,%s,%s)'%(K.name(), self.__nrows, self.__ncols) - return s + return 'MatrixAlgebra(%s,%s)' % (K.name(), self.__nrows) + return 'RMatrixSpace(%s,%s,%s)' % (K.name(), self.__nrows, self.__ncols) def _polymake_init_(self): r""" @@ -2384,6 +2381,7 @@ def _random_nonzero_element(self, *args, **kwds): rand_matrix = self.random_element(*args, **kwds) return rand_matrix + def dict_to_list(entries, nrows, ncols): r""" Given a dictionary of coordinate tuples, return the list given by @@ -2468,7 +2466,7 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check """ # Check that the empty 0x0 matrix is it's own inverse with det=1. ms00 = MatrixSpace(ring, 0, 0, sparse=sparse) - m00 = ms00(0) + m00 = ms00(0) assert(m00.determinant() == ring(1)) assert(m00.is_invertible()) assert(m00.inverse() == m00) @@ -2479,7 +2477,7 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check # computing the determinant raise the proper exception. for ms0 in [MatrixSpace(ring, 0, 3, sparse=sparse), MatrixSpace(ring, 3, 0, sparse=sparse)]: - mn0 = ms0(0) + mn0 = ms0(0) assert(not mn0.is_invertible()) try: d = mn0.determinant() @@ -2499,22 +2497,22 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check # Check that the null 1x1 matrix is not invertible and that det=0 ms1 = MatrixSpace(ring, 1, 1, sparse=sparse) - m0 = ms1(0) + m0 = ms1(0) assert(not m0.is_invertible()) assert(m0.determinant() == ring(0)) try: m0.inverse() res = False except (ZeroDivisionError, RuntimeError): - #FIXME: Make pynac throw a ZeroDivisionError on division by - #zero instead of a runtime Error + # FIXME: Make pynac throw a ZeroDivisionError on division by + # zero instead of a runtime Error res = True assert(res) if checkrank: assert(m0.rank() == 0) # Check that the identity 1x1 matrix is its own inverse with det=1 - m1 = ms1(1) + m1 = ms1(1) assert(m1.is_invertible()) assert(m1.determinant() == ring(1)) inv = m1.inverse() @@ -2529,10 +2527,13 @@ def _test_trivial_matrices_inverse(ring, sparse=True, implementation=None, check # Fix unpickling Matrix_modn_dense and Matrix_integer_2x2 lazy_import('sage.matrix.matrix_modn_dense_double', 'Matrix_modn_dense_double') lazy_import('sage.matrix.matrix_integer_dense', 'Matrix_integer_dense') -from sage.misc.persist import register_unpickle_override + + def _MatrixSpace_ZZ_2x2(): from sage.rings.integer_ring import ZZ - return MatrixSpace(ZZ,2) + return MatrixSpace(ZZ, 2) + + register_unpickle_override('sage.matrix.matrix_modn_dense', 'Matrix_modn_dense', Matrix_modn_dense_double) register_unpickle_override('sage.matrix.matrix_integer_2x2', diff --git a/src/sage/matrix/operation_table.py b/src/sage/matrix/operation_table.py index ff22a20d7c1..13f0a88822a 100644 --- a/src/sage/matrix/operation_table.py +++ b/src/sage/matrix/operation_table.py @@ -4,19 +4,19 @@ This module implements general operation tables, which are very matrix-like. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Rob Beezer # # 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/ +# **************************************************************************** from sage.structure.sage_object import SageObject + class OperationTable(SageObject): r""" An object that represents a binary operation as a table. diff --git a/src/sage/matroids/basis_exchange_matroid.pyx b/src/sage/matroids/basis_exchange_matroid.pyx index 7b72cd245df..5679814d32b 100644 --- a/src/sage/matroids/basis_exchange_matroid.pyx +++ b/src/sage/matroids/basis_exchange_matroid.pyx @@ -2115,7 +2115,7 @@ cdef class BasisExchangeMatroid(Matroid): return EQ[0] cpdef _is_isomorphism(self, other, morphism): - """ + r""" Version of is_isomorphism() that does no type checking. INPUT: diff --git a/src/sage/matroids/basis_matroid.pyx b/src/sage/matroids/basis_matroid.pyx index b8fd1cdc342..ff70add1ce2 100644 --- a/src/sage/matroids/basis_matroid.pyx +++ b/src/sage/matroids/basis_matroid.pyx @@ -1280,8 +1280,9 @@ cdef long set_to_index(bitset_t S): s = bitset_next(S, s + 1) return index + cdef index_to_set(bitset_t S, long index, long k, long n): - """ + r""" Compute the k-subset of `\{0, ..., n-1\}` of rank index """ bitset_clear(S) diff --git a/src/sage/matroids/extension.pyx b/src/sage/matroids/extension.pyx index f4f9d44516b..0408e60f86e 100644 --- a/src/sage/matroids/extension.pyx +++ b/src/sage/matroids/extension.pyx @@ -248,7 +248,7 @@ cdef class LinearSubclassesIter: cdef class LinearSubclasses: - """ + r""" An iterable set of linear subclasses of a matroid. Enumerate linear subclasses of a given matroid. A *linear subclass* is a @@ -412,7 +412,7 @@ cdef class LinearSubclasses: cdef class MatroidExtensions(LinearSubclasses): - """ + r""" An iterable set of single-element extensions of a given matroid. INPUT: diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 917017f6afe..0c9b0a1baff 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -761,7 +761,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): return {e: R[self._idx[e]] for e in self.groundset()} cpdef LeanMatrix _reduced_representation(self, B=None): - """ + r""" Return a reduced representation of the matroid, i.e. a matrix `R` such that `[I\ \ R]` represents the matroid. @@ -800,7 +800,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): # (field) isomorphism cpdef bint _is_field_isomorphism(self, LinearMatroid other, morphism): # not safe if self == other - """ + r""" Version of :meth:`` that does no type checking. @@ -966,7 +966,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): return self._is_field_isomorphism(other, morphism) cpdef is_field_isomorphism(self, other, morphism): - """ + r""" Test if a provided morphism induces a bijection between represented matroids. @@ -1322,7 +1322,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): return type(self)(reduced_matrix=M, groundset=rows + cols) cpdef dual(self): - """ + r""" Return the dual of the matroid. Let `M` be a matroid with ground set `E`. If `B` is the set of bases @@ -1354,7 +1354,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): return type(self)(reduced_matrix=R, groundset=cols + rows) cpdef has_line_minor(self, k, hyperlines=None, certificate=False): - """ + r""" Test if the matroid has a `U_{2, k}`-minor. The matroid `U_{2, k}` is a matroid on `k` elements in which every @@ -3130,7 +3130,7 @@ cdef class BinaryMatroid(LinearMatroid): self._one = GF2_one cpdef base_ring(self): - """ + r""" Return the base ring of the matrix representing the matroid, in this case `\GF{2}`. @@ -3308,7 +3308,7 @@ cdef class BinaryMatroid(LinearMatroid): return self._A.copy() # Deprecated Sage matrix operation cpdef LeanMatrix _reduced_representation(self, B=None): - """ + r""" Return a reduced representation of the matroid, i.e. a matrix `R` such that `[I\ \ R]` represents the matroid. @@ -4197,7 +4197,7 @@ cdef class TernaryMatroid(LinearMatroid): self._two = GF3_minus_one cpdef base_ring(self): - """ + r""" Return the base ring of the matrix representing the matroid, in this case `\GF{3}`. @@ -4381,7 +4381,7 @@ cdef class TernaryMatroid(LinearMatroid): return self._A.copy() # Deprecated Sage matrix operation cpdef LeanMatrix _reduced_representation(self, B=None): - """ + r""" Return a reduced representation of the matroid, i.e. a matrix `R` such that `[I\ \ R]` represents the matroid. @@ -4563,7 +4563,7 @@ cdef class TernaryMatroid(LinearMatroid): return self._t_invariant cpdef bicycle_dimension(self): - """ + r""" Return the bicycle dimension of the ternary matroid. The bicycle dimension of a linear subspace `V` is @@ -5096,7 +5096,7 @@ cdef class QuaternaryMatroid(LinearMatroid): self._x_one = (self._A)._x_one cpdef base_ring(self): - """ + r""" Return the base ring of the matrix representing the matroid, in this case `\GF{4}`. @@ -5273,7 +5273,7 @@ cdef class QuaternaryMatroid(LinearMatroid): return self._A.copy() # Deprecated Sage matrix operation cpdef LeanMatrix _reduced_representation(self, B=None): - """ + r""" Return a reduced representation of the matroid, i.e. a matrix `R` such that `[I\ \ R]` represents the matroid. @@ -5413,7 +5413,7 @@ cdef class QuaternaryMatroid(LinearMatroid): return self._q_invariant cpdef bicycle_dimension(self): - """ + r""" Return the bicycle dimension of the quaternary matroid. The bicycle dimension of a linear subspace `V` is @@ -5810,7 +5810,7 @@ cdef class RegularMatroid(LinearMatroid): return P cpdef base_ring(self): - """ + r""" Return the base ring of the matrix representing the matroid, in this case `\ZZ`. @@ -6230,7 +6230,7 @@ cdef class RegularMatroid(LinearMatroid): return {e:idx[m[str(e)]] for e in self.groundset() if str(e) in m} cpdef has_line_minor(self, k, hyperlines=None, certificate=False): - """ + r""" Test if the matroid has a `U_{2, k}`-minor. The matroid `U_{2, k}` is a matroid on `k` elements in which every diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index 8263860cbec..7378d250e44 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -3150,7 +3150,7 @@ cdef class Matroid(SageObject): return Polyhedron(vertices) def independence_matroid_polytope(self): - """ + r""" Return the independence matroid polytope of ``self``. This is defined as the convex hull of the vertices @@ -3430,7 +3430,7 @@ cdef class Matroid(SageObject): return self._is_isomorphism(other, morphism) cpdef is_isomorphism(self, other, morphism): - """ + r""" Test if a provided morphism induces a matroid isomorphism. A *morphism* is a map from the groundset of ``self`` to the groundset @@ -3553,7 +3553,7 @@ cdef class Matroid(SageObject): return self._is_isomorphism(other, mf) cpdef _is_isomorphism(self, other, morphism): - """ + r""" Version of is_isomorphism() that does no type checking. INPUT: @@ -3942,7 +3942,7 @@ cdef class Matroid(SageObject): return self.delete(X) cpdef dual(self): - """ + r""" Return the dual of the matroid. Let `M` be a matroid with ground set `E`. If `B` is the set of bases @@ -4054,7 +4054,7 @@ cdef class Matroid(SageObject): return self._has_minor(N, certificate) cpdef has_line_minor(self, k, hyperlines=None, certificate=False): - """ + r""" Test if the matroid has a `U_{2, k}`-minor. The matroid `U_{2, k}` is a matroid on `k` elements in which every @@ -4125,7 +4125,7 @@ cdef class Matroid(SageObject): return self._has_line_minor(k, hyperlines, certificate) cpdef _has_line_minor(self, k, hyperlines, certificate=False): - """ + r""" Test if the matroid has a `U_{2, k}`-minor. Internal version that does no input checking. @@ -4313,7 +4313,7 @@ cdef class Matroid(SageObject): return self.dual().extension(element, subsets).dual() cpdef modular_cut(self, subsets): - """ + r""" Compute the modular cut generated by ``subsets``. A *modular cut* is a collection `C` of flats such that @@ -4403,7 +4403,7 @@ cdef class Matroid(SageObject): return final_list cpdef linear_subclasses(self, line_length=None, subsets=None): - """ + r""" Return an iterable set of linear subclasses of the matroid. A *linear subclass* is a set of hyperplanes (i.e. closed sets of rank @@ -4714,7 +4714,7 @@ cdef class Matroid(SageObject): return True cpdef is_cosimple(self): - """ + r""" Test if the matroid is cosimple. A matroid is *cosimple* if it contains no cocircuits of length 1 or 2. @@ -4791,7 +4791,7 @@ cdef class Matroid(SageObject): return components cpdef is_connected(self, certificate=False): - """ + r""" Test if the matroid is connected. A *separation* in a matroid is a partition `(X, Y)` of the @@ -7480,7 +7480,7 @@ cdef class Matroid(SageObject): return A cpdef tutte_polynomial(self, x=None, y=None): - """ + r""" Return the Tutte polynomial of the matroid. The *Tutte polynomial* of a matroid is the polynomial diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index 5eed16a8565..8d2c2f080d5 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -525,12 +525,12 @@ def import_statements(*objects, **kwds): if kwds: raise TypeError("Unexpected '{}' argument".format(next(iter(kwds)))) - def expand_comma_separated_names(object): - if isinstance(object, str): - for w in object.strip('()').split(','): + def expand_comma_separated_names(obj): + if isinstance(obj, str): + for w in obj.strip('()').split(','): yield w.strip() else: - yield object + yield obj for obj in itertools.chain.from_iterable(expand_comma_separated_names(object) for object in objects): diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index 35f09ba3063..2d4413cd1a3 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -68,7 +68,16 @@ from warnings import warn import inspect from . import sageinspect -from sage.features import FeatureNotPresentError + +# LazyImport.__repr__ uses try... except FeatureNotPresentError. +# This is defined in sage.features, provided by the distribution sagemath-environment. +try: + from sage.features import FeatureNotPresentError +except ImportError: + # If sage.features cannot be imported, then FeatureNotPresentError cannot + # be raised. In this case, use the empty tuple as the exception specification. + FeatureNotPresentError = () + cdef inline obj(x): if type(x) is LazyImport: @@ -252,6 +261,8 @@ cdef class LazyImport(): self._object = getattr(__import__(self._module, {}, {}, [self._name]), self._name) except ImportError as e: if self._feature: + # Avoid warnings from static type checkers by explicitly importing FeatureNotPresentError. + from sage.features import FeatureNotPresentError raise FeatureNotPresentError(self._feature, reason=f'Importing {self._name} failed: {e}') raise diff --git a/src/sage/misc/misc.py b/src/sage/misc/misc.py index c2c440daffb..bae968c42f3 100644 --- a/src/sage/misc/misc.py +++ b/src/sage/misc/misc.py @@ -548,7 +548,7 @@ def union(x, y=None): True """ from sage.misc.superseded import deprecation - deprecation(32096, "sage.misc.misc.union is deprecated, use 'list(set(x).union(y)' or a more suitable replacement") + deprecation(32096, "sage.misc.misc.union is deprecated, use 'list(set(x).union(y))' or a more suitable replacement") if y is None: return list(set(x)) return list(set(x).union(y)) diff --git a/src/sage/misc/sage_input.py b/src/sage/misc/sage_input.py index 24586170e4e..b49763dbf27 100644 --- a/src/sage/misc/sage_input.py +++ b/src/sage/misc/sage_input.py @@ -161,7 +161,7 @@ - Vincent Delecroix (2015-02): documentation formatting """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Carl Witty # 2015 Vincent Delecroix <20100.delecroix@gmail.com> # @@ -169,8 +169,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/ +# **************************************************************************** def sage_input(x, preparse=True, verify=False, allow_locals=False): @@ -240,7 +240,7 @@ def sage_input(x, preparse=True, verify=False, allow_locals=False): sage: sage_input((3, lambda x: x)) Traceback (most recent call last): ... - ValueError: Can't convert at 0x...> to sage_input form + ValueError: cannot convert at 0x...> to sage_input form But we can have :func:`sage_input` continue anyway, and return an input form for the rest of the expression, with ``allow_locals=True``.:: @@ -272,6 +272,7 @@ def sage_input(x, preparse=True, verify=False, allow_locals=False): return final_answer + class SageInputBuilder: r""" An instance of this class is passed to ``_sage_input_`` methods. @@ -427,7 +428,7 @@ def __call__(self, x, coerced=False): sage: sage_input(lambda x: x) Traceback (most recent call last): ... - ValueError: Can't convert at 0x...> to sage_input form + ValueError: cannot convert at 0x...> to sage_input form sage: sage_input(lambda x: x, allow_locals=True, verify=True) LOCALS: _sil1: at 0x...> @@ -519,7 +520,7 @@ def __call__(self, x, coerced=False): self._locals[loc_name] = x return SIE_literal_stringrep(self, loc_name) else: - raise ValueError("Can't convert {} to sage_input form".format(x)) + raise ValueError("cannot convert {} to sage_input form".format(x)) def preparse(self): r""" @@ -815,7 +816,7 @@ def dict(self, entries): """ if isinstance(entries, dict): entries = list(entries.items()) - entries = [(self(key),self(val)) for (key,val) in entries] + entries = [(self(key), self(val)) for (key, val) in entries] return SIE_dict(self, entries) def getattr(self, sie, attr): @@ -1077,7 +1078,7 @@ def prod(self, factors, simplify=False): neg = False break if isinstance(factor, SIE_literal_stringrep) and factor._sie_value == '1': - factors[i:i+1] = [] + factors[i:i + 1] = [] else: i += 1 if len(factors) == 0: @@ -1123,7 +1124,7 @@ def sum(self, terms, simplify=False): while i < len(terms): term = terms[i] if isinstance(term, SIE_literal_stringrep) and term._sie_value == '0': - terms[i:i+1] = [] + terms[i:i + 1] = [] else: i += 1 if len(terms) == 0: @@ -1174,6 +1175,7 @@ def result(self, e): else: return SageInputAnswer(sif._commands, sif.format(e, 0)) + # Python's precedence levels. Hand-transcribed from section 5.14 of # the Python 2 reference manual. In the Python 3 reference manual # this is section 6.16. @@ -1200,6 +1202,7 @@ def result(self, e): _prec_funcall = 40 _prec_atomic = 42 + class SageInputExpression(): r""" Subclasses of this class represent expressions for :func:`sage_input`. @@ -1687,6 +1690,7 @@ def _sie_format_statement(self, sif): result, prec = self._sie_format(sif) return result + class SIE_literal(SageInputExpression): r""" An abstract base class for ``literals`` (basically, values which @@ -1730,6 +1734,7 @@ def _sie_is_simple(self): # times in an expression, it might be better to do the replacement. return not self._sie_share + class SIE_literal_stringrep(SIE_literal): r""" Values in this class are leaves in a :func:`sage_input` expression @@ -1813,6 +1818,7 @@ def _sie_format(self, sif): """ return self._sie_value, _prec_atomic + class SIE_call(SageInputExpression): r""" This class represents a function-call node in a :func:`sage_input` @@ -2024,6 +2030,7 @@ def _sie_format(self, sif): key = sif.format(self._sie_key, 0) return '%s[%s]' % (coll, key), _prec_subscript + class SIE_getattr(SageInputExpression): r""" This class represents a getattr node in a :func:`sage_input` @@ -2222,6 +2229,7 @@ def _sie_format(self, sif): else: return '(%s)' % ', '.join(values), _prec_atomic + class SIE_dict(SageInputExpression): r""" This class represents a dict node in a :func:`sage_input` diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index be8f2527bde..fbca2defc20 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1018,14 +1018,14 @@ def split_string(s, quot): if s[i] == '\\': escaped = not escaped continue - if not escaped and s[i:i+l] == quot: - return s[:i], s[i+l:] + if not escaped and s[i:i + l] == quot: + return s[:i], s[i + l:] escaped = False raise SyntaxError("EOF while scanning string literal") # 1. s is a triple-quoted string if s.startswith('"""'): a, b = split_string(s[3:], '"""') - return '"""'+a+'"""', b.strip() + return '"""' + a + '"""', b.strip() if s.startswith('r"""'): a, b = split_string(s[4:], '"""') return 'r"""'+a+'"""', b.strip() @@ -1313,7 +1313,7 @@ def _sage_getargspec_cython(source): name = None nb_stars = 0 else: - raise SyntaxError("varargs can't be defined twice") + raise SyntaxError("varargs cannot be defined twice") elif nb_stars == 2: if keywords is None: keywords = name @@ -1323,7 +1323,7 @@ def _sage_getargspec_cython(source): name = None nb_stars = 0 else: - raise SyntaxError("varargs can't be defined twice") + raise SyntaxError("varargs cannot be defined twice") else: raise SyntaxError("variable declaration comprises at most two '*'") else: diff --git a/src/sage/misc/table.py b/src/sage/misc/table.py index 8610f06df0d..cbd8b083a6b 100644 --- a/src/sage/misc/table.py +++ b/src/sage/misc/table.py @@ -207,7 +207,7 @@ class table(SageObject): sage: table(rows=[[1,2,3], [4,5,6]], columns=[[0,0,0], [0,0,1024]]) Traceback (most recent call last): ... - ValueError: Don't set both 'rows' and 'columns' when defining a table. + ValueError: do not set both 'rows' and 'columns' when defining a table sage: table(columns=[[0,0,0], [0,0,1024]]) 0 0 @@ -251,7 +251,7 @@ def __init__(self, rows=None, columns=None, header_row=False, """ # If both rows and columns are set, raise an error. if rows and columns: - raise ValueError("Don't set both 'rows' and 'columns' when defining a table.") + raise ValueError("do not set both 'rows' and 'columns' when defining a table") # If columns is set, use its transpose for rows. if columns: rows = list(zip(*columns)) @@ -268,7 +268,7 @@ def __init__(self, rows=None, columns=None, header_row=False, self._options['header_column'] = True elif header_column: self._options['header_column'] = True - rows = [(a,) + tuple(x) for (a,x) in zip(header_column, rows)] + rows = [(a,) + tuple(x) for (a, x) in zip(header_column, rows)] else: self._options['header_column'] = False @@ -442,7 +442,7 @@ def _repr_(self): if len(rows) == 0 or nc == 0: return "" - frame_line = "+" + "+".join("-" * (x+2) for x in self._widths()) + "+\n" + frame_line = "+" + "+".join("-" * (x + 2) for x in self._widths()) + "+\n" if self._options['header_column'] and self._options['frame']: frame_line = "+" + frame_line[1:].replace('+', '++', 1) @@ -503,7 +503,7 @@ def _str_table_row(self, row, header_row=False): """ frame = self._options['frame'] widths = self._widths() - frame_line = "+" + "+".join("-" * (x+2) for x in widths) + "+\n" + frame_line = "+" + "+".join("-" * (x + 2) for x in widths) + "+\n" align = self._options['align'] if align == 'right': @@ -607,16 +607,16 @@ def _latex_(self): # table header s = "\\begin{tabular}{" s += frame_char + align_char + frame_char + head_col_char - s += frame_char.join([align_char] * (nc-1)) + s += frame_char.join([align_char] * (nc - 1)) s += frame_char + "}" + frame_str + "\n" # first row s += " & ".join(LatexExpr(x) if isinstance(x, (str, LatexExpr)) - else '$' + latex(x).strip() + '$' for x in rows[0]) + else '$' + latex(x).strip() + '$' for x in rows[0]) s += " \\\\" + frame_str + head_row_str + "\n" # other rows for row in rows[1:]: s += " & ".join(LatexExpr(x) if isinstance(x, (str, LatexExpr)) - else '$' + latex(x).strip() + '$' for x in row) + else '$' + latex(x).strip() + '$' for x in row) s += " \\\\" + frame_str + "\n" s += "\\end{tabular}" return s @@ -724,7 +724,7 @@ def _html_(self): if rows: s.writelines([ # If the table has < 100 rows, don't truncate the output in the notebook - '
\n' if len(rows) <= 100 else '
' , + '
\n' if len(rows) <= 100 else '
', '\n'.format(frame), '\n', ]) @@ -813,7 +813,7 @@ def _html_table_row(self, file, row, header=False): # first entry of row entry = row[0] if isinstance(entry, Graphics): - file.write(first_column_tag % entry.show(linkmode = True)) + file.write(first_column_tag % entry.show(linkmode=True)) elif isinstance(entry, str): file.write(first_column_tag % math_parse(entry)) else: @@ -822,7 +822,7 @@ def _html_table_row(self, file, row, header=False): # other entries for column in range(1, len(row)): if isinstance(row[column], Graphics): - file.write(column_tag % row[column].show(linkmode = True)) + file.write(column_tag % row[column].show(linkmode=True)) elif isinstance(row[column], str): file.write(column_tag % math_parse(row[column])) else: diff --git a/src/sage/misc/weak_dict.pyx b/src/sage/misc/weak_dict.pyx index ac7bf3bbbd2..d52bedacfa4 100644 --- a/src/sage/misc/weak_dict.pyx +++ b/src/sage/misc/weak_dict.pyx @@ -129,6 +129,8 @@ from cpython.object cimport PyObject_Hash from cpython.ref cimport Py_INCREF, Py_XINCREF, Py_XDECREF from sage.cpython.dict_del_by_value cimport * +from sage.misc.superseded import deprecation + cdef extern from "Python.h": PyObject* Py_None # we need this redefinition because we want to be able to call @@ -369,7 +371,7 @@ cdef class WeakValueDictionary(dict): True """ - return WeakValueDictionary(self.iteritems()) + return WeakValueDictionary(self.items()) def __deepcopy__(self, memo): """ @@ -403,7 +405,7 @@ cdef class WeakValueDictionary(dict): """ out = WeakValueDictionary() - for k,v in self.iteritems(): + for k,v in self.items(): out[deepcopy(k, memo)] = v return out @@ -526,7 +528,7 @@ cdef class WeakValueDictionary(dict): sage: _ = gc.collect() sage: len(D) 1 - sage: D.items() + sage: list(D.items()) [(2, Integer Ring)] Check that :trac:`15956` has been fixed, i.e., a ``TypeError`` is @@ -620,7 +622,7 @@ cdef class WeakValueDictionary(dict): KeyError: 'popitem(): weak value dictionary is empty' """ - for k,v in self.iteritems(): + for k,v in self.items(): del self[k] return k, v raise KeyError('popitem(): weak value dictionary is empty') @@ -811,6 +813,24 @@ cdef class WeakValueDictionary(dict): return list(iter(self)) def itervalues(self): + """ + Deprecated. + + EXAMPLES:: + + sage: import sage.misc.weak_dict + sage: class Vals(): pass + sage: L = [Vals() for _ in range(10)] + sage: D = sage.misc.weak_dict.WeakValueDictionary(enumerate(L)) + sage: T = list(D.itervalues()) + doctest:warning...: + DeprecationWarning: use values instead + See https://trac.sagemath.org/34488 for details. + """ + deprecation(34488, "use values instead") + return self.values() + + def values(self): """ Iterate over the values of this dictionary. @@ -842,7 +862,7 @@ cdef class WeakValueDictionary(dict): sage: del D[2] sage: del L[5] - sage: for v in sorted(D.itervalues()): + sage: for v in sorted(D.values()): ....: print(v) <0> <1> @@ -866,7 +886,7 @@ cdef class WeakValueDictionary(dict): finally: self._exit_iter() - def values(self): + def values_list(self): """ Return the list of values. @@ -893,13 +913,28 @@ cdef class WeakValueDictionary(dict): sage: del D[2] sage: del L[5] - sage: sorted(D.values()) + sage: sorted(D.values_list()) [<0>, <1>, <3>, <4>, <6>, <7>, <8>, <9>] - """ - return list(self.itervalues()) + return list(self.values()) def iteritems(self): + """ + EXAMPLES:: + + sage: import sage.misc.weak_dict + sage: class Vals(): pass + sage: L = [Vals() for _ in range(10)] + sage: D = sage.misc.weak_dict.WeakValueDictionary(enumerate(L)) + sage: T = list(D.iteritems()) + doctest:warning...: + DeprecationWarning: use items instead + See https://trac.sagemath.org/34488 for details. + """ + deprecation(34488, "use items instead") + return self.items() + + def items(self): """ Iterate over the items of this dictionary. @@ -946,7 +981,7 @@ cdef class WeakValueDictionary(dict): sage: del D[Keys(2)] sage: del L[5] - sage: for k,v in sorted(D.iteritems()): + sage: for k,v in sorted(D.items()): ....: print("{} {}".format(k, v)) [0] <0> [1] <1> @@ -970,7 +1005,7 @@ cdef class WeakValueDictionary(dict): finally: self._exit_iter() - def items(self): + def items_list(self): """ The key-value pairs of this dictionary. @@ -1022,7 +1057,7 @@ cdef class WeakValueDictionary(dict): ([8], <8>), ([9], <9>)] """ - return list(self.iteritems()) + return list(self.items()) cdef int _enter_iter(self) except -1: """ diff --git a/src/sage/modular/abvar/cuspidal_subgroup.py b/src/sage/modular/abvar/cuspidal_subgroup.py index a2769d7eff7..136f6cf23e4 100644 --- a/src/sage/modular/abvar/cuspidal_subgroup.py +++ b/src/sage/modular/abvar/cuspidal_subgroup.py @@ -241,10 +241,11 @@ def lattice(self): try: return self.__lattice except AttributeError: - lattice = self._compute_lattice(rational_only = False) + lattice = self._compute_lattice(rational_only=False) self.__lattice = lattice return lattice + class RationalCuspSubgroup(CuspidalSubgroup_generic): """ EXAMPLES:: @@ -292,10 +293,11 @@ def lattice(self): try: return self.__lattice except AttributeError: - lattice = self._compute_lattice(rational_only = True) + lattice = self._compute_lattice(rational_only=True) self.__lattice = lattice return lattice + class RationalCuspidalSubgroup(CuspidalSubgroup_generic): """ EXAMPLES:: @@ -342,7 +344,7 @@ def lattice(self): try: return self.__lattice except AttributeError: - lattice = self._compute_lattice(rational_subgroup = True) + lattice = self._compute_lattice(rational_subgroup=True) self.__lattice = lattice return lattice diff --git a/src/sage/modular/abvar/finite_subgroup.py b/src/sage/modular/abvar/finite_subgroup.py index d2af5e29e00..3f4f0ffbd8f 100644 --- a/src/sage/modular/abvar/finite_subgroup.py +++ b/src/sage/modular/abvar/finite_subgroup.py @@ -461,7 +461,7 @@ def __mul__(self, right): """ lattice = self.lattice().scale(right) return FiniteSubgroup_lattice(self.abelian_variety(), lattice, - field_of_definition = self.field_of_definition()) + field_of_definition=self.field_of_definition()) def __rmul__(self, left): """ diff --git a/src/sage/modular/abvar/morphism.py b/src/sage/modular/abvar/morphism.py index d8676e7db00..bb31e19dbe0 100644 --- a/src/sage/modular/abvar/morphism.py +++ b/src/sage/modular/abvar/morphism.py @@ -546,7 +546,7 @@ def _image_of_finite_subgroup(self, G): B = G._relative_basis_matrix() * self.restrict_domain(G.abelian_variety()).matrix() * self.codomain().lattice().basis_matrix() lattice = B.row_module(ZZ) return self.codomain().finite_subgroup(lattice, - field_of_definition = G.field_of_definition()) + field_of_definition=G.field_of_definition()) def _image_of_abvar(self, A): """ diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index 7e07c33e551..b271e1b121f 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -744,7 +744,7 @@ def _find_cusps(self): so this should usually be overridden in subclasses; but it doesn't have to be. """ - i = Cusp([1,0]) + i = Cusp([1, 0]) L = [i] for a in self.coset_reps(): ai = i.apply([a.a(), a.b(), a.c(), a.d()]) @@ -757,11 +757,12 @@ def _find_cusps(self): L.append(ai) return L - def are_equivalent(self, x, y, trans = False): + def are_equivalent(self, x, y, trans=False): r""" - Test whether or not cusps x and y are equivalent modulo self. If self - has a reduce_cusp() method, use that; otherwise do a slow explicit - test. + Test whether or not cusps x and y are equivalent modulo self. + + If self has a reduce_cusp() method, use that; otherwise do a + slow explicit test. If trans = False, returns True or False. If trans = True, then return either False or an element of self mapping x onto y. diff --git a/src/sage/modular/hecke/submodule.py b/src/sage/modular/hecke/submodule.py index 572a8f73029..a6b5c96cbbc 100644 --- a/src/sage/modular/hecke/submodule.py +++ b/src/sage/modular/hecke/submodule.py @@ -27,7 +27,6 @@ from . import module - def is_HeckeSubmodule(x): r""" Return True if x is of type HeckeSubmodule. @@ -553,8 +552,8 @@ def dual_free_module(self, bound=None, anemic=True, use_star=True): # then we compute the dual on each eigenspace, then put them # together. if len(self.star_eigenvalues()) == 2: - V = self.plus_submodule(compute_dual = False).dual_free_module() + \ - self.minus_submodule(compute_dual = False).dual_free_module() + V = self.plus_submodule(compute_dual=False).dual_free_module() + \ + self.minus_submodule(compute_dual=False).dual_free_module() return V # At this point, we know that self is an eigenspace for star. diff --git a/src/sage/modular/local_comp/type_space.py b/src/sage/modular/local_comp/type_space.py index 87b3996dc04..2549e5519b0 100644 --- a/src/sage/modular/local_comp/type_space.py +++ b/src/sage/modular/local_comp/type_space.py @@ -33,7 +33,7 @@ @cached_function -def example_type_space(example_no = 0): +def example_type_space(example_no=0): r""" Quickly return an example of a type space. Used mainly to speed up doctesting. diff --git a/src/sage/modular/modform/ambient_eps.py b/src/sage/modular/modform/ambient_eps.py index 093f62daa0d..cf676af02ef 100644 --- a/src/sage/modular/modform/ambient_eps.py +++ b/src/sage/modular/modform/ambient_eps.py @@ -198,9 +198,9 @@ def change_ring(self, base_ring): """ if self.base_ring() == base_ring: return self - return ambient_R.ModularFormsAmbient_R(self, base_ring = base_ring) + return ambient_R.ModularFormsAmbient_R(self, base_ring=base_ring) - @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 corresponding space of modular symbols with given sign. @@ -222,9 +222,9 @@ def modular_symbols(self, sign=0): """ sign = rings.Integer(sign) return modsym.ModularSymbols(self.character(), - weight = self.weight(), - sign = sign, - base_ring = self.base_ring()) + weight=self.weight(), + sign=sign, + base_ring=self.base_ring()) @cached_method def eisenstein_submodule(self): diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index e16b2e4f1df..dfb1dc1b53f 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -153,12 +153,13 @@ def ModularForms_clear_cache(): global _cache _cache = {} -def ModularForms(group = 1, - weight = 2, - base_ring = None, + +def ModularForms(group=1, + weight=2, + base_ring=None, eis_only=False, - use_cache = True, - prec = defaults.DEFAULT_PRECISION): + use_cache=True, + prec=defaults.DEFAULT_PRECISION): r""" Create an ambient space of modular forms. @@ -346,8 +347,8 @@ def ModularForms(group = 1, eps = eps.minimize_base_ring() if eps.is_trivial(): return ModularForms(eps.modulus(), weight, base_ring, - use_cache = use_cache, - prec = prec) + use_cache=use_cache, + prec=prec) M = ModularFormsAmbient_eps(eps, weight, eis_only=eis_only) if base_ring != eps.base_ring(): M = M.base_extend(base_ring) # ambient_R.ModularFormsAmbient_R(M, base_ring) @@ -360,11 +361,11 @@ def ModularForms(group = 1, return M -def CuspForms(group = 1, - weight = 2, - base_ring = None, - use_cache = True, - prec = defaults.DEFAULT_PRECISION): +def CuspForms(group=1, + weight=2, + base_ring=None, + use_cache=True, + prec=defaults.DEFAULT_PRECISION): """ Create a space of cuspidal modular forms. @@ -380,13 +381,13 @@ def CuspForms(group = 1, use_cache=use_cache, prec=prec).cuspidal_submodule() -def EisensteinForms(group = 1, - weight = 2, - base_ring = None, - use_cache = True, - prec = defaults.DEFAULT_PRECISION): +def EisensteinForms(group=1, + weight=2, + base_ring=None, + use_cache=True, + prec=defaults.DEFAULT_PRECISION): """ - Create a space of eisenstein modular forms. + Create a space of Eisenstein modular forms. See the documentation for the ModularForms command for a description of the input parameters. @@ -396,7 +397,7 @@ def EisensteinForms(group = 1, sage: EisensteinForms(11,2) Eisenstein subspace of dimension 1 of Modular Forms space of dimension 2 for Congruence Subgroup Gamma0(11) of weight 2 over Rational Field """ - if weight==1: + if weight == 1: return ModularForms(group, weight, base_ring, use_cache=use_cache, eis_only=True, prec=prec).eisenstein_submodule() else: @@ -404,7 +405,6 @@ def EisensteinForms(group = 1, use_cache=use_cache, prec=prec).eisenstein_submodule() - def Newforms(group, weight=2, base_ring=None, names=None): r""" Returns a list of the newforms of the given weight and level (or weight, diff --git a/src/sage/modular/modform/cuspidal_submodule.py b/src/sage/modular/modform/cuspidal_submodule.py index d40af39c52e..e2e43a01f96 100644 --- a/src/sage/modular/modform/cuspidal_submodule.py +++ b/src/sage/modular/modform/cuspidal_submodule.py @@ -236,7 +236,7 @@ def _compute_q_expansion_basis(self, prec=None): prec = Integer(prec) if self.dimension() == 0: return [] - M = self.modular_symbols(sign = 1) + M = self.modular_symbols(sign=1) return M.q_expansion_basis(prec) def _compute_hecke_matrix_prime(self, p): diff --git a/src/sage/modular/modform/eis_series.py b/src/sage/modular/modform/eis_series.py index 65d43a39fda..88499df94c5 100644 --- a/src/sage/modular/modform/eis_series.py +++ b/src/sage/modular/modform/eis_series.py @@ -26,7 +26,7 @@ from .eis_series_cython import eisenstein_series_poly, Ek_ZZ -def eisenstein_series_qexp(k, prec = 10, K=QQ, var='q', normalization='linear'): +def eisenstein_series_qexp(k, prec=10, K=QQ, var='q', normalization='linear'): r""" Return the `q`-expansion of the normalized weight `k` Eisenstein series on `\SL_2(\ZZ)` to precision prec in the ring `K`. Three normalizations @@ -420,28 +420,29 @@ def eisenstein_series_lseries(weight, prec=53, sage: L(2) -5.0235535164599797471968418348135050804419155747868718371029 """ - f = eisenstein_series_qexp(weight,prec) + f = eisenstein_series_qexp(weight, prec) from sage.lfunctions.all import Dokchitser j = weight - L = Dokchitser(conductor = 1, - gammaV = [0,1], - weight = j, - eps = (-1)**Integer(j/2), - poles = [j], + L = Dokchitser(conductor=1, + gammaV=[0, 1], + weight=j, + eps=(-1)**Integer(j // 2), + poles=[j], # Using a string for residues is a hack but it works well # since this will make PARI/GP compute sqrt(pi) with the # right precision. - residues = '[sqrt(Pi)*(%s)]'%((-1)**Integer(j/2)*bernoulli(j)/j), - prec = prec) + residues='[sqrt(Pi)*(%s)]'%((-1)**Integer(j/2)*bernoulli(j)/j), + prec=prec) s = 'coeff = %s;'%f.list() - L.init_coeffs('coeff[k+1]',pari_precode = s, + L.init_coeffs('coeff[k+1]',pari_precode=s, max_imaginary_part=max_imaginary_part, max_asymp_coeffs=max_asymp_coeffs) L.check_functional_equation() L.rename('L-series associated to the weight %s Eisenstein series %s on SL_2(Z)'%(j,f)) return L + def compute_eisenstein_params(character, k): r""" Compute and return a list of all parameters `(\chi,\psi,t)` that diff --git a/src/sage/modular/modform/hecke_operator_on_qexp.py b/src/sage/modular/modform/hecke_operator_on_qexp.py index 6a61cbb46f2..89de388f27f 100644 --- a/src/sage/modular/modform/hecke_operator_on_qexp.py +++ b/src/sage/modular/modform/hecke_operator_on_qexp.py @@ -1,16 +1,15 @@ """ Hecke Operators on `q`-expansions """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004-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/ +# **************************************************************************** from sage.arith.misc import divisors, gcd from sage.matrix.constructor import matrix @@ -24,7 +23,7 @@ from sage.modular.dirichlet import DirichletGroup, is_DirichletCharacter from .element import is_ModularFormElement -def hecke_operator_on_qexp(f, n, k, eps = None, +def hecke_operator_on_qexp(f, n, k, eps=None, prec=None, check=True, _return_list=False): r""" Given the `q`-expansion `f` of a modular form with character @@ -149,8 +148,8 @@ def _hecke_operator_on_basis(B, V, n, k, eps): TB = [V.coordinate_vector(w) for w in TB] return matrix(V.base_ring(), len(B), len(B), TB, sparse=False) -def hecke_operator_on_basis(B, n, k, eps=None, - already_echelonized = False): + +def hecke_operator_on_basis(B, n, k, eps=None, already_echelonized=False): r""" Given a basis `B` of `q`-expansions for a space of modular forms with character `\varepsilon` to precision at least `\#B\cdot n+1`, @@ -232,8 +231,8 @@ def hecke_operator_on_basis(B, n, k, eps=None, raise TypeError("each element of B must be a power series") n = Integer(n) k = Integer(k) - prec = (f.prec()-1)//n + prec = (f.prec() - 1) // n A = R**prec V = A.span_of_basis([g.padded_list(prec) for g in B], - already_echelonized = already_echelonized) + already_echelonized=already_echelonized) return _hecke_operator_on_basis(B, V, n, k, eps) diff --git a/src/sage/modular/modform/space.py b/src/sage/modular/modform/space.py index 5dfd3f568d8..69206f0e023 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -1309,7 +1309,7 @@ def _compute_hecke_matrix_prime(self, p, prec=None): self.weight(), eps, already_echelonized=False) except ValueError: # Double the precision. - return self._compute_hecke_matrix_prime(p, prec = 2*prec+1) + return self._compute_hecke_matrix_prime(p, prec=2 * prec + 1) def _compute_hecke_matrix(self, n): """ diff --git a/src/sage/modular/modform/submodule.py b/src/sage/modular/modform/submodule.py index b1da8a92105..49b6c12b493 100644 --- a/src/sage/modular/modform/submodule.py +++ b/src/sage/modular/modform/submodule.py @@ -104,7 +104,8 @@ def _compute_q_expansion_basis(self, prec): O(q^5)] """ A = self.ambient_module() - return [A._q_expansion(element = f.element(), prec=prec) for f in self.basis()] + return [A._q_expansion(element=f.element(), prec=prec) + for f in self.basis()] # TODO diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index c1fc60f724c..fdd7e38b552 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -834,7 +834,7 @@ def emb_key(emb): return L if len(L) > 1: - L.sort(key = emb_key) + L.sort(key=emb_key) return L[-1] def _elliptic_conj_reps(self): diff --git a/src/sage/modular/modform_hecketriangle/series_constructor.py b/src/sage/modular/modform_hecketriangle/series_constructor.py index 3b698833b2b..881270c5bfa 100644 --- a/src/sage/modular/modform_hecketriangle/series_constructor.py +++ b/src/sage/modular/modform_hecketriangle/series_constructor.py @@ -33,8 +33,7 @@ from .hecke_triangle_groups import HeckeTriangleGroup - -class MFSeriesConstructor(SageObject,UniqueRepresentation): +class MFSeriesConstructor(SageObject, UniqueRepresentation): r""" Constructor for the Fourier expansion of some (specific, basic) modular forms. @@ -44,7 +43,7 @@ class MFSeriesConstructor(SageObject,UniqueRepresentation): """ @staticmethod - def __classcall__(cls, group = HeckeTriangleGroup(3), prec=ZZ(10)): + def __classcall__(cls, group=HeckeTriangleGroup(3), prec=ZZ(10)): r""" Return a (cached) instance with canonical parameters. diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index 6408405d520..4f9b23bfc28 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -3014,7 +3014,7 @@ def _compute_hecke_matrix_prime(self, p, rows=None): P1 = self.p1list() mod2term = self._mod2term R = self.manin_gens_to_basis() - W = R.new_matrix(nrows=len(B), ncols = R.nrows()) # the 0 with given number of rows and cols. + W = R.new_matrix(nrows=len(B), ncols=R.nrows()) # the 0 with given number of rows and cols. j = 0 tm = verbose("Matrix non-reduced", tm) for i in B: @@ -3588,11 +3588,11 @@ def __init__(self, eps, weight, sign, base_ring, custom_init=None, category=None """ level = eps.modulus() ModularSymbolsAmbient.__init__(self, - weight = weight, - group = arithgroup.Gamma1(level), - sign = sign, - base_ring = base_ring, - character = eps.change_ring(base_ring), + weight=weight, + group=arithgroup.Gamma1(level), + sign=sign, + base_ring=base_ring, + character=eps.change_ring(base_ring), custom_init=custom_init, category=category) diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index f8550d0f05f..fa24249edc8 100644 --- a/src/sage/modular/modsym/boundary.py +++ b/src/sage/modular/modsym/boundary.py @@ -274,17 +274,17 @@ def __neg__(self): sage: -x + x # indirect doctest 0 """ - return self*(-1) + return self * (-1) @richcmp_method class BoundarySpace(hecke.HeckeModule_generic): def __init__(self, - group = arithgroup.Gamma0(1), - weight = 2, - sign = 0, - base_ring = rings.QQ, - character = None): + group=arithgroup.Gamma0(1), + weight=2, + sign=0, + base_ring=rings.QQ, + character=None): """ Space of boundary symbols for a congruence subgroup of SL_2(Z). diff --git a/src/sage/modular/modsym/modsym.py b/src/sage/modular/modsym/modsym.py index a30f53a8a9e..0a87eece1d7 100644 --- a/src/sage/modular/modsym/modsym.py +++ b/src/sage/modular/modsym/modsym.py @@ -180,11 +180,11 @@ def ModularSymbols_clear_cache(): _cache = {} -def ModularSymbols(group = 1, - weight = 2, - sign = 0, - base_ring = None, - use_cache = True, +def ModularSymbols(group=1, + weight=2, + sign=0, + base_ring=None, + use_cache=True, custom_init=None): r""" Create an ambient space of modular symbols. diff --git a/src/sage/modular/modsym/subspace.py b/src/sage/modular/modsym/subspace.py index e27467a3816..c1f70471c0f 100644 --- a/src/sage/modular/modsym/subspace.py +++ b/src/sage/modular/modsym/subspace.py @@ -72,9 +72,10 @@ def __init__(self, ambient_hecke_module, submodule, """ self.__ambient_hecke_module = ambient_hecke_module A = ambient_hecke_module - sage.modular.modsym.space.ModularSymbolsSpace.__init__(self, A.group(), A.weight(), \ - A.character(), A.sign(), A.base_ring()) - hecke.HeckeSubmodule.__init__(self, A, submodule, dual_free_module = dual_free_module, check=check) + sage.modular.modsym.space.ModularSymbolsSpace.__init__(self, A.group(), + A.weight(), + A.character(), A.sign(), A.base_ring()) + hecke.HeckeSubmodule.__init__(self, A, submodule, dual_free_module=dual_free_module, check=check) def _repr_(self): """ diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index dcd3d681eac..6fd43f34560 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -170,8 +170,6 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.structure.richcmp import op_EQ, op_NE from sage.structure.element import parent -from sage.algebras.free_zinbiel_algebra import FreeZinbielAlgebra -from sage.arith.misc import bernoulli from sage.categories.cartesian_product import cartesian_product from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.categories.rings import Rings @@ -189,12 +187,11 @@ from sage.misc.cachefunc import cached_function, cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod -from sage.modules.free_module_element import vector +from sage.modular.multiple_zeta_F_algebra import F_algebra from sage.modules.free_module import VectorSpace from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ -from sage.rings.semirings.non_negative_integer_semiring import NN +from sage.sets.positive_integers import PositiveIntegers # multiplicative generators for weight <= 17 # using the following convention @@ -439,7 +436,7 @@ def __repr__(self): sage: MultizetaValues() Cached multiple zeta values at precision 1024 up to weight 8 """ - return "Cached multiple zeta values at precision %d up to weight %d" % (self.prec, self.max_weight) + return f"Cached multiple zeta values at precision {self.prec} up to weight {self.max_weight}" def reset(self, max_weight=8, prec=1024): r""" @@ -497,8 +494,7 @@ def pari_eval(self, index): if weight <= self.max_weight: index = pari.zetamultconvert(index, 2) return self._data[index - 1] - else: - return pari.zetamult(index, precision=self.prec) + return pari.zetamult(index, precision=self.prec) def __call__(self, index, prec=None, reverse=True): r""" @@ -543,97 +539,12 @@ def __call__(self, index, prec=None, reverse=True): index = pari.zetamultconvert(index, 2) value = self._data[index - 1] return value.sage().n(prec=prec) - else: - return pari.zetamult(index, precision=prec).sage().n(prec=prec) + return pari.zetamult(index, precision=prec).sage().n(prec=prec) Values = MultizetaValues() -def basis_f_odd_iterator(n): - """ - Return an iterator over compositions of ``n`` with parts in ``(3,5,7,...)`` - - INPUT: - - - ``n`` -- an integer - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import basis_f_odd_iterator - sage: [list(basis_f_odd_iterator(i)) for i in range(2,9)] - [[], [(3,)], [], [(5,)], [(3, 3)], [(7,)], [(5, 3), (3, 5)]] - sage: list(basis_f_odd_iterator(14)) - [(11, 3), - (5, 3, 3, 3), - (3, 5, 3, 3), - (3, 3, 5, 3), - (9, 5), - (3, 3, 3, 5), - (7, 7), - (5, 9), - (3, 11)] - """ - if n == 0: - yield tuple() - return - if n == 1: - return - if n % 2: - yield (n,) - for k in range(3, n, 2): - for start in basis_f_odd_iterator(n - k): - yield start + (k, ) - - -def basis_f_iterator(n): - """ - Return an iterator over decompositions of ``n`` using ``2,3,5,7,9,...``. - - The means that each term is made of a power of 2 and a composition - of the remaining integer with parts in ``(3,5,7,...)`` - - INPUT: - - - ``n`` -- an integer - - Each term is returned as a pair (integer, word) where - the integer is the exponent of 2. - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import basis_f_iterator - sage: [list(basis_f_iterator(i)) for i in range(2,9)] - [[(1, word: )], - [(0, word: f3)], - [(2, word: )], - [(0, word: f5), (1, word: f3)], - [(0, word: f3,f3), (3, word: )], - [(0, word: f7), (1, word: f5), (2, word: f3)], - [(0, word: f5,f3), (0, word: f3,f5), (1, word: f3,f3), (4, word: )]] - sage: list(basis_f_iterator(11)) - [(0, word: f11), - (0, word: f5,f3,f3), - (0, word: f3,f5,f3), - (0, word: f3,f3,f5), - (1, word: f9), - (1, word: f3,f3,f3), - (2, word: f7), - (3, word: f5), - (4, word: f3)] - - TESTS:: - - sage: list(basis_f_iterator(0)) - [(0, word: )] - """ - if n and n < 2: - return - for k in range(n // 2 + 1): - for start in basis_f_odd_iterator(n - 2 * k): - yield (k, Word(['f{}'.format(d) for d in start])) - - def extend_multiplicative_basis(B, n): """ Extend a multiplicative basis into a basis. @@ -749,9 +660,8 @@ def __init__(self, R): cat = GradedAlgebrasWithBasis(R).Commutative() if R in Domains(): cat = cat & Domains() - CombinatorialFreeModule.__init__(self, R, Words(NN, infinite=False), - prefix="Z", - category=cat) + W = Words(PositiveIntegers(), infinite=False) + CombinatorialFreeModule.__init__(self, R, W, prefix="Z", category=cat) def _repr_(self): r""" @@ -959,7 +869,7 @@ def phi(self): r""" Return the morphism ``phi``. - This sends multiple zeta values to the algebra :func:`F_ring`, + This sends multiple zeta values to the auxiliary F-algebra, which is a shuffle algebra in odd generators `f_3,f_5,f_7,\dots` over the polynomial ring in one variable `f_2`. @@ -975,12 +885,12 @@ def phi(self): sage: m = Multizeta(2,2) + 2*Multizeta(1,3); m 2*ζ(1,3) + ζ(2,2) sage: M.phi(m) - 1/2*f2^2*Z[] + 1/2*f2^2 sage: Z = Multizeta sage: B5 = [3*Z(1,4) + 2*Z(2,3) + Z(3,2), 3*Z(1,4) + Z(2,3)] sage: [M.phi(b) for b in B5] - [f2*Z[f3] - 1/2*Z[f5], 1/2*Z[f5]] + [-1/2*f5 + f2*f3, 1/2*f5] """ M_it = Multizetas_iterated(self.base_ring()) return M_it.phi * self.iterated @@ -1024,7 +934,7 @@ def _element_constructor_(self, x): if isinstance(x, list): x = tuple(x) return self._monomial(W(x, check=False)) - elif isinstance(parent(x), Multizetas_iterated): + if isinstance(parent(x), Multizetas_iterated): return x.composition() raise TypeError('invalid input for building a multizeta value') @@ -1129,7 +1039,7 @@ def basis_filtration(self, d, reverse=False): raise ValueError('d must be a non-negative integer') if d == 0: return [self([])] - elif d == 1: + if d == 1: return [] Values.reset(max_weight=d) @@ -1151,9 +1061,8 @@ def basis_filtration(self, d, reverse=False): v = self(c).phi_as_vector() if v in U: continue - else: - U = V.subspace(U.basis() + [v]) - basis.append(c) + U = V.subspace(U.basis() + [v]) + basis.append(c) k += 1 return [self(c) for c in basis] @@ -1201,10 +1110,10 @@ def single_valued(self): """ phi_im = self.phi() zin = phi_im.parent() - BR2 = zin.base_ring() - sv = zin.sum_of_terms((w, BR2(cf(0))) - for (a, b), cf in phi_im.coproduct() - for w in shuffle(a, b.reversal(), False)) + phi_no_f2 = phi_im.without_f2() + sv = zin.sum_of_terms(((0, w), cf) + for (a, b), cf in phi_no_f2.coproduct() + for w in shuffle(a[1], b[1].reversal(), False)) return rho_inverse(sv) def simplify(self): @@ -1331,7 +1240,7 @@ def _richcmp_(self, other, op): sage: (0*M()) == 0 True """ - if op != op_EQ and op != op_NE: + if op not in [op_EQ, op_NE]: raise TypeError('invalid comparison for multizetas') return self.iterated()._richcmp_(other.iterated(), op) @@ -1351,13 +1260,13 @@ def phi(self): """ Return the image of ``self`` by the morphism ``phi``. - This sends multiple zeta values to the algebra :func:`F_ring`. + This sends multiple zeta values to the auxiliary F-algebra. EXAMPLES:: sage: M = Multizetas(QQ) sage: M((1,2)).phi() - Z[f3] + f3 TESTS:: @@ -1366,7 +1275,7 @@ def phi(self): sage: M = Multizetas(A) sage: tst = u*M((1,2))+M((3,)) sage: tst.phi() - (u+1)*Z[f3] + (u+1)*f3 """ return self.parent().phi(self) @@ -1397,7 +1306,7 @@ def phi_as_vector(self): """ if not self.is_homogeneous(): raise ValueError('only defined for homogeneous elements') - return f_to_vector(self.parent().phi(self)) + return self.parent().phi(self).homogeneous_to_vector() def _numerical_approx_pari(self): r""" @@ -1463,8 +1372,7 @@ def numerical_approx(self, prec=None, digits=None, algorithm=None): if prec < Values.prec: s = sum(cf * Values(tuple(w)) for w, cf in self.monomial_coefficients().items()) return s.n(prec=prec) - else: - return sum(cf * Values(tuple(w), prec=prec) for w, cf in self.monomial_coefficients().items()) + return sum(cf * Values(tuple(w), prec=prec) for w, cf in self.monomial_coefficients().items()) class Multizetas_iterated(CombinatorialFreeModule): @@ -1514,9 +1422,10 @@ def _repr_(self): sage: from sage.modular.multiple_zeta import Multizetas_iterated sage: M = Multizetas_iterated(QQ); M - Algebra of motivic multiple zeta values as convergent iterated integrals over Rational Field + Algebra of motivic multiple zeta values + as convergent iterated integrals over Rational Field """ - return "Algebra of motivic multiple zeta values as convergent iterated integrals over {}".format(self.base_ring()) + return f"Algebra of motivic multiple zeta values as convergent iterated integrals over {self.base_ring()}" def _repr_term(self, m): """ @@ -1645,12 +1554,11 @@ def split_word(indices): w = Word(seq[indices[i]:indices[i + 1] + 1]) if len(w) == 2: # this factor is one continue - elif len(w) <= 4 or len(w) == 6 or w[0] == w[-1]: + if len(w) <= 4 or len(w) == 6 or w[0] == w[-1]: # vanishing factors return self.zero() - else: - value = M_all(w) - L *= value.regularise().simplify() + value = M_all(w) + L *= value.regularise().simplify() return L resu = self.tensor_square().zero() @@ -1837,7 +1745,7 @@ def phi_extended(self, w): OUTPUT: - an element in the algebra :func:`F_ring` + an element in the auxiliary F-algebra The coefficients are in the base ring. @@ -1846,52 +1754,50 @@ def phi_extended(self, w): sage: from sage.modular.multiple_zeta import Multizetas_iterated sage: M = Multizetas_iterated(QQ) sage: M.phi_extended((1,0)) - -f2*Z[] + -f2 sage: M.phi_extended((1,0,0)) - -Z[f3] + -f3 sage: M.phi_extended((1,1,0)) - Z[f3] + f3 sage: M.phi_extended((1,0,1,0,0)) - 3*f2*Z[f3] - 11/2*Z[f5] + -11/2*f5 + 3*f2*f3 More complicated examples:: sage: from sage.modular.multiple_zeta import composition_to_iterated sage: M.phi_extended(composition_to_iterated((4,3))) - 2/5*f2^2*Z[f3] + 10*f2*Z[f5] - 18*Z[f7] + -18*f7 + 10*f2*f5 + 2/5*f2^2*f3 sage: M.phi_extended(composition_to_iterated((3,4))) - -10*f2*Z[f5] + 17*Z[f7] + 17*f7 - 10*f2*f5 sage: M.phi_extended(composition_to_iterated((4,2))) - 10/21*f2^3*Z[] - 2*Z[f3,f3] + -2*f3f3 + 10/21*f2^3 sage: M.phi_extended(composition_to_iterated((3,5))) - -5*Z[f5,f3] + -5*f5f3 sage: M.phi_extended(composition_to_iterated((3,7))) - -6*Z[f5,f5] - 14*Z[f7,f3] + -6*f5f5 - 14*f7f3 sage: M.phi_extended(composition_to_iterated((3,3,2))) - -793/875*f2^4*Z[] - 4*f2*Z[f3,f3] + 9*Z[f3,f5] - 9/2*Z[f5,f3] + 9*f3f5 - 9/2*f5f3 - 4*f2*f3f3 - 793/875*f2^4 TESTS:: sage: M.phi_extended(tuple()) - Z[] + 1 """ # this is now hardcoded # prec = 1024 - f = F_ring_generator + F = F_algebra(self.base_ring()) + f = F.gen if not w: - F = F_ring(self.base_ring()) - empty = F.indices()([]) - return F.monomial(empty) + return F.one() N = len(w) compo = tuple(iterated_to_composition(w)) - BRf2 = PolynomialRing(self.base_ring(), 'f2') if compo in B_data[N]: # do not forget the sign result_QQ = (-1)**len(compo) * phi_on_multiplicative_basis(compo) - return result_QQ.base_extend(BRf2) + return result_QQ u = compute_u_on_basis(w) rho_inverse_u = rho_inverse(u) xi = self.composition_on_basis(w, QQ) @@ -1899,14 +1805,14 @@ def phi_extended(self, w): c_xi /= Multizeta(N)._numerical_approx_pari() c_xi = c_xi.bestappr().sage() # in QQ result_QQ = u + c_xi * f(N) - return result_QQ.base_extend(BRf2) + return result_QQ @lazy_attribute def phi(self): """ Return the morphism ``phi``. - This sends multiple zeta values to the algebra :func:`F_ring`. + This sends multiple zeta values to the auxiliary F-algebra. EXAMPLES:: @@ -1915,19 +1821,19 @@ def phi(self): sage: m = Multizeta(1,0,1,0) + 2*Multizeta(1,1,0,0); m 2*I(1100) + I(1010) sage: M.phi(m) - 1/2*f2^2*Z[] + 1/2*f2^2 sage: Z = Multizeta sage: B5 = [3*Z(1,4) + 2*Z(2,3) + Z(3,2), 3*Z(1,4) + Z(2,3)] sage: [M.phi(b.iterated()) for b in B5] - [f2*Z[f3] - 1/2*Z[f5], 1/2*Z[f5]] + [-1/2*f5 + f2*f3, 1/2*f5] sage: B6 = [6*Z(1,5) + 3*Z(2,4) + Z(3,3), ....: 6*Z(1,1,4) + 4*Z(1,2,3) + 2*Z(1,3,2) + 2*Z(2,1,3) + Z(2,2,2)] sage: [M.phi(b.iterated()) for b in B6] - [Z[f3,f3], 1/6*f2^3*Z[]] + [f3f3, 1/6*f2^3] """ - cod = F_ring(self.base_ring()) + cod = F_algebra(self.base_ring()) return self.module_morphism(self.phi_extended, codomain=cod) def _element_constructor_(self, x): @@ -1974,8 +1880,7 @@ def _element_constructor_(self, x): x = R(x) if x == 0: return self.element_class(self, {}) - else: - return self.from_base_ring_from_one_basis(x) + return self.from_base_ring_from_one_basis(x) class Element(CombinatorialFreeModule.Element): def simplify(self): @@ -2051,14 +1956,14 @@ def phi(self): """ Return the image of ``self`` by the morphism ``phi``. - This sends multiple zeta values to the algebra :func:`F_ring`. + This sends multiple zeta values to the auxiliary F-algebra. EXAMPLES:: sage: from sage.modular.multiple_zeta import Multizetas_iterated sage: M = Multizetas_iterated(QQ) sage: M((1,1,0)).phi() - Z[f3] + f3 """ return self.parent().phi(self) @@ -2121,7 +2026,7 @@ def _richcmp_(self, other, op): sage: a.iterated() == b.iterated() # not tested, long time 20s True """ - if op != op_EQ and op != op_NE: + if op not in [op_EQ, op_NE]: raise TypeError('invalid comparison for multizetas') return (self - other).is_zero() == (op == op_EQ) @@ -2452,100 +2357,6 @@ def regularise(self): # **************** procedures after F. Brown ************ - -def F_ring(basering, N=18): - r""" - Return the free Zinbiel algebra on many generators `f_3,f_5,\dots` - over the polynomial ring with generator `f_2`. - - For the moment, only with a finite number of variables. - - INPUT: - - - ``N`` -- an integer (default 18), upper bound for indices of generators - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import F_ring - sage: F_ring(QQ) - Free Zinbiel algebra on generators (Z[f3], Z[f5], Z[f7], Z[f9], ...) - over Univariate Polynomial Ring in f2 over Rational Field - """ - ring = PolynomialRing(basering, ['f2']) - return FreeZinbielAlgebra(ring, ['f{}'.format(k) - for k in range(3, N, 2)]) - - -def F_prod(a, b): - """ - Return the associative and commutative product of ``a`` and ``b``. - - INPUT: - - - ``a``, ``b`` -- two elements of the F ring - - OUTPUT: - - an element of the F ring - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import F_ring_generator, F_prod - sage: f2 = F_ring_generator(2) - sage: f3 = F_ring_generator(3) - sage: F_prod(f2,f2) - f2^2*Z[] - sage: F_prod(f2,f3) - f2*Z[f3] - sage: F_prod(f3,f3) - 2*Z[f3,f3] - sage: F_prod(3*f2+5*f3,6*f2+f3) - 18*f2^2*Z[] + 33*f2*Z[f3] + 10*Z[f3,f3] - """ - F = a.parent() - empty = F.indices()([]) - one = F.monomial(empty) - ct_a = a.coefficient(empty) - ct_b = b.coefficient(empty) - rem_a = a - ct_a * one - rem_b = b - ct_b * one - resu = ct_a * ct_b * one + ct_a * rem_b + ct_b * rem_a - return resu + rem_a * rem_b + rem_b * rem_a - - -def F_ring_generator(i): - r""" - Return the generator of the F ring over `\QQ`. - - INPUT: - - - ``i`` -- a nonnegative integer - - If ``i`` is odd, this returns a single generator `f_i` of the free - shuffle algebra. - - Otherwise, it returns an appropriate multiple of a power of `f_2`. - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import F_ring_generator - sage: [F_ring_generator(i) for i in range(2,8)] - [f2*Z[], Z[f3], 2/5*f2^2*Z[], Z[f5], 8/35*f2^3*Z[], Z[f7]] - """ - F = F_ring(QQ) - one = F.monomial(Word([])) - f2 = F.base_ring().gen() - if i == 2: - return f2 * one - # now i odd >= 3 - if i % 2: - return F.monomial(Word(['f{}'.format(i)])) - i = i // 2 - B = bernoulli(2 * i) * (-1)**(i - 1) - B *= ZZ(2)**(3 * i - 1) * ZZ(3)**i / ZZ(2 * i).factorial() - return B * f2**i * one - - def coeff_phi(w): """ Return the coefficient of `f_k` in the image by ``phi``. @@ -2577,8 +2388,8 @@ def coeff_phi(w): M = Multizetas_iterated(QQ) z = M.phi_extended(w) W = z.parent().basis().keys() - w = W(['f{}'.format(k)], check=False) - return z.coefficient(w).lc() # in QQ + w = W((0, [k])) + return z.coefficient(w) # in QQ def phi_on_multiplicative_basis(compo): @@ -2597,16 +2408,14 @@ def phi_on_multiplicative_basis(compo): sage: from sage.modular.multiple_zeta import phi_on_multiplicative_basis sage: phi_on_multiplicative_basis((2,)) - f2*Z[] + f2 sage: phi_on_multiplicative_basis((3,)) - Z[f3] + f3 """ - f = F_ring_generator - F = F_ring(QQ) - one = F.monomial(Word([])) + f = F_algebra(QQ).gen if tuple(compo) == (2,): - return f(2) * one + return f(2) if len(compo) == 1: n, = compo @@ -2633,18 +2442,14 @@ def phi_on_basis(L): sage: from sage.modular.multiple_zeta import phi_on_basis sage: phi_on_basis([(3,),(3,)]) - 2*Z[f3,f3] + 2*f3f3 sage: phi_on_basis([(2,),(2,)]) - f2^2*Z[] + f2^2 sage: phi_on_basis([(2,),(3,),(3,)]) - 2*f2*Z[f3,f3] + 2*f2*f3f3 """ - # beware that the default * is the half-shuffle ! - F = F_ring(QQ) - resu = F.monomial(Word([])) - for compo in L: - resu = F_prod(resu, phi_on_multiplicative_basis(compo)) - return resu + F = F_algebra(QQ) + return F.prod(phi_on_multiplicative_basis(compo) for compo in L) def D_on_compo(k, compo): @@ -2707,11 +2512,11 @@ def compute_u_on_compo(compo): sage: from sage.modular.multiple_zeta import compute_u_on_compo sage: compute_u_on_compo((2,4)) - 2*Z[f3,f3] + 2*f3f3 sage: compute_u_on_compo((2,3,2)) - -11/2*f2*Z[f5] + -11/2*f2*f5 sage: compute_u_on_compo((3,2,3,2)) - 11*f2*Z[f3,f5] - 75/4*Z[f3,f7] - 9*f2*Z[f5,f3] + 81/4*Z[f5,f5] + 75/8*Z[f7,f3] + -75/4*f3f7 + 81/4*f5f5 + 75/8*f7f3 + 11*f2*f3f5 - 9*f2*f5f3 """ it = composition_to_iterated(compo) return (-1)**len(compo) * compute_u_on_basis(it) @@ -2733,103 +2538,29 @@ def compute_u_on_basis(w): sage: from sage.modular.multiple_zeta import compute_u_on_basis sage: compute_u_on_basis((1,0,0,0,1,0)) - -2*Z[f3,f3] + -2*f3f3 sage: compute_u_on_basis((1,1,1,0,0)) - f2*Z[f3] + f2*f3 sage: compute_u_on_basis((1,0,0,1,0,0,0,0)) - -5*Z[f5,f3] + -5*f5f3 sage: compute_u_on_basis((1,0,1,0,0,1,0)) - 11/2*f2*Z[f5] + 11/2*f2*f5 sage: compute_u_on_basis((1,0,0,1,0,1,0,0,1,0)) - 11*f2*Z[f3,f5] - 75/4*Z[f3,f7] - 9*f2*Z[f5,f3] + 81/4*Z[f5,f5] - + 75/8*Z[f7,f3] + -75/4*f3f7 + 81/4*f5f5 + 75/8*f7f3 + 11*f2*f3f5 - 9*f2*f5f3 """ M = Multizetas_iterated(QQ) - F = F_ring(QQ) - f = F_ring_generator + F = F_algebra(QQ) N = len(w) xi_dict = {} for k in range(3, N, 2): xi_dict[k] = F.sum(cf * coeff_phi(ww[0]) * M.phi_extended(tuple(ww[1])) for ww, cf in M.D_on_basis(k, w)) - return F.sum(f(k) * xi_dict[k] for k in range(3, N, 2)) - - -def f_to_vector(elt): - """ - Convert an element of F ring to a vector. - - INPUT: - - an homogeneous element of :func:`F_ring` over some base ring - - OUTPUT: - - a vector with coefficients in the base ring - - .. SEEALSO:: :func:`vector_to_f` - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import F_ring, vector_to_f, f_to_vector - sage: F = F_ring(QQ) - sage: f2 = F.base_ring().gen() - sage: x = f2**4*F.monomial(Word([]))+f2*F.monomial(Word(['f3','f3'])) - sage: f_to_vector(x) - (0, 0, 1, 1) - sage: vector_to_f(_,8) - f2^4*Z[] + f2*Z[f3,f3] - - sage: x = F.monomial(Word(['f11'])); x - Z[f11] - sage: f_to_vector(x) - (1, 0, 0, 0, 0, 0, 0, 0, 0) - """ - F = elt.parent() - BR = F.base_ring().base_ring() - if not elt: - return vector(BR, []) - a, b = next(iter(elt)) - N = sum(int(x[1:]) for x in a) + 2 * b.degree() - W = F.basis().keys() - return vector(BR, [elt.coefficient(W(b, check=False)).lc() - for _, b in basis_f_iterator(N)]) - - -def vector_to_f(vec, N): - """ - Convert back a vector to an element of the F ring. - - INPUT: - - a vector with coefficients in some base ring - - OUTPUT: - - an homogeneous element of :func:`F_ring` over this base ring - - .. SEEALSO:: :func:`f_to_vector` - - EXAMPLES:: - - sage: from sage.modular.multiple_zeta import vector_to_f, f_to_vector - sage: vector_to_f((4,5),6) - 5*f2^3*Z[] + 4*Z[f3,f3] - sage: f_to_vector(_) - (4, 5) - """ - if isinstance(vec, (list, tuple)): - vec = vector(vec) - BR = vec.base_ring() - F = F_ring(BR) - f2 = F.base_ring().gen() - basis_F = (f2**k * F.monomial(b) - for k, b in basis_f_iterator(N)) - return sum(cf * bi for cf, bi in zip(vec, basis_F)) + return F.sum(F.half_product(F.gen(k), xi_dict[k]) + for k in range(3, N, 2)) @cached_function @@ -2859,7 +2590,7 @@ def rho_matrix_inverse(n): resu = [] for b in base: phi_b = phi_on_basis(b) - resu.append(f_to_vector(phi_b)) + resu.append(phi_b.homogeneous_to_vector()) dN = len(resu) return ~matrix(QQ, dN, dN, resu) @@ -2878,13 +2609,15 @@ def rho_inverse(elt): EXAMPLES:: - sage: from sage.modular.multiple_zeta import F_ring_generator, rho_inverse - sage: f = F_ring_generator + sage: from sage.modular.multiple_zeta import rho_inverse + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: f = A.gen sage: rho_inverse(f(3)) ζ(3) sage: rho_inverse(f(9)) ζ(9) - sage: rho_inverse(f(5)*f(3)) + sage: rho_inverse(A("53")) -1/5*ζ(3,5) """ pa = elt.parent() @@ -2893,9 +2626,10 @@ def rho_inverse(elt): if elt == pa.zero(): return M_BR.zero() - a, b = next(iter(elt)) - N = sum(int(x[1:]) for x in a) + 2 * b.degree() + pw, _ = next(iter(elt)) + p, w = pw + N = 2 * p + sum(int(c) for c in w) - v = f_to_vector(elt) + v = elt.homogeneous_to_vector() w = v * rho_matrix_inverse(N) return sum(cf * b for cf, b in zip(w, M_BR.basis_data(BR, N))) diff --git a/src/sage/modular/multiple_zeta_F_algebra.py b/src/sage/modular/multiple_zeta_F_algebra.py new file mode 100644 index 00000000000..39e7dcad4e7 --- /dev/null +++ b/src/sage/modular/multiple_zeta_F_algebra.py @@ -0,0 +1,723 @@ +# -*- coding: utf-8 -*- +r""" +F-algebra for motivic multiple zeta values. + +This is a commutative algebra, defined as the tensor product of the +polynomial algebra over one generator `f_2` by the shuffle algebra in +infinitely many generators indexed by odd integers and denoted by +`f_3`, `f_5`, ... It serves as an auxiliary algebra in the study of +the ring of motivic multiple zeta values. + +Here we provide a basic direct implementation, endowed with the +motivic coproduct. + +AUTHORS: + +- Frédéric Chapoton (2022-09): Initial version + +""" +# **************************************************************************** +# Copyright (C) 2022 Frédéric Chapoton +# +# Distributed under the terms of the GNU General Public License (GPL) +# https://www.gnu.org/licenses/ +# **************************************************************************** +from __future__ import annotations +from typing import Iterator + +from sage.arith.misc import bernoulli +from sage.categories.rings import Rings +from sage.categories.bialgebras_with_basis import BialgebrasWithBasis +from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.words.words import Words +from sage.combinat.words.finite_word import FiniteWord_class +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_attribute import lazy_attribute +from sage.sets.integer_range import IntegerRange +from sage.rings.integer_ring import ZZ +from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.rings.infinity import Infinity +from sage.modules.free_module_element import vector + + +# the indexing set: (integer power of f_2, word in 3, 5, 7,...) +W_Odds = Words(IntegerRange(3, Infinity, 2), infinite=False) + + +def str_to_index(x: str) -> tuple: + """ + Convert a string to an index. + + Every letter "2" contributes to the power of `f_2`. Other letters + define a word in `f_3`, `f_5`, ... + + Usually the letters "2" form a prefix of the input. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import str_to_index + sage: str_to_index("22357") + (2, [3, 5, 7]) + """ + p = x.count("2") + w = [int(i) for i in x if i != '2'] + return (p, w) + + +def basis_f_odd_iterator(n) -> Iterator[tuple]: + """ + Return an iterator over compositions of ``n`` with parts in ``(3,5,7,...)`` + + This is used to index a basis. + + INPUT: + + - ``n`` -- an integer + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import basis_f_odd_iterator + sage: [list(basis_f_odd_iterator(i)) for i in range(2,9)] + [[], [(3,)], [], [(5,)], [(3, 3)], [(7,)], [(5, 3), (3, 5)]] + sage: list(basis_f_odd_iterator(14)) + [(11, 3), + (5, 3, 3, 3), + (3, 5, 3, 3), + (3, 3, 5, 3), + (9, 5), + (3, 3, 3, 5), + (7, 7), + (5, 9), + (3, 11)] + """ + if n == 0: + yield tuple() + return + if n == 1: + return + if n % 2: + yield (n,) + for k in range(3, n, 2): + for start in basis_f_odd_iterator(n - k): + yield start + (k, ) + + +def basis_f_iterator(n) -> Iterator[tuple]: + """ + Return an iterator over decompositions of ``n`` using ``2,3,5,7,9,...``. + + The means that each term is made of a power of 2 and a composition + of the remaining integer with parts in ``(3,5,7,...)`` + + This set is indexing a basis of the homogeneous component of weight ``n``. + + INPUT: + + - ``n`` -- an integer + + Each term is returned as a pair (integer, word) where + the integer is the exponent of 2. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import basis_f_iterator + sage: [list(basis_f_iterator(i)) for i in range(2,9)] + [[(1, word: )], + [(0, word: 3)], + [(2, word: )], + [(0, word: 5), (1, word: 3)], + [(0, word: 33), (3, word: )], + [(0, word: 7), (1, word: 5), (2, word: 3)], + [(0, word: 53), (0, word: 35), (1, word: 33), (4, word: )]] + sage: list(basis_f_iterator(11)) + [(0, word: 11), + (0, word: 533), + (0, word: 353), + (0, word: 335), + (1, word: 9), + (1, word: 333), + (2, word: 7), + (3, word: 5), + (4, word: 3)] + + TESTS:: + + sage: list(basis_f_iterator(0)) + [(0, word: )] + """ + if n and n < 2: + return + for k in range(n // 2 + 1): + for start in basis_f_odd_iterator(n - 2 * k): + yield (k, W_Odds(start, check=False)) + + +def morphism_constructor(data: dict): + """ + Build a morphism from the F-algebra to some codomain. + + INPUT: + + a dictionary containing the images of `f_2`, `f_3`, `f_5`, `f_7`, ... + + OUTPUT: + + the unique morphism defined by the dictionary ``data`` + + The codomain must be a zinbiel algebra, namely have both a + commutative associative product ``*`` and a zinbiel product + available as ``half_product``. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra, morphism_constructor + sage: F = F_algebra(QQ) + sage: Z = Multizeta + sage: D = {2: Z(2), 3: Z(3)} + sage: rho = morphism_constructor(D) + sage: rho(F("2")) + ζ(2) + sage: rho(F("3")) + ζ(3) + sage: rho(F("33")) + 6*ζ(1,5) + 3*ζ(2,4) + ζ(3,3) + sage: rho(F("23")) + 6*ζ(1,4) + 3*ζ(2,3) + ζ(3,2) + """ + im_f2 = data[2] + codomain = im_f2.parent() + domain = F_algebra(codomain.base_ring()) + + def morphism_on_basis(pw): + p, w = pw + if not w: + return im_f2**p + v = im_f2**p * data[w[-1]] + for letter in w[-2::-1]: + v = codomain.half_product(data[letter], v) + return v + + morphism = domain._module_morphism(morphism_on_basis, codomain=codomain) + + return morphism + + +class F_algebra(CombinatorialFreeModule): + r""" + Auxiliary algebra for the study of motivic multiple zeta values. + + INPUT: + + - ``R`` -- ring + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ); F + F-ring over Rational Field + sage: F.base_ring() + Rational Field + sage: F.is_commutative() + True + sage: TestSuite(F).run() + + sage: f2 = F("2") + sage: f3 = F("3") + sage: f5 = F("5") + + sage: s = f2*f3+f5; s + f5 + f2*f3 + """ + def __init__(self, R): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ); F + F-ring over Rational Field + + TESTS:: + + sage: F_algebra(24) + Traceback (most recent call last): + ... + TypeError: argument R must be a ring + """ + if R not in Rings(): + raise TypeError("argument R must be a ring") + Indices = NonNegativeIntegers().cartesian_product(W_Odds) + cat = BialgebrasWithBasis(R).Commutative().Graded() + CombinatorialFreeModule.__init__(self, R, Indices, + latex_prefix="", prefix='f', + category=cat) + + def _repr_term(self, pw) -> str: + """ + Return the custom representation of terms. + + Each monomial is written as a power of `f_2` times a word + in `f_3`, `f_5`, ... + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: f2 = F.gen(2) + sage: f3 = F.gen(3) + sage: f5 = F.gen(5) + sage: f2*f3+f5+f2**2 + f5 + f2*f3 + f2^2 + """ + p, w = pw + if not p: + if not w: + return "1" + resu = "" + elif p == 1: + resu = "f2" + else: + resu = f"f2^{p}" + if p and w: + resu += "*" + return resu + "".join(f"f{i}" for i in w) + + def _repr_(self) -> str: + r""" + Text representation of this algebra. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(ZZ) + sage: F # indirect doctest + F-ring over Integer Ring + """ + return f"F-ring over {self.base_ring()}" + + @cached_method + def one_basis(self): + r""" + Return the pair (0, empty word), which index of `1` of this algebra. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: A.one_basis() + (0, word: ) + """ + return self.basis().keys()((0, [])) + + def product_on_basis(self, pw1, pw2): + r""" + Return the product of basis elements ``pw1`` and ``pw2``. + + INPUT: + + - ``pw1``, ``pw2`` -- basis elements + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: W = A.basis().keys() + sage: A.product(A("23"), A("25")) + f2^2*f3f5 + f2^2*f5f3 + """ + p1, w1 = pw1 + p2, w2 = pw2 + p = p1 + p2 + return self.sum_of_monomials((p, u) for u in w1.shuffle(w2)) + + def half_product_on_basis(self, pw1, pw2): + r""" + Return the half product of basis elements ``pw1`` and ``pw2``. + + This is an extension of the zinbiel product of the shuffle algebra. + + INPUT: + + - ``pw1``, ``pw2`` -- Basis elements + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: W = A.basis().keys() + sage: t = A.half_product(A("23"), A("25")); t + f2^2*f3f5 + + TESTS:: + + sage: [list(pw[1]) for pw, cf in t] + [[3, 5]] + """ + p1, w1 = pw1 + p2, w2 = pw2 + p = p1 + p2 + if not w1: + return self.basis()[(p, w2)] + letter = w1[:1] + return self.sum_of_monomials((p, letter + u) + for u in w1[1:].shuffle(w2)) + + @lazy_attribute + def half_product(self): + r""" + Return the `<` product. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: W = A.basis().keys() + sage: A.half_product(A("235"), A("227")) + f2^3*f3f5f7 + f2^3*f3f7f5 + """ + half = self.half_product_on_basis + return self._module_morphism(self._module_morphism(half, position=0, + codomain=self), + position=1) + + def gen(self, i): + r""" + Return the generator of the F ring over `\QQ`. + + INPUT: + + - ``i`` -- a nonnegative integer (at least 2) + + If ``i`` is odd, this returns a single generator `f_i` of the free + shuffle algebra. + + Otherwise, it returns an appropriate multiple of a power of `f_2`. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: [A.gen(i) for i in range(2,8)] + [f2, f3, 2/5*f2^2, f5, 8/35*f2^3, f7] + """ + f2 = self.monomial(self._indices((1, []))) + if i == 2: + return f2 + # now i odd >= 3 + if i % 2: + return self.monomial(self._indices((0, [i]))) + # now powers of f2 + i = i // 2 + B = bernoulli(2 * i) * (-1)**(i - 1) + B *= ZZ(2)**(3 * i - 1) * ZZ(3)**i / ZZ(2 * i).factorial() + return B * f2**i + + def an_element(self): + """ + Return a typical element. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(ZZ) + sage: F.an_element() + 3*f2*f3f5 + f2*f5f3 + """ + return self("253") + 3 * self("235") + + def some_elements(self): + """ + Return some typical elements. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(ZZ) + sage: F.some_elements() + [0, 1, f2, f3 + f5] + """ + return [self.zero(), self.one(), self.gen(2), + self.gen(3) + self.gen(5)] + + def coproduct_on_basis(self, pw): + r""" + Return the coproduct of the basis element indexed by the pair ``pw``. + + The coproduct is given by deconcatenation on the shuffle part, + and extended by the value + + .. MATH:: + + \Delta(f_2) = 1 \otimes f_2. + + INPUT: + + - ``pw`` -- an index + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: W = F.basis().keys() + sage: F.coproduct_on_basis(W((1,[]))) + 1 # f2 + sage: F.coproduct_on_basis(W((0,[3]))) + 1 # f3 + f3 # 1 + sage: F.coproduct_on_basis(W((1,[3]))) + 1 # f2*f3 + f3 # f2 + sage: F.coproduct_on_basis(W((0,[3,5]))) + 1 # f3f5 + f3 # f5 + f3f5 # 1 + sage: F.coproduct_on_basis(W((0,[]))) + 1 # 1 + + TESTS:: + + sage: F = F_algebra(QQ) + sage: S = F.an_element(); S + 3*f2*f3f5 + f2*f5f3 + sage: F.coproduct(S) + 3*1 # f2*f3f5 + 1 # f2*f5f3 + 3*f3 # f2*f5 + 3*f3f5 # f2 + + f5 # f2*f3 + f5f3 # f2 + """ + p, w = pw + TS = self.tensor_square() + return TS.sum_of_monomials(((0, w[:i]), (p, w[i:])) + for i in range(len(w) + 1)) + + def degree_on_basis(self, pw): + """ + Return the degree of the element ``w``. + + This is the sum of the power of `f_2` and the indices in the word. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: A = F_algebra(QQ) + sage: [A.degree_on_basis(x.leading_support()) for x in A.some_elements() if x != 0] + [0, 1, 5] + """ + p, w = pw + return ZZ(p + sum(w)) + + def homogeneous_from_vector(self, vec, N): + """ + Convert back a vector to an element of the F-algebra. + + INPUT: + + - ``vec`` -- a vector with coefficients in some base ring + + - ``N`` -- integer, the homogeneous weight + + OUTPUT: + + an homogeneous element of :func:`F_ring` over this base ring + + .. SEEALSO:: :meth:`F_algebra.homogeneous_to_vector` + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: F.homogeneous_from_vector((4,5),6) + 4*f3f3 + 5*f2^3 + sage: _.homogeneous_to_vector() + (4, 5) + """ + if isinstance(vec, (list, tuple)): + vec = vector(vec) + return self.sum(cf * self.monomial(bi) + for cf, bi in zip(vec, basis_f_iterator(N))) + + def _element_constructor_(self, x): + r""" + Convert ``x`` into ``self``. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: R = F_algebra(QQ) + sage: R("3") + f3 + sage: R("2") + f2 + sage: R("2235") + f2^2*f3f5 + """ + if isinstance(x, (str, FiniteWord_class)): + return self.monomial(self._indices(str_to_index(x))) + + P = x.parent() + if isinstance(P, F_algebra): + if P is self: + return x + if P is not self.base_ring(): + return self.element_class(self, x.monomial_coefficients()) + + R = self.base_ring() + # coercion via base ring + x = R(x) + if x == 0: + return self.element_class(self, {}) + return self.from_base_ring_from_one_basis(x) + + def _coerce_map_from_(self, R): + r""" + Return ``True`` if there is a coercion from ``R`` into ``self`` + and ``False`` otherwise. + + The things that coerce into ``self`` are + + - an ``F_algebra`` over a base with a coercion + map into ``self.base_ring()``. + + - Anything with a coercion into ``self.base_ring()``. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(GF(7)); F + F-ring over Finite Field of size 7 + + Elements of the algebra itself canonically coerce in:: + + sage: F.coerce(F("2")*F("3")) # indirect doctest + f2*f3 + + Elements of the integers coerce in, since there is a coerce map + from `\ZZ` to GF(7):: + + sage: F.coerce(1) # indirect doctest + 1 + + There is no coerce map from `\QQ` to `\GF{7}`:: + + sage: F.coerce(2/3) # indirect doctest + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Rational Field + to F-ring over Finite Field of size 7 + + Elements of the base ring coerce in:: + + sage: F.coerce(GF(7)(5)) + 5 + + The algebra over `\ZZ` coerces in, since + `\ZZ` coerces to `\GF{7}`:: + + sage: G = F_algebra(ZZ) + sage: Gx,Gy = G.gen(2), G.gen(3) + sage: z = F.coerce(Gx**2 * Gy);z + f2^2*f3 + sage: z.parent() is F + True + + However, `\GF{7}` does not coerce to `\ZZ`, so the + algebra over `\GF{7}` does not coerce to the one over `\ZZ`:: + + sage: G.coerce(F("2")) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from F-ring over Finite Field + of size 7 to F-ring over Integer Ring + + TESTS:: + + sage: F = F_algebra(ZZ) + sage: G = F_algebra(QQ) + + sage: F._coerce_map_from_(G) + False + sage: G._coerce_map_from_(F) + True + + sage: F._coerce_map_from_(QQ) + False + sage: G._coerce_map_from_(QQ) + True + + sage: F.has_coerce_map_from(PolynomialRing(ZZ, 3, 'x,y,z')) + False + """ + if isinstance(R, F_algebra): + return self.base_ring().has_coerce_map_from(R.base_ring()) + + return self.base_ring().has_coerce_map_from(R) + + class Element(CombinatorialFreeModule.Element): + def coefficient(self, w): + """ + Return the coefficient of the given index. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: S = F.an_element(); S + 3*f2*f3f5 + f2*f5f3 + sage: S.coefficient("235") + 3 + sage: S.coefficient((1,[5,3])) + 1 + """ + if isinstance(w, str): + w = str_to_index(w) + w = self.parent()._indices(w) + return super().coefficient(w) + + def homogeneous_to_vector(self): + """ + Convert an homogeneous element to a vector. + + This is using a fixed enumeration of the basis. + + OUTPUT: + + a vector with coefficients in the base ring + + .. SEEALSO:: :meth:`F_algebra.homogeneous_from_vector` + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: f2 = F("2") + sage: x = f2**4 + 34 * F("233") + sage: x.homogeneous_to_vector() + (0, 0, 34, 1) + sage: x.coefficients() + [34, 1] + + TESTS:: + + sage: x = F.monomial(F._indices((0,[11]))); x + f11 + sage: x.homogeneous_to_vector() + (1, 0, 0, 0, 0, 0, 0, 0, 0) + """ + F = self.parent() + BR = F.base_ring() + if not self: + return vector(BR, []) + a, b = next(iter(self))[0] + N = 2 * a + sum(int(x) for x in b) + return vector(BR, [self.coefficient(b) + for b in basis_f_iterator(N)]) + + def without_f2(self): + """ + Remove all terms containing a power of `f_2`. + + EXAMPLES:: + + sage: from sage.modular.multiple_zeta_F_algebra import F_algebra + sage: F = F_algebra(QQ) + sage: t = 4*F("35")+F("27") + sage: t.without_f2() + 4*f3f5 + """ + F = self.parent() + return F._from_dict({(0, w): cf for (p, w), cf in self if not p}) diff --git a/src/sage/modular/overconvergent/genus0.py b/src/sage/modular/overconvergent/genus0.py index 0e30f40d23b..8f903f76b7c 100644 --- a/src/sage/modular/overconvergent/genus0.py +++ b/src/sage/modular/overconvergent/genus0.py @@ -202,11 +202,12 @@ __ocmfdict = {} + #################### # Factory function # #################### -def OverconvergentModularForms(prime, weight, radius, base_ring=QQ, prec = 20, char = None): +def OverconvergentModularForms(prime, weight, radius, base_ring=QQ, prec=20, char=None): r""" Create a space of overconvergent `p`-adic modular forms of level `\Gamma_0(p)`, over the given base ring. The base ring need not be a @@ -316,7 +317,7 @@ def __init__(self, prime, weight, radius, base_ring, prec, char): if isinstance(weight, WeightCharacter): self._wtchar = weight else: - self._wtchar = WeightSpace(prime, base_ring = char.base_ring())(weight, char, algebraic=True) + self._wtchar = WeightSpace(prime, base_ring=char.base_ring())(weight, char, algebraic=True) if not self._wtchar.is_even(): raise ValueError("Weight-character must be even") @@ -951,7 +952,7 @@ def _convert_to_basis(self, qexp): x = x - self._basis_cache[i] * answer[i] return answer + O(g**n) - def hecke_matrix(self, m, n, use_recurrence = False, exact_arith = False): + def hecke_matrix(self, m, n, use_recurrence=False, exact_arith=False): r""" Calculate the matrix of the `T_m` operator in the basis of this space, truncated to an `n \times n` matrix. Conventions are that operators act @@ -1052,12 +1053,14 @@ def slopes(self, n, use_recurrence=False): print("slopes are only defined for base field QQ or a p-adic field") return [-i for i in slopelist] - def eigenfunctions(self, n, F = None, exact_arith=True): + def eigenfunctions(self, n, F=None, exact_arith=True): """ - Calculate approximations to eigenfunctions of self. These are the - eigenfunctions of self.hecke_matrix(p, n), which are approximations to - the true eigenfunctions. Returns a list of - OverconvergentModularFormElement objects, in increasing order of slope. + Calculate approximations to eigenfunctions of self. + + These are the eigenfunctions of self.hecke_matrix(p, n), which + are approximations to the true eigenfunctions. Returns a list + of OverconvergentModularFormElement objects, in increasing + order of slope. INPUT: @@ -1201,7 +1204,7 @@ def recurrence_matrix(self, use_smithline=True): return self._cached_recurrence_matrix MM = OverconvergentModularForms(self.prime(), 0, 0, base_ring=QQ) - m = MM._discover_recurrence_matrix(use_smithline = True).base_extend(self.base_ring()) + m = MM._discover_recurrence_matrix(use_smithline=True).base_extend(self.base_ring()) r = diagonal_matrix([self._const**i for i in range(self.prime())]) self._cached_recurrence_matrix = (r**(-1)) * m * r @@ -1339,7 +1342,7 @@ def _add_(self, other): sage: f + f # indirect doctest 2-adic overconvergent modular form of weight-character 12 with q-expansion 2 - 131040/1414477*q ... """ - return OverconvergentModularFormElement(self.parent(), gexp = self.gexp() + other.gexp()) + return OverconvergentModularFormElement(self.parent(), gexp=self.gexp() + other.gexp()) def _lmul_(self, x): r""" @@ -1353,7 +1356,7 @@ def _lmul_(self, x): 2-adic overconvergent modular form of weight-character 12 with q-expansion 2 - 131040/1414477*q ... """ - return OverconvergentModularFormElement(self.parent(), gexp = x * self.gexp()) + return OverconvergentModularFormElement(self.parent(), gexp=x * self.gexp()) def _rmul_(self, x): r""" @@ -1367,7 +1370,7 @@ def _rmul_(self, x): 2-adic overconvergent modular form of weight-character 12 with q-expansion 3 - 196560/1414477*q ... """ - return OverconvergentModularFormElement(self.parent(), gexp = x * self.gexp()) + return OverconvergentModularFormElement(self.parent(), gexp=x * self.gexp()) def prec(self): r""" @@ -1636,7 +1639,7 @@ def governing_term(self, r): return i raise RuntimeError("Can't get here") - def valuation_plot(self, rmax = None): + def valuation_plot(self, rmax=None): r""" Draw a graph depicting the growth of the norm of this overconvergent modular form as it approaches the boundary of the overconvergent @@ -1650,8 +1653,8 @@ def valuation_plot(self, rmax = None): Graphics object consisting of 1 graphics primitive """ if rmax is None: - rmax = ZZ(self.prime())/ZZ(1 + self.prime()) - return plot(self.r_ord, (0, rmax) ) + rmax = ZZ(self.prime()) / ZZ(1 + self.prime()) + return plot(self.r_ord, (0, rmax)) def weight(self): r""" diff --git a/src/sage/modular/pollack_stevens/manin_map.py b/src/sage/modular/pollack_stevens/manin_map.py index 74de1b039f3..70465dade8f 100644 --- a/src/sage/modular/pollack_stevens/manin_map.py +++ b/src/sage/modular/pollack_stevens/manin_map.py @@ -762,7 +762,7 @@ def specialize(self, *args): return self.__class__(self._codomain.specialize(*args), self._manin, D, check=False) - def hecke(self, ell, algorithm = 'prep'): + def hecke(self, ell, algorithm='prep'): r""" Return the image of this Manin map under the Hecke operator `T_{\ell}`. diff --git a/src/sage/modular/pollack_stevens/space.py b/src/sage/modular/pollack_stevens/space.py index 8bb41867770..99bff5e6890 100644 --- a/src/sage/modular/pollack_stevens/space.py +++ b/src/sage/modular/pollack_stevens/space.py @@ -851,7 +851,7 @@ def cusps_from_mat(g): return ac, bd -def ps_modsym_from_elliptic_curve(E, sign = 0, implementation='eclib'): +def ps_modsym_from_elliptic_curve(E, sign=0, implementation='eclib'): r""" Return the overconvergent modular symbol associated to an elliptic curve defined over the rationals. diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index b849f1e86ee..47fb713d522 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -8243,4 +8243,3 @@ def __richcmp__(self, other, op): True """ return self.obj._echelon_matrix_richcmp(other.obj, op) - diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index de627d5939a..67991cebd52 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -3743,7 +3743,7 @@ cdef class FreeModuleElement(Vector): # abstract base class from sage.misc.latex import latex vector_delimiters = latex.vector_delimiters() s = '\\left' + vector_delimiters[0] - s += ',\,'.join(latex(a) for a in self.list()) + s += r',\,'.join(latex(a) for a in self.list()) return s + '\\right' + vector_delimiters[1] def dense_vector(self): diff --git a/src/sage/modules/module_functors.py b/src/sage/modules/module_functors.py index 5e84c79008d..497120d02e8 100644 --- a/src/sage/modules/module_functors.py +++ b/src/sage/modules/module_functors.py @@ -75,7 +75,7 @@ class QuotientModuleFunctor(ConstructionFunctor): sage: Q2 = A2 / B2 sage: q3 = Q1.an_element() + Q2.an_element() """ - rank = 5 # ranking of functor, not rank of module + rank = 5 # ranking of functor, not rank of module def __init__(self, relations): """ @@ -187,4 +187,3 @@ def merge(self, other): """ if isinstance(other, QuotientModuleFunctor): return QuotientModuleFunctor(self._relations + other._relations) - diff --git a/src/sage/modules/submodule.py b/src/sage/modules/submodule.py index f8078c4066e..4e0d6994f02 100644 --- a/src/sage/modules/submodule.py +++ b/src/sage/modules/submodule.py @@ -243,4 +243,3 @@ def ambient_module(self): True """ return self._ambient - diff --git a/src/sage/modules/with_basis/cell_module.py b/src/sage/modules/with_basis/cell_module.py index 5c6145d167e..a17882b4e9e 100644 --- a/src/sage/modules/with_basis/cell_module.py +++ b/src/sage/modules/with_basis/cell_module.py @@ -473,4 +473,3 @@ def _acted_upon_(self, scalar, self_on_left=False): # For backward compatibility _lmul_ = _acted_upon_ _rmul_ = _acted_upon_ - diff --git a/src/sage/modules/with_basis/morphism.py b/src/sage/modules/with_basis/morphism.py index b8fe98111b2..3cd841629a9 100644 --- a/src/sage/modules/with_basis/morphism.py +++ b/src/sage/modules/with_basis/morphism.py @@ -1551,6 +1551,7 @@ def pointwise_inverse_function(f): return f.pointwise_inverse() return PointwiseInverseFunction(f) + from sage.structure.sage_object import SageObject class PointwiseInverseFunction(SageObject): r""" @@ -1630,4 +1631,3 @@ def pointwise_inverse(self): True """ return self._pointwise_inverse - diff --git a/src/sage/monoids/free_abelian_monoid.py b/src/sage/monoids/free_abelian_monoid.py index d1a5dce30c1..54771b247e4 100644 --- a/src/sage/monoids/free_abelian_monoid.py +++ b/src/sage/monoids/free_abelian_monoid.py @@ -308,4 +308,3 @@ def cardinality(self): return ZZ.one() from sage.rings.infinity import infinity return infinity - diff --git a/src/sage/monoids/free_monoid_element.py b/src/sage/monoids/free_monoid_element.py index 23a6cc709c7..f23dba93b45 100644 --- a/src/sage/monoids/free_monoid_element.py +++ b/src/sage/monoids/free_monoid_element.py @@ -408,7 +408,6 @@ def to_list(self, indices=False): :meth:`to_word` """ if not indices: - return sum( ([i[0]] * i[1] for i in list(self)), []) + return sum(([i[0]] * i[1] for i in list(self)), []) gens = self.parent().gens() - return sum( ([gens.index(i[0])] * i[1] for i in list(self)), []) - + return sum(([gens.index(i[0])] * i[1] for i in list(self)), []) diff --git a/src/sage/monoids/indexed_free_monoid.py b/src/sage/monoids/indexed_free_monoid.py index cda2681c5be..58910533a9a 100644 --- a/src/sage/monoids/indexed_free_monoid.py +++ b/src/sage/monoids/indexed_free_monoid.py @@ -1002,7 +1002,6 @@ def gen(self, x): if x not in self._indices: raise IndexError("{} is not in the index set".format(x)) try: - return self.element_class(self, {self._indices(x):1}) - except (TypeError, NotImplementedError): # Backup (e.g., if it is a string) - return self.element_class(self, {x:1}) - + return self.element_class(self, {self._indices(x): 1}) + except (TypeError, NotImplementedError): # Backup (e.g., if it is a string) + return self.element_class(self, {x: 1}) diff --git a/src/sage/monoids/monoid.py b/src/sage/monoids/monoid.py index 4ba247e7d99..31e6c219f89 100644 --- a/src/sage/monoids/monoid.py +++ b/src/sage/monoids/monoid.py @@ -70,4 +70,3 @@ def monoid_generators(self): """ from sage.sets.family import Family return Family(self.gens()) - diff --git a/src/sage/numerical/linear_tensor.py b/src/sage/numerical/linear_tensor.py index bdf9529659a..a210ff52fd7 100644 --- a/src/sage/numerical/linear_tensor.py +++ b/src/sage/numerical/linear_tensor.py @@ -478,7 +478,4 @@ def _an_element_(self): (1.0, 0.0) + (5.0, 0.0)*x_2 + (7.0, 0.0)*x_5 """ m = self.free_module().an_element() - return self._element_constructor_({-1:m, 2:5*m, 5:7*m}) - - - + return self._element_constructor_({-1: m, 2: 5 * m, 5: 7 * m}) diff --git a/src/sage/numerical/linear_tensor_constraints.py b/src/sage/numerical/linear_tensor_constraints.py index ce09731cc6e..3da0cd4719a 100644 --- a/src/sage/numerical/linear_tensor_constraints.py +++ b/src/sage/numerical/linear_tensor_constraints.py @@ -446,7 +446,7 @@ def _element_constructor_(self, left, right, equality): def _an_element_(self): """ - Returns an element + Return an element. EXAMPLES:: @@ -457,4 +457,3 @@ def _an_element_(self): """ LT = self.linear_tensors() return LT.an_element() >= 0 - diff --git a/src/sage/plot/bar_chart.py b/src/sage/plot/bar_chart.py index 1f0d7d62cf7..34ed242af4c 100644 --- a/src/sage/plot/bar_chart.py +++ b/src/sage/plot/bar_chart.py @@ -1,5 +1,5 @@ """ -Bar Charts +Bar charts """ # ***************************************************************************** diff --git a/src/sage/plot/bezier_path.py b/src/sage/plot/bezier_path.py index 99290dc9a9d..27c95f10c0c 100644 --- a/src/sage/plot/bezier_path.py +++ b/src/sage/plot/bezier_path.py @@ -1,5 +1,5 @@ r""" -Bezier Paths +Bezier paths """ #***************************************************************************** # Copyright (C) 2006 Alex Clemesha , diff --git a/src/sage/plot/complex_plot.pyx b/src/sage/plot/complex_plot.pyx index 47617d9a353..6f0aeab87ae 100644 --- a/src/sage/plot/complex_plot.pyx +++ b/src/sage/plot/complex_plot.pyx @@ -1,5 +1,5 @@ """ -Complex Plots +Complex plots AUTHORS: diff --git a/src/sage/plot/contour_plot.py b/src/sage/plot/contour_plot.py index 3cf3d0f932d..c0cab456686 100644 --- a/src/sage/plot/contour_plot.py +++ b/src/sage/plot/contour_plot.py @@ -1,5 +1,5 @@ """ -Contour Plots +Contour plots """ # **************************************************************************** # Copyright (C) 2006 Alex Clemesha , diff --git a/src/sage/plot/density_plot.py b/src/sage/plot/density_plot.py index 741b5d9be00..155ac8d7a8e 100644 --- a/src/sage/plot/density_plot.py +++ b/src/sage/plot/density_plot.py @@ -1,5 +1,5 @@ """ -Density Plots +Density plots """ #***************************************************************************** diff --git a/src/sage/plot/line.py b/src/sage/plot/line.py index e4b3b4ddc82..691e3c31307 100644 --- a/src/sage/plot/line.py +++ b/src/sage/plot/line.py @@ -1,5 +1,5 @@ """ -Line Plots +Line plots """ # ***************************************************************************** diff --git a/src/sage/plot/matrix_plot.py b/src/sage/plot/matrix_plot.py index e15b007184e..f62d362ea11 100644 --- a/src/sage/plot/matrix_plot.py +++ b/src/sage/plot/matrix_plot.py @@ -1,5 +1,5 @@ """ -Matrix Plots +Matrix plots """ #***************************************************************************** # Copyright (C) 2006 Alex Clemesha , diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index a64457ef661..37a8000f9aa 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -1,4 +1,6 @@ -"Plotting utilities" +""" +Plotting utilities +""" # **************************************************************************** # Distributed under the terms of the GNU General Public License (GPL) diff --git a/src/sage/plot/plot.py b/src/sage/plot/plot.py index d41b4bad908..b36ee57227c 100644 --- a/src/sage/plot/plot.py +++ b/src/sage/plot/plot.py @@ -1,5 +1,5 @@ r""" -2D Plotting +2D plotting Sage provides extensive 2D plotting functionality. The underlying rendering is done using the matplotlib Python library. diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index ae1fd739499..77dabadc78e 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -1,5 +1,5 @@ r""" -Base Classes for 3D Graphics Objects and Plotting +Base classes for 3D graphics objects and plotting The most important facts about these classes are that you can simply add graphics objects @@ -9,7 +9,7 @@ choosing a viewer and setting various parameters for displaying the graphics. Most of the other methods of these classes are technical and -for special usage. +for special usage. AUTHORS: @@ -999,7 +999,7 @@ cdef class Graphics3d(SageObject): "camera_position","updir", # "look_at", # omit look_at. viewdir is sufficient for most purposes "viewdir") - + # The tachyon "aspectratio" parameter is outdated for normal users: # From the tachyon documentation: # "By using the aspect ratio parameter, one can produce images which look @@ -1085,7 +1085,7 @@ cdef class Graphics3d(SageObject): updir = _flip_orientation(updir) camera_position = _flip_orientation(camera_position) light_position = _flip_orientation(light_position) - + return """ begin_scene resolution {resolution_x:d} {resolution_y:d} @@ -1167,9 +1167,9 @@ end_scene""".format( def _tostring(s): r""" Converts vector information to a space-separated string. - + EXAMPLES:: - + sage: sage.plot.plot3d.base.Graphics3d._tostring((1.0,1.2,-1.3)) '1.00000000000000 1.20000000000000 -1.30000000000000' """ @@ -1682,7 +1682,7 @@ end_scene""".format( the viewpoint, with respect to the cube $[-1,1]\\times[-1,1]\\times[-1,1]$, into which the bounding box of the scene - is scaled and centered. + is scaled and centered. The default viewing direction is towards the origin. - ``viewdir`` (for tachyon) -- (default: None) three coordinates @@ -1713,7 +1713,7 @@ end_scene""".format( * ``'lowest'``: worst quality rendering, preview (and fastest). Sets tachyon command line flag ``-lowestshade``. - + - ``extra_opts`` (for tachyon) -- string (default: empty string); extra options that will be appended to the tachyon command line. diff --git a/src/sage/plot/plot3d/implicit_plot3d.py b/src/sage/plot/plot3d/implicit_plot3d.py index 2eb18f7d64d..aa05059878d 100644 --- a/src/sage/plot/plot3d/implicit_plot3d.py +++ b/src/sage/plot/plot3d/implicit_plot3d.py @@ -1,5 +1,5 @@ """ -Implicit Plots +Implicit plots """ from .implicit_surface import ImplicitSurface diff --git a/src/sage/plot/plot3d/implicit_surface.pyx b/src/sage/plot/plot3d/implicit_surface.pyx index aaa2db0c3a8..0a2d99cb5a7 100644 --- a/src/sage/plot/plot3d/implicit_surface.pyx +++ b/src/sage/plot/plot3d/implicit_surface.pyx @@ -1,5 +1,5 @@ r""" -Graphics 3D Object for Representing and Triangulating Isosurfaces. +Graphics 3D object for representing and triangulating isosurfaces AUTHORS: diff --git a/src/sage/plot/plot3d/index_face_set.pyx b/src/sage/plot/plot3d/index_face_set.pyx index 867529d59c5..642397e9ecf 100644 --- a/src/sage/plot/plot3d/index_face_set.pyx +++ b/src/sage/plot/plot3d/index_face_set.pyx @@ -1,5 +1,5 @@ """ -Indexed Face Sets +Indexed face sets Graphics3D object that consists of a list of polygons, also used for triangulations of other objects. diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index 417b9a3528a..c8179d036c5 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -1,5 +1,5 @@ """ -List Plots +List plots """ from sage.structure.element import is_Matrix diff --git a/src/sage/plot/plot3d/parametric_plot3d.py b/src/sage/plot/plot3d/parametric_plot3d.py index f0411e199fe..e16df517fb8 100644 --- a/src/sage/plot/plot3d/parametric_plot3d.py +++ b/src/sage/plot/plot3d/parametric_plot3d.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Parametric Plots +Parametric plots """ from .parametric_surface import ParametricSurface diff --git a/src/sage/plot/plot3d/parametric_surface.pyx b/src/sage/plot/plot3d/parametric_surface.pyx index ad6ea410e4d..68b388b587e 100644 --- a/src/sage/plot/plot3d/parametric_surface.pyx +++ b/src/sage/plot/plot3d/parametric_surface.pyx @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- r""" -Parametric Surface +Parametric surface Graphics 3D object for triangulating surfaces, and a base class for many other objects that can be represented by a 2D parametrization. diff --git a/src/sage/plot/plot3d/platonic.py b/src/sage/plot/plot3d/platonic.py index ef9a22aabdd..eee95d3290f 100644 --- a/src/sage/plot/plot3d/platonic.py +++ b/src/sage/plot/plot3d/platonic.py @@ -1,5 +1,5 @@ r""" -Platonic Solids +Platonic solids EXAMPLES: The five platonic solids in a row: diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 44620a0edcb..a2bddd8a3a0 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -1,5 +1,5 @@ r""" -Plotting Functions +Plotting functions EXAMPLES:: diff --git a/src/sage/plot/plot3d/plot_field3d.py b/src/sage/plot/plot3d/plot_field3d.py index 4f1a28cc197..bdf39391d3e 100644 --- a/src/sage/plot/plot3d/plot_field3d.py +++ b/src/sage/plot/plot3d/plot_field3d.py @@ -1,5 +1,5 @@ """ -Plotting 3D Fields +Plotting 3D fields """ #***************************************************************************** # Copyright (C) 2009 Jason Grout diff --git a/src/sage/plot/plot3d/texture.py b/src/sage/plot/plot3d/texture.py index deb400773d7..c2aa4f652d1 100644 --- a/src/sage/plot/plot3d/texture.py +++ b/src/sage/plot/plot3d/texture.py @@ -1,5 +1,5 @@ r""" -Texture Support +Texture support This module provides texture/material support for 3D Graphics objects and plotting. This is a very rough common interface for diff --git a/src/sage/plot/plot3d/transform.pyx b/src/sage/plot/plot3d/transform.pyx index 7e91d30823b..b140a1c1c41 100644 --- a/src/sage/plot/plot3d/transform.pyx +++ b/src/sage/plot/plot3d/transform.pyx @@ -1,4 +1,6 @@ -"Transformations" +""" +Transformations +""" #***************************************************************************** # Copyright (C) 2007 Robert Bradshaw diff --git a/src/sage/plot/scatter_plot.py b/src/sage/plot/scatter_plot.py index 83e1836479b..c78b33a5258 100644 --- a/src/sage/plot/scatter_plot.py +++ b/src/sage/plot/scatter_plot.py @@ -1,5 +1,5 @@ """ -Scatter Plots +Scatter plots """ # ***************************************************************************** diff --git a/src/sage/plot/streamline_plot.py b/src/sage/plot/streamline_plot.py index 8e34bcc297b..bd9156bf000 100644 --- a/src/sage/plot/streamline_plot.py +++ b/src/sage/plot/streamline_plot.py @@ -1,5 +1,5 @@ """ -Streamline Plots +Streamline plots """ # **************************************************************************** # Copyright (C) 2006 Alex Clemesha , diff --git a/src/sage/quivers/homspace.py b/src/sage/quivers/homspace.py index 296ae15129c..cb9a36e3eed 100644 --- a/src/sage/quivers/homspace.py +++ b/src/sage/quivers/homspace.py @@ -17,6 +17,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations from sage.categories.homset import Homset from sage.quivers.morphism import QuiverRepHom from sage.misc.cachefunc import cached_method @@ -53,8 +54,8 @@ class QuiverHomSpace(Homset): sage: H.dimension() 2 sage: H.gens() - [Homomorphism of representations of Multi-digraph on 2 vertices, - Homomorphism of representations of Multi-digraph on 2 vertices] + (Homomorphism of representations of Multi-digraph on 2 vertices, + Homomorphism of representations of Multi-digraph on 2 vertices) """ Element = QuiverRepHom @@ -499,25 +500,25 @@ def dimension(self): """ return self._space.dimension() - def gens(self): + def gens(self) -> tuple: """ - Return a list of generators of the hom space (as a `k`-vector + Return a tuple of generators of the hom space (as a `k`-vector space). OUTPUT: - - list of :class:`QuiverRepHom` objects, the generators + - tuple of :class:`QuiverRepHom` objects, the generators EXAMPLES:: sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup() sage: H = Q.S(QQ, 2).Hom(Q.P(QQ, 1)) sage: H.gens() - [Homomorphism of representations of Multi-digraph on 2 vertices, - Homomorphism of representations of Multi-digraph on 2 vertices] + (Homomorphism of representations of Multi-digraph on 2 vertices, + Homomorphism of representations of Multi-digraph on 2 vertices) """ - return [self.element_class(self._domain, self._codomain, f) - for f in self._space.gens()] + return tuple([self.element_class(self._domain, self._codomain, f) + for f in self._space.gens()]) def coordinates(self, hom): """ diff --git a/src/sage/quivers/representation.py b/src/sage/quivers/representation.py index 78ed8ce6d2a..859ff1b10b1 100644 --- a/src/sage/quivers/representation.py +++ b/src/sage/quivers/representation.py @@ -447,7 +447,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** - +from __future__ import annotations from sage.structure.factory import UniqueFactory from sage.modules.module import Module from sage.structure.element import ModuleElement @@ -1915,9 +1915,9 @@ def support(self): return sup - def gens(self, names='v'): + def gens(self, names='v') -> tuple: """ - Return a list of generators of ``self`` as a `k`-module. + Return a tuple of generators of ``self`` as a `k`-module. INPUT: @@ -1928,7 +1928,7 @@ def gens(self, names='v'): OUTPUT: - - list of :class:`QuiverRepElement` objects, the linear generators + - tuple of :class:`QuiverRepElement` objects, the linear generators of the module (over the base ring) .. NOTE:: @@ -1942,14 +1942,14 @@ def gens(self, names='v'): sage: Q = DiGraph({1:{2:['a', 'b']}}).path_semigroup() sage: M = Q.P(QQ, 1) sage: M.gens() - [v_0, v_1, v_2] + (v_0, v_1, v_2) If a string is given then it is used as the name of each generator, with the index of the generator appended in order to differentiate them:: sage: M.gens('generator') - [generator_0, generator_1, generator_2] + (generator_0, generator_1, generator_2) If a list or other iterable variable is given then each generator is named using the appropriate entry. The length of the variable @@ -1960,14 +1960,14 @@ def gens(self, names='v'): ... TypeError: can only concatenate list (not "str") to list sage: M.gens(['x', 'y', 'z']) - [x, y, z] + (x, y, z) Strings are iterable, so if the length of the string is equal to the number of generators then the characters of the string will be used as the names:: sage: M.gens('xyz') - [x, y, z] + (x, y, z) """ # Use names as a list if and only if it is the correct length uselist = (len(names) == self.dimension()) @@ -1986,7 +1986,7 @@ def gens(self, names='v'): basis.append(self({v: m}, names + "_" + str(i))) i += 1 - return basis + return tuple(basis) def coordinates(self, vector): """ diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index 025e9fe80ce..930eccbe57b 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -1,7 +1,7 @@ # distutils: libraries = givaro gmp m # distutils: language = c++ r""" -Givaro Field Elements +Givaro finite field elements Sage includes the Givaro finite field library, for highly optimized arithmetic in finite fields. diff --git a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx index beda02aea78..a9c85582af7 100644 --- a/src/sage/rings/finite_rings/element_ntl_gf2e.pyx +++ b/src/sage/rings/finite_rings/element_ntl_gf2e.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ r""" -Finite Fields of characteristic 2. +Finite field of characteristic 2 elements This implementation uses NTL's GF2E class to perform the arithmetic and is the standard implementation for ``GF(2^n)`` for ``n >= 16``. diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index ffad0442389..caeadff7ae2 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -1,5 +1,5 @@ """ -Base Classes for Finite Fields +Base class for finite fields TESTS:: diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index 685c385cf2e..e42b2bed2dd 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -1,5 +1,5 @@ r""" -Finite Fields +Finite fields Sage supports arithmetic in finite prime and extension fields. Several implementation for prime fields are implemented natively in diff --git a/src/sage/rings/finite_rings/finite_field_givaro.py b/src/sage/rings/finite_rings/finite_field_givaro.py index 6b34b7e66be..a70cfc0c717 100644 --- a/src/sage/rings/finite_rings/finite_field_givaro.py +++ b/src/sage/rings/finite_rings/finite_field_givaro.py @@ -1,5 +1,5 @@ """ -Givaro Finite Field +Givaro finite fields Finite fields that are implemented using Zech logs and the cardinality must be less than `2^{16}`. By default, Conway polynomials are diff --git a/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py b/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py index ee47bba4d1c..d2dd7f49613 100644 --- a/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py +++ b/src/sage/rings/finite_rings/finite_field_ntl_gf2e.py @@ -1,5 +1,5 @@ """ -Finite Fields of Characteristic 2 +Finite fields of characteristic 2 """ #***************************************************************************** diff --git a/src/sage/rings/finite_rings/finite_field_prime_modn.py b/src/sage/rings/finite_rings/finite_field_prime_modn.py index 9129ecb56aa..f2a91186cd9 100644 --- a/src/sage/rings/finite_rings/finite_field_prime_modn.py +++ b/src/sage/rings/finite_rings/finite_field_prime_modn.py @@ -1,5 +1,5 @@ """ -Finite Prime Fields +Finite prime fields AUTHORS: diff --git a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx index d79ea68fc25..ad88a240355 100644 --- a/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx +++ b/src/sage/rings/finite_rings/hom_finite_field_givaro.pyx @@ -5,7 +5,7 @@ # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ """ -Finite field morphisms using Givaro +Givaro finite field morphisms Special implementation for givaro finite fields of: diff --git a/src/sage/rings/finite_rings/homset.py b/src/sage/rings/finite_rings/homset.py index ca4bd31571b..0a7578a092e 100644 --- a/src/sage/rings/finite_rings/homset.py +++ b/src/sage/rings/finite_rings/homset.py @@ -1,5 +1,5 @@ """ -Homset for Finite Fields +Homset for finite fields This is the set of all field homomorphisms between two finite fields. diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index 8e584ee0141..f1342415355 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -1847,12 +1847,8 @@ def FieldIdeal(R): Multivariate Polynomial Ring in x1, x2, x3, x4 over Finite Field in alpha of size 2^4 """ - q = R.base_ring().order() - import sage.rings.infinity if q is sage.rings.infinity.infinity: raise TypeError("Cannot construct field ideal for R.base_ring().order()==infinity") - - return R.ideal([x**q - x for x in R.gens() ]) - + return R.ideal([x**q - x for x in R.gens()]) diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 796dec859f6..50d6fc8af57 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -217,7 +217,6 @@ from sage.arith.functions import lcm from sage.arith.misc import divisors, moebius from sage.combinat.partition import Partition, Partitions -from sage.misc.misc_c import prod from sage.misc.derivative import derivative_parse from sage.categories.integral_domains import IntegralDomains from sage.rings.infinity import infinity diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 5a38cb794b6..cfb71b38abf 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -153,6 +153,11 @@ from collections import Counter from builtins import zip +from sage.categories.homset import Hom +from sage.categories.sets_cat import Sets +from sage.modules.free_module import VectorSpace +from sage.modules.free_module_element import vector +from sage.rings.real_mpfr import RR _NumberFields = NumberFields() @@ -9306,6 +9311,78 @@ def minkowski_embedding(self, B=None, prec=None): return sage.matrix.all.matrix(d) + def logarithmic_embedding(self, prec=53): + r""" + Return the morphism of ``self`` under the logarithmic embedding + in the category Set. + + The logarithmic embedding is defined as a map from the number field ``self`` to `\RR^n`. + + It is defined under Definition 4.9.6 in [Coh1993]_. + + INPUT: + + - ``prec`` -- desired floating point precision. + + OUTPUT: + + - the morphism of ``self`` under the logarithmic embedding in the category Set. + + EXAMPLES:: + + sage: CF. = CyclotomicField(5) + sage: f = CF.logarithmic_embedding() + sage: f(0) + (-1, -1) + sage: f(7) + (3.89182029811063, 3.89182029811063) + + :: + + sage: K. = NumberField(x^3 + 5) + sage: f = K.logarithmic_embedding() + sage: f(0) + (-1, -1) + sage: f(7) + (1.94591014905531, 3.89182029811063) + + :: + + sage: F. = NumberField(x^4 - 8*x^2 + 3) + sage: f = F.logarithmic_embedding() + sage: f(0) + (-1, -1, -1, -1) + sage: f(7) + (1.94591014905531, 1.94591014905531, 1.94591014905531, 1.94591014905531) + """ + def closure_map(x, prec=53): + """ + The function closure of the logarithmic embedding. + """ + K = self + K_embeddings = K.places(prec) + r1, r2 = K.signature() + r = r1 + r2 - 1 + + from sage.rings.all import RealField + Reals = RealField(prec) + + if x == 0: + return vector([-1 for _ in range(r + 1)]) + + x_logs = [] + for i in range(r1): + sigma = K_embeddings[i] + x_logs.append(Reals(abs(sigma(x))).log()) + for i in range(r1, r + 1): + tau = K_embeddings[i] + x_logs.append(2 * Reals(abs(tau(x))).log()) + + return vector(x_logs) + + hom = Hom(self, VectorSpace(RR, len(closure_map(self(0), prec))), Sets()) + return hom(closure_map) + def places(self, all_complex=False, prec=None): r""" Return the collection of all infinite places of self. diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index d33980c4b10..9e80ef1e3c1 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -99,8 +99,12 @@ from sage.rings.number_field.morphism import RelativeNumberFieldHomomorphism_from_abs from sage.libs.pari.all import pari_gen -from sage.rings.rational_field import QQ -from sage.rings.integer_ring import ZZ +from sage.categories.homset import Hom +from sage.categories.sets_cat import Sets +from sage.modules.free_module import VectorSpace +from sage.modules.free_module_element import vector + +from sage.rings.all import RR, QQ, ZZ def is_RelativeNumberField(x): @@ -2062,6 +2066,75 @@ def automorphisms(self): check=False, universe=self.Hom(self)) return self.__automorphisms + def logarithmic_embedding(self, prec=53): + r""" + Return the morphism of ``self`` under the logarithmic embedding + in the category Set. + + The logarithmic embedding is defined as a map from the relative number field ``self`` to `\RR^n`. + + It is defined under Definition 4.9.6 in [Coh1993]_. + + INPUT: + + - ``prec`` -- desired floating point precision. + + OUTPUT: + + - the morphism of ``self`` under the logarithmic embedding in the category Set. + + EXAMPLES:: + + sage: K. = CyclotomicField(3) + sage: R. = K[] + sage: L. = K.extension(x^5 + 5) + sage: f = L.logarithmic_embedding() + sage: f(0) + (-1, -1, -1, -1, -1) + sage: f(5) + (3.21887582486820, 3.21887582486820, 3.21887582486820, + 3.21887582486820, 3.21887582486820) + + :: + + sage: K. = NumberField(x^2 + 1) + sage: t = K['t'].gen() + sage: L. = K.extension(t^4 - i) + sage: f = L.logarithmic_embedding() + sage: f(0) + (-1, -1, -1, -1, -1, -1, -1, -1) + sage: f(3) + (2.19722457733622, 2.19722457733622, 2.19722457733622, 2.19722457733622, + 2.19722457733622, 2.19722457733622, 2.19722457733622, 2.19722457733622) + """ + def closure_map(x, prec=53): + """ + The function closure of the logarithmic embedding. + """ + K = self + K_embeddings = K.places(prec) + r1, r2 = K.signature() + r = r1 + r2 - 1 + + from sage.rings.all import RealField + Reals = RealField(prec) + + if x == 0: + return vector([-1 for _ in range(r + 1)]) + + x_logs = [] + for i in range(r1): + sigma = K_embeddings[i] + x_logs.append(Reals(abs(sigma(x))).log()) + for i in range(r1, r + 1): + tau = K_embeddings[i] + x_logs.append(2 * Reals(abs(tau(x))).log()) + + return vector(x_logs) + + hom = Hom(self, VectorSpace(RR, len(closure_map(self(0), prec))), Sets()) + return hom(closure_map) + def places(self, all_complex=False, prec=None): """ Return the collection of all infinite places of self. diff --git a/src/sage/rings/polynomial/infinite_polynomial_ring.py b/src/sage/rings/polynomial/infinite_polynomial_ring.py index 68e20e1aa74..1bc126c1e00 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_ring.py +++ b/src/sage/rings/polynomial/infinite_polynomial_ring.py @@ -19,7 +19,7 @@ - ``R``, the base ring. It has to be a commutative ring, and in some applications it must even be a field -- ``names``, a list of generator names. Generator names must be alpha-numeric. +- ``names``, a finite list of generator names. Generator names must be alpha-numeric. - ``order`` (optional string). The default order is ``'lex'`` (lexicographic). ``'deglex'`` is degree lexicographic, and ``'degrevlex'`` (degree reverse lexicographic) is possible but discouraged. @@ -180,7 +180,7 @@ If the type of monomial orderings (e.g., 'degrevlex' versus 'lex') or -if the implementations don't match, there is no simplified +if the implementations do not match, there is no simplified construction available:: sage: X. = InfinitePolynomialRing(ZZ) @@ -254,18 +254,24 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +import operator +import re +from functools import reduce from sage.rings.ring import CommutativeRing from sage.categories.rings import Rings from sage.structure.all import SageObject, parent from sage.structure.factory import UniqueFactory from sage.misc.cachefunc import cached_method -import operator -import re -from functools import reduce + +################################################### +# The Construction Functor + +from sage.categories.pushout import InfinitePolynomialFunctor + ############################################################### -## Ring Factory framework +# Ring Factory framework class InfinitePolynomialRingFactory(UniqueFactory): """ @@ -326,23 +332,21 @@ def create_key(self, R, names=('x',), order='lex', implementation='dense'): Traceback (most recent call last): ... ValueError: Infinite Polynomial Rings must have at least one generator - """ if isinstance(names, list): names = tuple(names) if not names: raise ValueError("Infinite Polynomial Rings must have at least one generator") - if len(names)>len(set(names)): - raise ValueError("The variable names must be distinct") - F = InfinitePolynomialFunctor(names,order,implementation) - while hasattr(R,'construction'): + if len(names) > len(set(names)): + raise ValueError("the variable names must be distinct") + F = InfinitePolynomialFunctor(names, order, implementation) + while hasattr(R, 'construction'): C = R.construction() if C is None: break - F = F*C[0] + F = F * C[0] R = C[1] - return (F,R) - + return (F, R) def create_object(self, version, key): """ @@ -352,36 +356,32 @@ def create_object(self, version, key): sage: InfinitePolynomialRing.create_object('1.0', InfinitePolynomialRing.create_key(ZZ, ('x3',))) Infinite polynomial ring in x3 over Integer Ring - """ - if len(key)>2: + if len(key) > 2: # We got an old pickle. By calling the ring constructor, it will automatically # be transformed into the new scheme return InfinitePolynomialRing(*key) # By now, we have different unique keys, based on construction functors - C,R = key + C, R = key from sage.categories.pushout import CompositeConstructionFunctor, InfinitePolynomialFunctor - if isinstance(C,CompositeConstructionFunctor): + if isinstance(C, CompositeConstructionFunctor): F = C.all[-1] - if len(C.all)>1: + if len(C.all) > 1: R = CompositeConstructionFunctor(*C.all[:-1])(R) else: F = C if not isinstance(F, InfinitePolynomialFunctor): - raise TypeError("We expected an InfinitePolynomialFunctor, not %s"%type(F)) - if F._imple=='sparse': + raise TypeError("we expected an InfinitePolynomialFunctor, not %s" % type(F)) + if F._imple == 'sparse': return InfinitePolynomialRing_sparse(R, F._gens, order=F._order) return InfinitePolynomialRing_dense(R, F._gens, order=F._order) -InfinitePolynomialRing = InfinitePolynomialRingFactory('InfinitePolynomialRing') -################################################### -## The Construction Functor +InfinitePolynomialRing = InfinitePolynomialRingFactory('InfinitePolynomialRing') -from sage.categories.pushout import InfinitePolynomialFunctor ############################################################## -## An auxiliary dictionary-like class that returns variables +# An auxiliary dictionary-like class that returns variables class InfiniteGenDict: """ @@ -421,9 +421,8 @@ def __init__(self, Gens): [InfiniteGenDict defined by ['a', 'b'], {'1': 1}] sage: D._D == loads(dumps(D._D)) # indirect doctest True - """ - self._D = dict(zip([(hasattr(X,'_name') and X._name) or repr(X) for X in Gens],Gens)) + self._D = dict(zip(((hasattr(X, '_name') and X._name) or repr(X) for X in Gens), Gens)) def __eq__(self, other): """ @@ -481,16 +480,16 @@ def __getitem__(self, k): sage: type(_) """ - if not isinstance(k, str): - raise KeyError("String expected") + raise KeyError("string expected") L = k.split('_') try: - if len(L)==2: + if len(L) == 2: return self._D[L[0]][int(L[1])] except Exception: pass - raise KeyError("%s is not a variable name"%k) + raise KeyError("%s is not a variable name" % k) + class GenDictWithBasering: """ @@ -513,10 +512,8 @@ class GenDictWithBasering: sage: sage_eval('3*a_3*b_5-1/2*a_7', D) -1/2*a_7 + 3*a_3*b_5 - """ - - def __init__(self,parent, start): + def __init__(self, parent, start): """ INPUT: @@ -547,14 +544,13 @@ def __init__(self,parent, start): KeyError: 'a' sage: D['a'] a - """ P = self._P = parent - if isinstance(start,list): + if isinstance(start, list): self._D = start return self._D = [start] - while hasattr(P,'base_ring') and (P.base_ring() is not P): + while hasattr(P, 'base_ring') and (P.base_ring() is not P): P = P.base_ring() D = P.gens_dict() if isinstance(D, GenDictWithBasering): @@ -562,6 +558,7 @@ def __init__(self,parent, start): break else: self._D.append(D) + def __next__(self): """ Return a dictionary that can be used to interprete strings in the base ring of ``self``. @@ -576,10 +573,9 @@ def __next__(self): GenDict of Univariate Polynomial Ring in t over Rational Field sage: sage_eval('t^2', next(D)) t^2 - """ - if len(self._D)<=1: - raise ValueError("No next term for %s available"%self) + if len(self._D) <= 1: + raise ValueError("no next term for %s available" % self) return GenDictWithBasering(self._P.base_ring(), self._D[1:]) next = __next__ @@ -593,7 +589,7 @@ def __repr__(self): sage: D GenDict of Infinite polynomial ring in a, b over Integer Ring """ - return "GenDict of "+repr(self._P) + return "GenDict of " + repr(self._P) def __getitem__(self, k): """ @@ -613,10 +609,11 @@ def __getitem__(self, k): return D[k] except KeyError: pass - raise KeyError("%s is not a variable name of %s or its iterated base rings"%(k,self._P)) + raise KeyError("%s is not a variable name of %s or its iterated base rings" % (k, self._P)) + ############################################################## -## The sparse implementation +# The sparse implementation class InfinitePolynomialRing_sparse(CommutativeRing): r""" @@ -697,20 +694,19 @@ def __init__(self, R, names, order): True sage: X.gen(1)[2]*Y.gen(0)[1] alpha_1*beta_2 - """ if not names: names = ['x'] for n in names: if not (isinstance(n, str) and n.isalnum() and (not n[0].isdigit())): - raise ValueError("generator names must be alpha-numeric strings not starting with a digit, but %s isn't"%n) + raise ValueError("generator names must be alpha-numeric strings not starting with a digit, but %s is not" % n) if len(names) != len(set(names)): raise ValueError("generator names must be pairwise different") self._names = tuple(names) if not isinstance(order, str): - raise TypeError("The monomial order must be given as a string") + raise TypeError("the monomial order must be given as a string") if R not in Rings().Commutative(): - raise TypeError("The given 'base ring' (= %s) must be a commutative ring" % R) + raise TypeError("the given 'base ring' (= %s) must be a commutative ring" % R) # now, the input is accepted if hasattr(R, '_underlying_ring'): @@ -722,7 +718,7 @@ def __init__(self, R, names, order): self._identify_variable = lambda x, y: (-self._names.index(x), int(y)) self._find_maxshift = re.compile('_([0-9]+)') # findall yields stringrep of the shifts self._find_variables = re.compile('[a-zA-Z0-9]+_[0-9]+') - self._find_varpowers = re.compile(r'([a-zA-Z0-9]+)_([0-9]+)\^?([0-9]*)') # findall yields triple "generator_name", "index", "exponent" + self._find_varpowers = re.compile(r'([a-zA-Z0-9]+)_([0-9]+)\^?([0-9]*)') # findall yields triple "generator_name", "index", "exponent" # Create some small underlying polynomial ring. # It is used to ensure that the parent of the underlying @@ -753,9 +749,8 @@ def __repr__(self): sage: X. = InfinitePolynomialRing(ZZ, order='deglex'); X Infinite polynomial ring in alpha, beta over Integer Ring - """ - return "Infinite polynomial ring in %s over %s"%(", ".join(self._names), self._base) + return "Infinite polynomial ring in %s over %s" % (", ".join(self._names), self._base) def _latex_(self): r""" @@ -794,10 +789,10 @@ def one(self): 1 """ from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial - return InfinitePolynomial(self,self._base(1)) + return InfinitePolynomial(self, self._base(1)) ##################### - ## coercion + # coercion def construction(self): """ @@ -887,7 +882,7 @@ def _element_constructor_(self, x): sage: Y('1/3') Traceback (most recent call last): ... - ValueError: Can't convert 1/3 into an element of Infinite polynomial ring in x over Integer Ring + ValueError: cannot convert 1/3 into an element of Infinite polynomial ring in x over Integer Ring """ from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial # In many cases, the easiest solution is to "simply" evaluate @@ -897,20 +892,20 @@ def _element_constructor_(self, x): try: x = sage_eval(x, self.gens_dict()) except Exception: - raise ValueError("Can't convert %s into an element of %s" % (x, self)) + raise ValueError("cannot convert %s into an element of %s" % (x, self)) P = parent(x) if P is self: return x elif self._base.has_coerce_map_from(P): return InfinitePolynomial(self, self._base(x)) else: - raise ValueError("Can't convert %s into an element of %s" % (x, self)) + raise ValueError("cannot convert %s into an element of %s" % (x, self)) if isinstance(parent(x), InfinitePolynomialRing_sparse): # the easy case - parent == self - is already past - if x.parent() is self._base: # another easy case - return InfinitePolynomial(self,x) - xmaxind = x.max_index() # save for later + if x.parent() is self._base: # another easy case + return InfinitePolynomial(self, x) + xmaxind = x.max_index() # save for later x = x._p else: xmaxind = -1 @@ -932,26 +927,26 @@ def _element_constructor_(self, x): # By now, we can assume that x has a parent, because # types like int have already been done in the previous step; # and also it is not an InfinitePolynomial. - # If it isn't a polynomial (duck typing: we need + # If it is not a polynomial (duck typing: we need # the variables attribute), we fall back to using strings - if not hasattr(x,'variables'): + if not hasattr(x, 'variables'): try: return sage_eval(repr(x), self.gens_dict()) except Exception: - raise ValueError("Can't convert %s into an element of %s" % (x, self)) + raise ValueError("cannot convert %s into an element of %s" % (x, self)) # direct conversion will only be used if the underlying polynomials are libsingular. from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomial_libsingular, MPolynomialRing_libsingular # try interpretation in self._P, if we have a dense implementation - if hasattr(self,'_P'): + if hasattr(self, '_P'): if x.parent() is self._P: - return InfinitePolynomial(self,x) + return InfinitePolynomial(self, x) # It's a shame to use sage_eval. However, it's even more of a shame - # that MPolynomialRing_polydict doesn't work in complicated settings. + # that MPolynomialRing_polydict does not work in complicated settings. # So, if self._P is libsingular (and this will be the case in many # applications!), we do it "nicely". Otherwise, we have to use sage_eval. - if isinstance(x, MPolynomial_libsingular) and isinstance(self._P,MPolynomialRing_libsingular): - if xmaxind == -1: # Otherwise, x has been an InfinitePolynomial + if isinstance(x, MPolynomial_libsingular) and isinstance(self._P, MPolynomialRing_libsingular): + if xmaxind == -1: # Otherwise, x has been an InfinitePolynomial # We infer the correct variable shift. # Note: Since we are in the "libsingular" case, there are # no further "variables" hidden in the base ring of x.parent() @@ -963,7 +958,7 @@ def _element_constructor_(self, x): # This tests admissibility on the fly: VarList.sort(key=self.varname_key, reverse=True) except ValueError: - raise ValueError("Can't convert %s into an element of %s - variables aren't admissible"%(x,self)) + raise ValueError("cannot convert %s into an element of %s - variables are not admissible" % (x, self)) xmaxind = max([int(v.split('_')[1]) for v in VarList]) try: # Apparently, in libsingular, the polynomial conversion is not done by @@ -975,17 +970,17 @@ def _element_constructor_(self, x): if self._max < xmaxind: self.gen()[xmaxind] if self._P.ngens() == x.parent().ngens(): - self.gen()[self._max+1] + self.gen()[self._max + 1] # conversion to self._P will be done in InfinitePolynomial.__init__ return InfinitePolynomial(self, x) except (ValueError, TypeError, NameError): - raise ValueError("Can't convert %s (from %s, but variables %s) into an element of %s - no conversion into underlying polynomial ring %s"%(x,x.parent(),x.variables(),self,self._P)) + raise ValueError("cannot convert %s (from %s, but variables %s) into an element of %s - no conversion into underlying polynomial ring %s" % (x, x.parent(), x.variables(), self, self._P)) # By now, x or self._P are not libsingular. Since MPolynomialRing_polydict # is too buggy, we use string evaluation try: return sage_eval(repr(x), self.gens_dict()) except (ValueError, TypeError, NameError): - raise ValueError("Can't convert %s into an element of %s - no conversion into underlying polynomial ring"%(x,self)) + raise ValueError("cannot convert %s into an element of %s - no conversion into underlying polynomial ring" % (x, self)) # By now, we are in the sparse case. try: @@ -996,48 +991,48 @@ def _element_constructor_(self, x): # This tests admissibility on the fly: VarList.sort(key=self.varname_key, reverse=True) except ValueError: - raise ValueError("Can't convert %s into an element of %s - variables aren't admissible"%(x,self)) + raise ValueError("cannot convert %s into an element of %s - variables are not admissible" % (x, self)) - if len(VarList)==1: + if len(VarList) == 1: # univariate polynomial rings are crab. So, make up another variable. - if VarList[0]==self._names[0]+'_0': - VarList.append(self._names[0]+'_1') + if VarList[0] == self._names[0] + '_0': + VarList.append(self._names[0] + '_1') else: - VarList.append(self._names[0]+'_0') + VarList.append(self._names[0] + '_0') # We ensure that polynomial conversion is done by names; # the problem is that it is done by names if the number of variables coincides. - if len(VarList)==x.parent().ngens(): + if len(VarList) == x.parent().ngens(): BigList = x.parent().variable_names() ind = 2 - while self._names[0]+'_'+str(ind) in BigList: - ind+=1 - VarList.append(self._names[0]+'_'+str(ind)) + while self._names[0] + '_' + str(ind) in BigList: + ind += 1 + VarList.append(self._names[0] + '_' + str(ind)) try: VarList.sort(key=self.varname_key, reverse=True) except ValueError: - raise ValueError("Can't convert %s into an element of %s; the variables aren't admissible"%(x,self)) + raise ValueError("cannot convert %s into an element of %s; the variables are not admissible" % (x, self)) from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing R = PolynomialRing(self._base, VarList, order=self._order) - if isinstance(R, MPolynomialRing_libsingular) and isinstance(x,MPolynomial_libsingular): # everything else is so buggy that it's even not worth to try. + if isinstance(R, MPolynomialRing_libsingular) and isinstance(x, MPolynomial_libsingular): # everything else is so buggy that it's even not worth to try. try: # Problem: If there is only a partial overlap in the variables # of x.parent() and R, then R(x) raises an error (which, I think, # is a bug, since we talk here about conversion, not coercion). # Hence, for being on the safe side, we coerce into a pushout ring: - x = R(1)*x - return InfinitePolynomial(self,x) + x = R(1) * x + return InfinitePolynomial(self, x) except Exception: # OK, last resort, to be on the safe side try: return sage_eval(repr(x), self.gens_dict()) - except (ValueError,TypeError,NameError): - raise ValueError("Can't convert %s into an element of %s; conversion of the underlying polynomial failed"%(x,self)) + except (ValueError, TypeError, NameError): + raise ValueError("cannot convert %s into an element of %s; conversion of the underlying polynomial failed" % (x, self)) else: try: return sage_eval(repr(x), self.gens_dict()) - except (ValueError,TypeError,NameError): - raise ValueError("Can't convert %s into an element of %s"%(x,self)) + except (ValueError, TypeError, NameError): + raise ValueError("cannot convert %s into an element of %s" % (x, self)) def tensor_with_ring(self, R): """ @@ -1073,20 +1068,20 @@ def tensor_with_ring(self, R): True """ if not R.has_coerce_map_from(self._underlying_ring): - raise TypeError("We can't tensor with "+repr(R)) + raise TypeError("we cannot tensor with " + repr(R)) B = self.base_ring() - if hasattr(B,'tensor_with_ring'): + if hasattr(B, 'tensor_with_ring'): return InfinitePolynomialRing(B.tensor_with_ring(R), self._names, self._order, implementation='sparse') - if hasattr(B,'change_ring'): # e.g., polynomial rings + if hasattr(B, 'change_ring'): # e.g., polynomial rings return InfinitePolynomialRing(B.change_ring(R), self._names, self._order, implementation='sparse') # try to find the correct base ring in other ways: try: - o = B.one()*R.one() + o = B.one() * R.one() except Exception: - raise TypeError("We can't tensor with "+repr(R)) + raise TypeError("we cannot tensor with " + repr(R)) return InfinitePolynomialRing(o.parent(), self._names, self._order, implementation='sparse') - ## Basic Ring Properties + # Basic Ring Properties # -- some stuff that is useful for quotient rings etc. def is_noetherian(self): """ @@ -1230,7 +1225,6 @@ def gen(self, i=None): sage: XX = InfinitePolynomialRing(GF(5)) sage: XX.gen(0) is XX.gen() True - """ if i is not None and i > len(self._names): raise ValueError @@ -1449,48 +1443,49 @@ def __getitem__(self, i): alpha_1 """ if int(i) != i: - raise ValueError("The index (= %s) must be an integer" % i) + raise ValueError("the index (= %s) must be an integer" % i) i = int(i) if i < 0: - raise ValueError("The index (= %s) must be non-negative" % i) + raise ValueError("the index (= %s) must be non-negative" % i) P = self._parent from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial_dense, InfinitePolynomial_sparse from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing OUT = self._output.get(i) - if hasattr(P,'_P'): + if hasattr(P, '_P'): if i <= P._max: - #return InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) + # return InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) if OUT is None: - self._output[i] = InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) + self._output[i] = InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name + '_' + str(i)))) else: if OUT._p.parent() is not P._P: OUT._p = P._P(OUT._p) return self._output[i] - #Calculate all of the new names needed + # Calculate all of the new names needed try: - names = [ [name+'_'+str(j) for name in P._names] for j in range(i+1)] + names = [[name + '_' + str(j) for name in P._names] + for j in range(i + 1)] except OverflowError: - raise IndexError("Variable index is too big - consider using the sparse implementation") + raise IndexError("variable index is too big - consider using the sparse implementation") names = reduce(operator.add, names) names.sort(key=P.varname_key, reverse=True) - #Create the new polynomial ring - P._P = PolynomialRing(P.base_ring(), names, order = P._order) - ##Get the generators + # Create the new polynomial ring + P._P = PolynomialRing(P.base_ring(), names, order=P._order) + # Get the generators P._max = i - #return InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) - self._output[i] = InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) + # return InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name+'_'+str(i)))) + self._output[i] = InfinitePolynomial_dense(P, P._P.gen(P._P.variable_names().index(self._name + '_' + str(i)))) return self._output[i] # Now, we are in the sparse implementation - if OUT is not None: # in the sparse implementation, this is ok + if OUT is not None: # in the sparse implementation, this is ok return OUT - if i==0: - names = [self._name+'_0',self._name+'_1'] + if i == 0: + names = [self._name + '_0', self._name + '_1'] else: - names = [self._name+'_0',self._name+'_'+str(i)] + names = [self._name + '_0', self._name + '_' + str(i)] names.sort(key=P.varname_key, reverse=True) Pol = PolynomialRing(P.base_ring(), names, order=P._order) - #return InfinitePolynomial_sparse(P, Pol.gen(names.index(self._name+'_'+str(i)))) - self._output[i] = InfinitePolynomial_sparse(P, Pol.gen(names.index(self._name+'_'+str(i)))) + # return InfinitePolynomial_sparse(P, Pol.gen(names.index(self._name+'_'+str(i)))) + self._output[i] = InfinitePolynomial_sparse(P, Pol.gen(names.index(self._name + '_' + str(i)))) return self._output[i] def _repr_(self): @@ -1500,9 +1495,8 @@ def _repr_(self): sage: X. = InfinitePolynomialRing(QQ) sage: x # indirect doctest x_* - """ - return self._name+'_*' + return self._name + '_*' def __str__(self): """ @@ -1511,12 +1505,12 @@ def __str__(self): sage: X. = InfinitePolynomialRing(QQ) sage: print(x) # indirect doctest Generator for the x's in Infinite polynomial ring in x, y over Rational Field - """ - return "Generator for the %s's in %s"%(self._name, self._parent) + return "Generator for the %s's in %s" % (self._name, self._parent) + ############################################################## -## The dense implementation +# The dense implementation class InfinitePolynomialRing_dense(InfinitePolynomialRing_sparse): """ @@ -1537,14 +1531,14 @@ def __init__(self, R, names, order): """ if not names: names = ['x'] - #Generate the initial polynomial ring + # Generate the initial polynomial ring self._max = 0 InfinitePolynomialRing_sparse.__init__(self, R, names, order) self._P = self._minP - #self._pgens = self._P.gens() + # self._pgens = self._P.gens() ##################### - ## Coercion + # Coercion def construction(self): """ @@ -1598,17 +1592,17 @@ def tensor_with_ring(self, R): """ if not R.has_coerce_map_from(self._underlying_ring): - raise TypeError("We can't tensor with "+repr(R)) + raise TypeError("we cannot tensor with " + repr(R)) B = self.base_ring() - if hasattr(B,'tensor_with_ring'): + if hasattr(B, 'tensor_with_ring'): return InfinitePolynomialRing(B.tensor_with_ring(R), self._names, self._order, implementation='dense') - if hasattr(B,'change_ring'): # e.g., polynomial rings + if hasattr(B, 'change_ring'): # e.g., polynomial rings return InfinitePolynomialRing(B.change_ring(R), self._names, self._order, implementation='dense') # try to find the correct base ring in other ways: try: - o = B.one()*R.one() + o = B.one() * R.one() except Exception: - raise TypeError("We can't tensor with "+repr(R)) + raise TypeError("we cannot tensor with " + repr(R)) return InfinitePolynomialRing(o.parent(), self._names, self._order, implementation='dense') def polynomial_ring(self): diff --git a/src/sage/rings/polynomial/msolve.py b/src/sage/rings/polynomial/msolve.py index 65ae859f751..0be0c676758 100644 --- a/src/sage/rings/polynomial/msolve.py +++ b/src/sage/rings/polynomial/msolve.py @@ -8,7 +8,7 @@ This module provide implementations of some operations on polynomial ideals based on msolve. -Note that msolve must be installed separately. +Note that the `optional package msolve <../spkg/msolve.html>`_ must be installed. .. SEEALSO:: @@ -46,13 +46,11 @@ def _run_msolve(ideal, options): # Run msolve - msolve().require() - drlpolring = ideal.ring().change_ring(order='degrevlex') polys = ideal.change_ring(drlpolring).gens() msolve_in = tempfile.NamedTemporaryFile(mode='w', encoding='ascii', delete=False) - command = ["msolve", "-f", msolve_in.name] + options + command = [msolve().absolute_filename(), "-f", msolve_in.name] + options try: print(",".join(drlpolring.variable_names()), file=msolve_in) print(base.characteristic(), file=msolve_in) @@ -290,7 +288,7 @@ def to_poly(p, d=1, *, upol=PolynomialRing(base, 't')): variety = [] for rt in elim_roots: den_of_rt = den(rt) - point = [-p(rt)/den_of_rt for p in param] + point = [-p(rt) / den_of_rt for p in param] if len(param) != len(vars): point.append(rt) assert len(point) == len(vars) @@ -313,4 +311,3 @@ def to_poly(p, d=1, *, upol=PolynomialRing(base, 't')): for point in l] return [KeyConvertingDict(out_ring, zip(vars, point)) for point in variety] - diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 4e1937a4645..c2de7cbd075 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2467,7 +2467,8 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True {y: 0.3611030805286474?, x: 2.769292354238632?}, {y: 1, x: 1}] - We can also use the external program msolve to compute the variety. + We can also use the `optional package msolve <../spkg/msolve.html>`_ + to compute the variety. See :mod:`~sage.rings.polynomial.msolve` for more information. :: sage: I.variety(RBF, algorithm='msolve', proof=False) # optional - msolve @@ -2543,9 +2544,9 @@ def variety(self, ring=None, *, algorithm="triangular_decomposition", proof=True uses triangular decomposition, via Singular if possible, falling back on a toy implementation otherwise. - - With ``algorithm`` = ``"msolve"``, calls the external program - `msolve `_ (if available in the system - program search path). Note that msolve uses heuristics and therefore + - With ``algorithm`` = ``"msolve"``, uses the + `optional package msolve <../spkg/msolve.html>`_. + Note that msolve uses heuristics and therefore requires setting the ``proof`` flag to ``False``. See :mod:`~sage.rings.polynomial.msolve` for more information. """ @@ -4089,7 +4090,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal Macaulay2's ``GroebnerBasis`` command with the strategy "MGB" (if available) 'msolve' - `msolve `_ (if available, degrevlex order, + `optional package msolve <../spkg/msolve.html>`_ (degrevlex order, prime fields) 'magma:GroebnerBasis' @@ -4215,9 +4216,8 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal sage: I.groebner_basis('macaulay2:mgb') # optional - macaulay2 [c^3 + 28*c^2 - 37*b + 13*c, b^2 - 41*c^2 + 20*b - 20*c, b*c - 19*c^2 + 10*b + 40*c, a + 2*b + 2*c - 1] - Over prime fields of small characteristic, we can also use - `msolve `_ (if available in the system program - search path):: + Over prime fields of small characteristic, we can also use the + `optional package msolve <../spkg/msolve.html>`_:: sage: R. = PolynomialRing(GF(101), 3) sage: I = sage.rings.ideal.Katsura(R,3) # regenerate to prevent caching @@ -5458,4 +5458,3 @@ def __richcmp__(self, other, op): return not (contained and contains) else: # remaining case < return contained and not contains - diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index e369473c3c4..41850904621 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -328,8 +328,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: S. = BooleanPolynomialRing(2, order='deglex') sage: P == S False - - """ def __init__(self, n=None, names=None, order='lex'): """ @@ -348,7 +346,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): cdef Py_ssize_t i, j, bstart, bsize if names is None: - raise TypeError("You must specify the names of the variables.") + raise TypeError("you must specify the names of the variables") if n is None: if isinstance(names, (tuple, list)): @@ -357,10 +355,10 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): try: n = int(n) except TypeError as msg: - raise TypeError("Number of variables must be an integer") + raise TypeError("number of variables must be an integer") if n < 1: - raise ValueError("Number of variables must be greater than 1.") + raise ValueError("number of variables must be greater than 1") self.pbind = sig_malloc(n*sizeof(Py_ssize_t)) @@ -369,13 +367,13 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): try: pb_order_code = order_mapping[order[0].name()] except KeyError: - raise ValueError("Only order keys " + + raise ValueError("only order keys " + ', '.join(order_mapping.keys()) + - " are supported.") + " are supported") if order.is_block_order(): if pb_order_code is pblp: - raise ValueError("Only deglex and degneglex are supported for block orders.") + raise ValueError("only deglex and degneglex are supported for block orders") elif pb_order_code is pbdlex: pb_order_code = pbblock_dlex elif pb_order_code is pbdp_asc: @@ -384,8 +382,8 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): pb_order_code = pbblock_dp for i in range(1, len(order.blocks())): if order[0].name() != order[i].name(): - raise ValueError("Each block must have the same order type " - "(deglex and degneglex) for block orders.") + raise ValueError("each block must have the same order type " + "(deglex and degneglex) for block orders") if pb_order_code is pbdp: for i in range(n): @@ -506,8 +504,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): INPUT: - - ``i`` - an integer or a boolean monomial in one - variable + - ``i`` -- an integer or a boolean monomial in one variable EXAMPLES:: @@ -530,10 +527,10 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): if len(i) == 1: i = i.index() else: - raise TypeError("Boolean monomials must be in one variable only.") + raise TypeError("boolean monomials must be in one variable only") cdef idx = int(i) if idx < 0 or idx >= self._pbring.nVariables(): - raise ValueError("Generator not defined.") + raise ValueError("generator not defined") return new_BP_from_PBVar(self, self._pbring.variable(self.pbind[idx])) def gens(self): @@ -551,7 +548,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: P = BooleanPolynomialRing(10,'x') sage: P.gens() (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) - """ return tuple(new_BP_from_PBVar(self, self._pbring.variable(self.pbind[i])) @@ -559,14 +555,12 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): def change_ring(self, base_ring=None, names=None, order=None): """ - Return a new multivariate polynomial ring with base ring - ``base_ring``, variable names set to ``names``, and term - ordering given by ``order``. + Return a new multivariate polynomial ring with base ring ``base_ring``, + variable names set to ``names``, and term ordering given by ``order``. When ``base_ring`` is not specified, this function returns a ``BooleanPolynomialRing`` isomorphic to ``self``. Otherwise, - this returns a ``MPolynomialRing``. Each argument above is - optional. + this returns a ``MPolynomialRing``. Each argument above is optional. INPUT: @@ -590,7 +584,6 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: T.term_order() Lexicographic term order """ - if names is None: names = self.variable_names() if order is None: @@ -1082,10 +1075,9 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: R.remove_var(x,y,z) Traceback (most recent call last): ... - ValueError: impossible to use the original term order (most likely because it was a block order). Please specify the term order for the subring + ValueError: impossible to use the original term order (most likely because it was a block order); please specify the term order for the subring sage: R.remove_var(x,y,z, order='deglex') Boolean PolynomialRing in u, v - """ vars = list(self.variable_names()) for v in var: @@ -1096,7 +1088,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): try: return BooleanPolynomialRing(names=vars, order=self.term_order()) except ValueError: - raise ValueError("impossible to use the original term order (most likely because it was a block order). Please specify the term order for the subring") + raise ValueError("impossible to use the original term order (most likely because it was a block order); please specify the term order for the subring") else: return BooleanPolynomialRing(names=vars, order=order) @@ -1205,7 +1197,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): sage: P.random_element(degree=4) Traceback (most recent call last): ... - ValueError: Given degree should be less than or equal to number of variables (3) + ValueError: given degree should be less than or equal to number of variables (3) sage: f = P.random_element(degree=1, terms=5) sage: f.degree() <= 1 @@ -1251,7 +1243,7 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): degree = Integer(degree) if degree > nvars: - raise ValueError("Given degree should be less than or equal to number of variables (%s)" % nvars) + raise ValueError("given degree should be less than or equal to number of variables (%s)" % nvars) tot_terms = 0 monom_counts = [] @@ -1638,10 +1630,10 @@ cdef class BooleanPolynomialRing(MPolynomialRing_base): if len(i) == 1: i = i.index() else: - raise TypeError("Boolean monomials must be in one variable only.") + raise TypeError("boolean monomials must be in one variable only") i = int(i) if i < 0 or i >= self._pbring.nVariables(): - raise ValueError("Generator not defined.") + raise ValueError("generator not defined") return new_BM_from_PBVar(self._monom_monoid, self, self._pbring.variable(self.pbind[i])) @@ -1998,7 +1990,7 @@ class BooleanMonomialMonoid(UniqueRepresentation, Monoid_class): x50 """ if i < 0 or i >= self.ngens(): - raise ValueError("Generator not defined.") + raise ValueError("generator not defined") cdef PBVar newvar newvar = PBBooleVariable(i, (self._ring)._pbring) @@ -2382,11 +2374,11 @@ cdef class BooleanMonomial(MonoidElement): """ P = self.parent() if args and kwds: - raise ValueError("Using keywords and regular arguments not supported.") + raise ValueError("using keywords and regular arguments not supported") if args: - d = {} if len(args) > self._parent.ngens(): - raise ValueError("Number of arguments is greater than the number of variables of parent ring.") + raise ValueError("number of arguments is greater than the number of variables of parent ring") + d = {} for i in range(len(args)): d[i] = args[i] elif kwds: @@ -2522,7 +2514,7 @@ cdef class BooleanMonomial(MonoidElement): return self._pbmonom.deg() if x not in self._parent.gens(): - raise ValueError("x must be one of the generators of the parent.") + raise ValueError("x must be one of the generators of the parent") if self.reducible_by(x.lm()): return 1 @@ -3004,7 +2996,7 @@ cdef class BooleanPolynomial(MPolynomial): sage: a._repr_with_changed_varnames([1,'y','z']) Traceback (most recent call last): ... - TypeError: varnames has entries with wrong type. + TypeError: varnames has entries with wrong type :: @@ -3016,7 +3008,7 @@ cdef class BooleanPolynomial(MPolynomial): cdef int N = P._pbring.nVariables() if len(varnames) != N: - raise TypeError("len(varnames) doesn't equal self.parent().ngens()") + raise TypeError("len(varnames) is not equal to self.parent().ngens()") orig_varnames = P.variable_names() try: @@ -3025,7 +3017,7 @@ cdef class BooleanPolynomial(MPolynomial): except TypeError: for i in range(N): P._pbring.setVariableName(i, str_to_bytes(orig_varnames[i])) - raise TypeError("varnames has entries with wrong type.") + raise TypeError("varnames has entries with wrong type") s = ccrepr(self._pbpoly) for i in range(N): P._pbring.setVariableName(i, str_to_bytes(orig_varnames[i])) @@ -3256,7 +3248,7 @@ cdef class BooleanPolynomial(MPolynomial): sage: p^-1 Traceback (most recent call last): ... - NotImplementedError: Negative exponents for non constant boolean polynomials not implemented. + NotImplementedError: negative exponents for non constant boolean polynomials not implemented :: @@ -3278,7 +3270,7 @@ cdef class BooleanPolynomial(MPolynomial): elif self._pbpoly.isZero(): raise ZeroDivisionError else: - raise NotImplementedError("Negative exponents for non constant boolean polynomials not implemented.") + raise NotImplementedError("negative exponents for non constant boolean polynomials not implemented") def __neg__(BooleanPolynomial self): r""" @@ -3953,11 +3945,11 @@ cdef class BooleanPolynomial(MPolynomial): P = self._parent cdef int N = P.ngens() if args and kwds: - raise ValueError("Using keywords and regular arguments not supported.") + raise ValueError("using keywords and regular arguments not supported") if args: d = {} if len(args) != N: - raise ValueError("Number of arguments is different from the number of variables of parent ring.") + raise ValueError("number of arguments is different from the number of variables of parent ring") for i in range(N): arg = args[i] try: @@ -4565,7 +4557,7 @@ cdef class BooleanPolynomial(MPolynomial): L.append(tuple(l)) return tuple(L) else: - raise TypeError("Type '%s' of s not supported." % type(s)) + raise TypeError("type '%s' of s not supported" % type(s)) def spoly(self, BooleanPolynomial rhs): r""" @@ -4665,7 +4657,7 @@ cdef class BooleanPolynomial(MPolynomial): sage: a.reduce([None,None]) Traceback (most recent call last): ... - TypeError: argument must be a BooleanPolynomial. + TypeError: argument must be a BooleanPolynomial """ from sage.rings.polynomial.pbori.pbori import red_tail if not I: @@ -4674,7 +4666,7 @@ cdef class BooleanPolynomial(MPolynomial): I = I.gens() first = I[0] if first is None: - raise TypeError("argument must be a BooleanPolynomial.") + raise TypeError("argument must be a BooleanPolynomial") g = ReductionStrategy(first.ring()) g.opt_red_tail = True for p in I: @@ -4729,7 +4721,7 @@ cdef class PolynomialConstruct: # So, it is just a conversion. [Simon King] return (ring)._element_constructor_(x) - raise TypeError("Cannot generate Boolean polynomial from %s , %s" % + raise TypeError("cannot generate Boolean polynomial from %s , %s" % (type(x), type(ring))) @@ -4768,7 +4760,7 @@ cdef class MonomialConstruct: return result.lm() return result except Exception: - raise TypeError("Cannot convert to Boolean Monomial %s" % + raise TypeError("cannot convert to Boolean Monomial %s" % type(x)) cdef class VariableConstruct: @@ -4790,11 +4782,10 @@ cdef class VariableConstruct: """ if isinstance(arg, BooleanPolynomialRing): return arg.variable(0) - elif isinstance(ring, BooleanPolynomialRing): + if isinstance(ring, BooleanPolynomialRing): return (ring).variable(arg) - else: - raise TypeError("todo polynomial factory %s%s" % - (str(type(arg)), str(type(ring)))) + raise TypeError("todo polynomial factory %s%s" % + (str(type(arg)), str(type(ring)))) cdef class BooleanPolynomialIterator: @@ -4932,7 +4923,7 @@ class BooleanPolynomialIdeal(MPolynomialIdeal): - ``lazy`` - (default: ``True``) - ``invert`` - setting ``invert=True`` input and output get a - transformation ``x+1`` for each variable ``x``, which shouldn't + transformation ``x+1`` for each variable ``x``, which should not effect the calculated GB, but the algorithm. - ``other_ordering_first`` - possible values are ``False`` or @@ -5526,7 +5517,7 @@ cdef class BooleSet: elif isinstance(rhs, BooleanPolynomial): s = (rhs)._pbpoly.set() else: - raise TypeError("Argument 'rhs' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(rhs)) + raise TypeError("argument 'rhs' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(rhs)) return new_BS_from_PBSet(self._pbset.diff(s), self._ring) def union(self, rhs): @@ -5560,7 +5551,7 @@ cdef class BooleSet: elif isinstance(rhs, BooleanPolynomial): s = (rhs)._pbpoly.set() else: - raise TypeError("Argument 'rhs' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(rhs)) + raise TypeError("argument 'rhs' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(rhs)) return new_BS_from_PBSet(self._pbset.unite(s), self._ring) def change(self, ind): @@ -6175,7 +6166,7 @@ cdef class BooleanPolynomialVector: elif isinstance(el, BooleanMonomial): p = PBBoolePolynomial((el)._pbmonom) else: - raise TypeError("Argument 'el' has incorrect type (expected BooleanPolynomial or BooleanMonomial, got %s)" % type(el)) + raise TypeError("argument 'el' has incorrect type (expected BooleanPolynomial or BooleanMonomial, got %s)" % type(el)) self._vec.push_back(p) cdef inline BooleanPolynomialVector new_BPV_from_PBPolyVector( @@ -6255,12 +6246,12 @@ cdef class ReductionStrategy: sage: red.add_generator(None) Traceback (most recent call last): ... - TypeError: argument must be a BooleanPolynomial. + TypeError: argument must be a BooleanPolynomial """ if p is None: - raise TypeError("argument must be a BooleanPolynomial.") + raise TypeError("argument must be a BooleanPolynomial") if p._pbpoly.isZero(): - raise ValueError("zero generators not allowed.") + raise ValueError("zero generators not allowed") deref(self._strat).addGenerator(p._pbpoly) def nf(self, BooleanPolynomial p): @@ -6525,7 +6516,6 @@ cdef class FGLMStrategy: Traceback (most recent call last): ... RuntimeError... - """ cdef BooleanPolynomialRing _from_ring, _to_ring @@ -6598,7 +6588,7 @@ cdef class GroebnerStrategy: self._strat = make_shared[PBGBStrategy]((param)._pbring) self._parent = param else: - raise ValueError("Cannot generate GroebnerStrategy from %s." % + raise ValueError("cannot generate GroebnerStrategy from %s" % type(param)) self.reduction_strategy = ReductionStrategy(self._parent) @@ -6629,7 +6619,7 @@ cdef class GroebnerStrategy: [a + b, a + c] """ if p._pbpoly.isZero(): - raise ValueError("zero generators not allowed.") + raise ValueError("zero generators not allowed") deref(self._strat).addGeneratorDelayed(p._pbpoly) def add_generator(self, BooleanPolynomial p): @@ -6654,7 +6644,7 @@ cdef class GroebnerStrategy: ValueError: strategy already contains a polynomial with same lead """ if p._pbpoly.isZero(): - raise ValueError("zero generators not allowed.") + raise ValueError("zero generators not allowed") if deref(self._strat).generators.leadingTerms.owns(p._pbpoly.lead()): raise ValueError("strategy already contains a polynomial with same lead") deref(self._strat).generators.addGenerator(p._pbpoly) @@ -6689,7 +6679,7 @@ cdef class GroebnerStrategy: [a + c, b + c] """ if p._pbpoly.isZero(): - raise ValueError("zero generators not allowed.") + raise ValueError("zero generators not allowed") deref(self._strat).addAsYouWish(p._pbpoly) def implications(self, i): @@ -7207,7 +7197,7 @@ def zeros(pol, BooleSet s): elif isinstance(pol, BooleanMonomial): p = PBBoolePolynomial((pol)._pbmonom) else: - raise TypeError("Argument 'p' has incorrect type (expected BooleanPolynomial or BooleanMonomial, got %s)" % type(pol)) + raise TypeError("argument 'p' has incorrect type (expected BooleanPolynomial or BooleanMonomial, got %s)" % type(pol)) return new_BS_from_PBSet(pb_zeros(p, s._pbset), s._ring) @@ -7256,13 +7246,13 @@ def interpolate(zero, one): z = (zero)._pbpoly.set() ring = (zero)._parent else: - raise TypeError("Argument 'zero' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(zero)) + raise TypeError("argument 'zero' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(zero)) if isinstance(one, BooleSet): o = (one)._pbset elif isinstance(one, BooleanPolynomial): o = (one)._pbpoly.set() else: - raise TypeError("Argument 'one' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(one)) + raise TypeError("argument 'one' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(one)) return new_BP_from_PBPoly(ring, pb_interpolate(z, o)) @@ -7333,13 +7323,13 @@ def interpolate_smallest_lex(zero, one): elif isinstance(zero, BooleanPolynomial): z = (zero)._pbpoly.set() else: - raise TypeError("Argument 'zero' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(zero)) + raise TypeError("argument 'zero' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(zero)) if isinstance(one, BooleSet): o = (one)._pbset elif isinstance(one, BooleanPolynomial): o = (one)._pbpoly.set() else: - raise TypeError("Argument 'one' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(one)) + raise TypeError("argument 'one' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(one)) return new_BP_from_PBPoly(zero.ring(), pb_interpolate_smallest_lex(z, o)) @@ -7400,7 +7390,7 @@ def ll_red_nf_redsb(p, BooleSet reductors): t = PBBoolePolynomial((p)._pbmonom) parent = (p)._ring else: - raise TypeError("Argument 'p' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(p)) + raise TypeError("argument 'p' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(p)) res = pb_ll_red_nf(t, reductors._pbset) @@ -7513,7 +7503,7 @@ def if_then_else(root, a, b): sage: if_then_else(x5, f0, f1) Traceback (most recent call last): ... - IndexError: index of root must be less than the values of roots of the branches. + IndexError: index of root must be less than the values of roots of the branches """ cdef PBSet a_set, b_set cdef PBSet res @@ -7525,14 +7515,14 @@ def if_then_else(root, a, b): b_set = (b)._pbpoly.set() ring = (b)._parent else: - raise TypeError("Argument 'b' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(b)) + raise TypeError("argument 'b' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(b)) if isinstance(a, BooleSet): a_set = (a)._pbset elif isinstance(a, BooleanPolynomial): a_set = (a)._pbpoly.set() else: - raise TypeError("Argument 'a' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(a)) + raise TypeError("argument 'a' has incorrect type (expected BooleSet or BooleanPolynomial, got %s)" % type(a)) try: root = int(root) @@ -7541,22 +7531,22 @@ def if_then_else(root, a, b): if len(root) == 1: root = root.lm() else: - raise TypeError("Only variables are acceptable as root.") + raise TypeError("only variables are acceptable as root") if isinstance(root, BooleanMonomial): if len(root) == 1: root = root.index() else: - raise TypeError("Only variables are acceptable as root.") + raise TypeError("only variables are acceptable as root") if not isinstance(root, int): - raise TypeError("Only variables are acceptable as root.") + raise TypeError("only variables are acceptable as root") cdef Py_ssize_t* pbind = ring.pbind root = ring.pbind[root] if (root >= a_set.navigation().value()) or (root >= b_set.navigation().value()): raise IndexError("index of root must be less than " - "the values of roots of the branches.") + "the values of roots of the branches") res = PBBooleSet(root, a_set.navigation(), b_set.navigation(), ring._pbring) @@ -7590,7 +7580,7 @@ def top_index(s): elif isinstance(s, BooleanPolynomial): idx = (s)._pbpoly.navigation().value() else: - raise TypeError("Argument 's' has incorrect type (expected BooleSet, BooleanMonomial or BooleanPolynomial, got %s)" % type(s)) + raise TypeError("argument 's' has incorrect type (expected BooleSet, BooleanMonomial or BooleanPolynomial, got %s)" % type(s)) return (s.ring()).pbind[idx] @@ -8010,19 +8000,16 @@ cdef class VariableFactory: a sage: VariableFactory(B)(0) a - """ if ring is None and self._ring is not None: return new_BM_from_PBVar(self._ring._monom_monoid, self._ring, self._factory(arg)) - elif isinstance(arg, BooleanPolynomialRing): + if isinstance(arg, BooleanPolynomialRing): return arg.variable(0) - elif isinstance(ring, BooleanPolynomialRing): + if isinstance(ring, BooleanPolynomialRing): return (ring).variable(arg) - else: - raise TypeError( - "Cannot convert (%s, %s) to Boolean Variable" % - (type(arg), type(ring))) + raise TypeError("cannot convert (%s, %s) to Boolean Variable" % + (type(arg), type(ring))) cdef class MonomialFactory: @@ -8097,7 +8084,7 @@ cdef class MonomialFactory: return result except Exception: raise TypeError( - "Cannot %s convert to Boolean Monomial" % type(arg)) + "cannot %s convert to Boolean Monomial" % type(arg)) cdef class PolynomialFactory: @@ -8174,5 +8161,5 @@ cdef class PolynomialFactory: return new_BP_from_PBPoly(self._ring, self._factory((arg)._pbmonom)) - raise TypeError("Cannot convert %s to BooleanPolynomial" % + raise TypeError("cannot convert %s to BooleanPolynomial" % type(arg)) diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 7f781c65060..69cb4e8bded 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -1,45 +1,50 @@ # coding: utf-8 """ -Univariate Polynomial Base Class +Univariate polynomial base class + +TESTS:: + + sage: R. = ZZ[] + sage: f = x^5 + 2*x^2 + (-1) + sage: f == loads(dumps(f)) + True + + sage: PolynomialRing(ZZ,'x').objgen() + (Univariate Polynomial Ring in x over Integer Ring, x) AUTHORS: -- William Stein: first version. +- William Stein: first version -- Martin Albrecht: Added singular coercion. +- Martin Albrecht: added singular coercion -- Robert Bradshaw: Move Polynomial_generic_dense to Cython. +- Robert Bradshaw: moved Polynomial_generic_dense to Cython -- Miguel Marco: Implemented resultant in the case where PARI fails. +- Miguel Marco: implemented resultant in the case where PARI fails -- Simon King: Use a faster way of conversion from the base ring. +- Simon King: used a faster way of conversion from the base ring -- Julian Rueth (2012-05-25,2014-05-09): Fixed is_squarefree() for imperfect - fields, fixed division without remainder over QQbar; added ``_cache_key`` - for polynomials with unhashable coefficients +- Kwankyu Lee (2013-06-02): enhanced :meth:`quo_rem` -- Simon King (2013-10): Implement copying of :class:`PolynomialBaseringInjection`. +- Julian Rueth (2012-05-25,2014-05-09): fixed is_squarefree() for imperfect + fields, fixed division without remainder over QQbar; added ``_cache_key`` + for polynomials with unhashable coefficients -- Kiran Kedlaya (2016-03): Added root counting. +- Simon King (2013-10): implemented copying of :class:`PolynomialBaseringInjection` -- Edgar Costa (2017-07): Added rational reconstruction. +- Bruno Grenet (2014-07-13): enhanced :meth:`quo_rem` -- Kiran Kedlaya (2017-09): Added reciprocal transform, trace polynomial. +- Kiran Kedlaya (2016-03): added root counting -- David Zureick-Brown (2017-09): Added is_weil_polynomial. +- Edgar Costa (2017-07): added rational reconstruction -- Sebastian Oehms (2018-10): made :meth:`roots` and :meth:`factor` work over more - cases of proper integral domains (see :trac:`26421`) +- Kiran Kedlaya (2017-09): added reciprocal transform, trace polynomial -TESTS:: +- David Zureick-Brown (2017-09): added is_weil_polynomial - sage: R. = ZZ[] - sage: f = x^5 + 2*x^2 + (-1) - sage: f == loads(dumps(f)) - True +- Sebastian Oehms (2018-10): made :meth:`roots` and :meth:`factor` work over more + cases of proper integral domains (see :trac:`26421`) - sage: PolynomialRing(ZZ,'x').objgen() - (Univariate Polynomial Ring in x over Integer Ring, x) """ # **************************************************************************** @@ -11336,7 +11341,7 @@ cdef class Polynomial_generic_dense(Polynomial): sage: class BrokenRational(Rational): ....: def __bool__(self): ....: raise NotImplementedError("cannot check whether number is non-zero") - ....: + ....: sage: z = BrokenRational() sage: R. = QQ[] sage: from sage.rings.polynomial.polynomial_element import Polynomial_generic_dense @@ -11636,18 +11641,12 @@ cdef class Polynomial_generic_dense(Polynomial): Raises a ``ZerodivisionError`` if ``other`` is zero. Raises an ``ArithmeticError`` if the division is not exact. - AUTHORS: - - - Kwankyu Lee (2013-06-02) - - - Bruno Grenet (2014-07-13) - EXAMPLES:: sage: P. = QQ[] sage: R. = P[] - sage: f = R.random_element(10) - sage: g = y^5+R.random_element(4) + sage: f = y^10 + R.random_element(9) + sage: g = y^5 + R.random_element(4) sage: q,r = f.quo_rem(g) sage: f == q*g + r True diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py index 803e78f6e13..e397fffc6d8 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring_element.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring_element.py @@ -737,4 +737,3 @@ def rational_reconstruction(self, *args, **kwargs): R = m.parent() f = R(self._polynomial) return f.rational_reconstruction(m, *args, **kwargs) - diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd b/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd index ab22926414f..438773a39ef 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd @@ -2,6 +2,7 @@ from sage.rings.polynomial.skew_polynomial_element cimport SkewPolynomial_generi cdef class SkewPolynomial_finite_order_dense (SkewPolynomial_generic_dense): cdef _norm + cdef _charpoly cdef _optbound cdef _matphir_c(self) diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx index e61f20e17f3..951fcd22c97 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx @@ -71,6 +71,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): """ SkewPolynomial_generic_dense.__init__ (self, parent, x, check, construct, **kwds) self._norm = None + self._charpoly = None self._optbound = None @@ -87,7 +88,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): cdef k = parent.base_ring() cdef RingElement zero = k(0) cdef RingElement one = k(1) - cdef list line, phir = [ ] + cdef list line, phir = [] if r < d: for i from 0 <= i < d-r: line = d * [zero] @@ -130,10 +131,6 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): Return the matrix of the multiplication by ``self`` on `K[X,\sigma]` considered as a free module over `K[X^r]` (here `r` is the order of `\sigma`). - - .. WARNING:: - - Does not work if self is not monic. """ from sage.matrix.constructor import matrix cdef Py_ssize_t i, j, deb, k, r = self.parent()._order @@ -142,15 +139,15 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): cdef RingElement minusone = base_ring(-1) cdef RingElement zero = base_ring(0) cdef Polk = PolynomialRing (base_ring, 'xr') - cdef list M = [ ] + cdef list M = [] cdef list l = self.list() - for j from 0 <= j < r: - for i from 0 <= i < r: + for j in range(r): + for i in range(r): if i < j: - pol = [ zero ] + pol = [zero] deb = i-j+r else: - pol = [ ] + pol = [] deb = i-j for k from deb <= k <= d by r: pol.append(l[k]) @@ -213,10 +210,14 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): sage: b = S.random_element(degree=7) sage: a.reduced_trace() + b.reduced_trace() == (a+b).reduced_trace() True + + .. SEEALSO:: + + :meth:`reduced_norm`, :meth:`reduced_charpoly` """ order = self.parent()._order twisting_morphism = self.parent().twisting_morphism() - coeffs = [ ] + coeffs = [] for i in range(0, self.degree()+1, order): tr = c = self._coeffs[i] for _ in range(order-1): @@ -265,7 +266,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): By default, the name of the central variable is usually ``z`` (see :meth:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_order.center` for more details about this). - However, the user can speciify a different variable name if desired:: + However, the user can specify a different variable name if desired:: sage: a.reduced_norm(var='u') u^3 + 4*u^2 + 4 @@ -312,6 +313,10 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): polynomial of the left multiplication by `X` on the quotient `K[X,\sigma] / K[X,\sigma] P` (which is a `K`-vector space of dimension `d`). + + .. SEEALSO:: + + :meth:`reduced_trace`, :meth:`reduced_charpoly` """ if self._norm is None: if self.is_zero(): @@ -335,6 +340,84 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): center = self.parent().center(name=var) return center(self._norm) + def reduced_charpoly(self, var=None): + r""" + Return the reduced characteristic polynomial of this + skew polynomial. + + INPUT: + + - ``var`` -- a string, a pair of strings or ``None`` + (default: ``None``); the variable names used for the + characteristic polynomial and the center + + .. NOTE:: + + The result is cached. + + EXAMPLES:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['u', Frob] + sage: a = u^3 + (2*t^2 + 3)*u^2 + (4*t^2 + t + 4)*u + 2*t^2 + 2 + sage: chi = a.reduced_charpoly() + sage: chi + x^3 + (2*z + 1)*x^2 + (3*z^2 + 4*z)*x + 4*z^3 + z^2 + 1 + + The reduced characteristic polynomial has coefficients in the center + of `S`, which is itself a univariate polynomial ring in the variable + `z = u^3` over `\GF{5}`. Hence it appears as a bivariate polynomial:: + + sage: chi.parent() + Univariate Polynomial Ring in x over Univariate Polynomial Ring in z over Finite Field of size 5 + + The constant coefficient of the reduced characteristic polynomial is + the reduced norm, up to a sign:: + + sage: chi[0] == -a.reduced_norm() + True + + Its coefficient of degree `\deg(a) - 1` is the opposite of the reduced + trace:: + + sage: chi[2] == -a.reduced_trace() + True + + By default, the name of the variable of the reduced characteristic + polynomial is ``x`` and the name of central variable is usually ``z`` + (see :meth:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_order.center` + for more details about this). + The user can speciify different names if desired:: + + sage: a.reduced_charpoly(var='T') # variable name for the caracteristic polynomial + T^3 + (2*z + 1)*T^2 + (3*z^2 + 4*z)*T + 4*z^3 + z^2 + 1 + + sage: a.reduced_charpoly(var=('T', 'c')) + T^3 + (2*c + 1)*T^2 + (3*c^2 + 4*c)*T + 4*c^3 + c^2 + 1 + + .. SEEALSO:: + + :meth:`reduced_trace`, :meth:`reduced_norm` + """ + if self._charpoly is None: + parent = self._parent + section = parent._embed_constants.section() + M = self._matmul_c() + chi = M.charpoly() + self._charpoly = [tuple(c.list()) for c in chi.list()] + if self._norm is not None: + self._norm = self._charpoly[-1] + varcenter = None + if var is None: + varcharpoly = 'x' + elif isinstance(var, (tuple, list)) and len(var) == 2: + (varcharpoly, varcenter) = var + else: + varcharpoly = var + center = self.parent().center(name=varcenter) + coeffs = [center(c) for c in self._charpoly] + return PolynomialRing(center, name=varcharpoly)(coeffs) def is_central(self): r""" @@ -486,7 +569,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): except ValueError: bound = self._matphir_c().minimal_polynomial() section = self._parent._embed_constants.section() - self._optbound = [ section(x) for x in bound.list() ] + self._optbound = [section(x) for x in bound.list()] return center(self._optbound) diff --git a/src/sage/rings/semirings/tropical_semiring.pyx b/src/sage/rings/semirings/tropical_semiring.pyx index 5ae1ea93bf7..17e25091f39 100644 --- a/src/sage/rings/semirings/tropical_semiring.pyx +++ b/src/sage/rings/semirings/tropical_semiring.pyx @@ -99,7 +99,7 @@ cdef class TropicalSemiringElement(Element): return repr(self._val) def _latex_(self): - """ + r""" Return a latex representation of ``self``. EXAMPLES:: @@ -135,7 +135,7 @@ cdef class TropicalSemiringElement(Element): # Comparisons cpdef _richcmp_(left, right, int op): - """ + r""" Return the standard comparison of ``left`` and ``right``. EXAMPLES:: @@ -259,7 +259,7 @@ cdef class TropicalSemiringElement(Element): return x def __neg__(self): - """ + r""" Return the additive inverse, which only exists for `\infty`. EXAMPLES:: @@ -610,7 +610,7 @@ class TropicalSemiring(Parent, UniqueRepresentation): @cached_method def zero(self): - """ + r""" Return the (tropical) additive identity element `+\infty`. EXAMPLES:: diff --git a/src/sage/rings/tate_algebra.py b/src/sage/rings/tate_algebra.py index 9097b2a4e07..701278b2eb1 100644 --- a/src/sage/rings/tate_algebra.py +++ b/src/sage/rings/tate_algebra.py @@ -1295,4 +1295,3 @@ def is_integral_domain(self, proof=True): True """ return True - diff --git a/src/sage/sat/solvers/cryptominisat.py b/src/sage/sat/solvers/cryptominisat.py index 6a090604438..eb12e9fbbb3 100644 --- a/src/sage/sat/solvers/cryptominisat.py +++ b/src/sage/sat/solvers/cryptominisat.py @@ -276,11 +276,9 @@ def clauses(self, filename=None): 1 2 -4 0 x1 2 3 0 x1 2 -5 0 - + """ if filename is None: return self._clauses - else: - from sage.sat.solvers.dimacs import DIMACS - DIMACS.render_dimacs(self._clauses, filename, self.nvars()) - + from sage.sat.solvers.dimacs import DIMACS + DIMACS.render_dimacs(self._clauses, filename, self.nvars()) diff --git a/src/sage/sat/solvers/dimacs.py b/src/sage/sat/solvers/dimacs.py index ca40b2d6fe7..cff59ac8205 100644 --- a/src/sage/sat/solvers/dimacs.py +++ b/src/sage/sat/solvers/dimacs.py @@ -622,6 +622,5 @@ def __call__(self, **kwds): if line.startswith("v"): full_line += line[2:] + ' ' s = map(int, full_line[:-3].strip().split(" ")) - s = (None,) + tuple(e>0 for e in s) + s = (None,) + tuple(e > 0 for e in s) return s - diff --git a/src/sage/sat/solvers/picosat.py b/src/sage/sat/solvers/picosat.py index f27c70a92bf..daeef620669 100644 --- a/src/sage/sat/solvers/picosat.py +++ b/src/sage/sat/solvers/picosat.py @@ -220,7 +220,5 @@ def clauses(self, filename=None): """ if filename is None: return self._clauses - else: - from sage.sat.solvers.dimacs import DIMACS - DIMACS.render_dimacs(self._clauses, filename, self.nvars()) - + from sage.sat.solvers.dimacs import DIMACS + DIMACS.render_dimacs(self._clauses, filename, self.nvars()) diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index 68b8375daee..6b64df4d075 100644 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1098,7 +1098,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al kernel point of odd order `\geq 5`. This algorithm is selected using ``algorithm="velusqrt"``. - - Factored Isogenies (*experimental* --- see + - Factored Isogenies (see :mod:`~sage.schemes.elliptic_curves.hom_composite`): Given a list of points which generate a composite-order subgroup, decomposes the isogeny into prime-degree steps. @@ -1200,9 +1200,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al sage: E = EllipticCurve(GF(2^32-5), [170246996, 2036646110]) sage: P = E.lift_x(2) - sage: E.isogeny(P, algorithm="factored") # experimental - doctest:warning - ... + sage: E.isogeny(P, algorithm="factored") Composite morphism of degree 1073721825 = 3^4*5^2*11*19*43*59: From: Elliptic Curve defined by y^2 = x^3 + 170246996*x + 2036646110 over Finite Field of size 4294967291 To: Elliptic Curve defined by y^2 = x^3 + 272790262*x + 1903695400 over Finite Field of size 4294967291 diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 8d707e8e6b7..0ff9011fdd4 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -221,7 +221,6 @@ def degree(self): is the product of the degrees of the individual factors:: sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - doctest:warning ... sage: E = EllipticCurve(GF(419), [1,0]) sage: P, = E.gens() sage: phi = EllipticCurveHom_composite(E, P+P) @@ -713,7 +712,7 @@ def compare_via_evaluation(left, right): q = F.cardinality() d = left.degree() e = integer_floor(1 + 2 * (2*d.sqrt() + 1).log(q)) # from Hasse bound - e = next(i for i,n in enumerate(E.count_points(e+1), 1) if n > 4*d) + e = next(i for i, n in enumerate(E.count_points(e+1), 1) if n > 4*d) EE = E.base_extend(F.extension(e)) Ps = EE.gens() return all(left._eval(P) == right._eval(P) for P in Ps) @@ -728,4 +727,3 @@ def compare_via_evaluation(left, right): else: raise NotImplementedError('not implemented for this base field') - diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py index 32b1fa9e0bb..6528d7bef5d 100644 --- a/src/sage/schemes/elliptic_curves/hom_composite.py +++ b/src/sage/schemes/elliptic_curves/hom_composite.py @@ -7,12 +7,6 @@ while exposing (close to) the same interface as "normal", unfactored elliptic-curve isogenies. -.. WARNING:: - - This module is currently considered experimental. - It may change in a future release without prior warning, or even - be removed altogether if things turn out to be unfixably broken. - EXAMPLES: The following example would take quite literally forever with the @@ -20,8 +14,6 @@ decomposing into prime steps is exponentially faster:: sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - doctest:warning - ... sage: p = 3 * 2^143 - 1 sage: GF(p^2).inject_variables() Defining z2 @@ -90,9 +82,6 @@ from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism -from sage.misc.superseded import experimental_warning -experimental_warning(32744, 'EllipticCurveHom_composite is experimental code.') - #TODO: implement sparse strategies? (cf. the SIKE cryptosystem) def _eval_factored_isogeny(phis, P): @@ -789,7 +778,7 @@ def make_default(): This method exists only temporarily to make testing more convenient while :class:`EllipticCurveHom_composite` is - experimental. + not yet the default. EXAMPLES:: diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 20688dbb4d0..043edcd7399 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -1247,4 +1247,3 @@ def _random_example_for_testing(): K = G(v).element() assert K.order() == deg return E, K - diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index 33549debee1..a9ad45f6fb2 100644 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -907,4 +907,3 @@ def scaling_factor(self): the tuple `(u,r,s,t)` defining the isomorphism. """ return self.u - diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index f85a7295dbc..87e02bc962b 100644 --- a/src/sage/schemes/riemann_surfaces/riemann_surface.py +++ b/src/sage/schemes/riemann_surfaces/riemann_surface.py @@ -478,7 +478,7 @@ def reparameterize_differential_minpoly(minpoly, z0): return mt -class RiemannSurface(object): +class RiemannSurface(): r""" Construct a Riemann Surface. This is specified by the zeroes of a bivariate polynomial with rational coefficients `f(z,w) = 0`. diff --git a/src/sage/sets/disjoint_union_enumerated_sets.py b/src/sage/sets/disjoint_union_enumerated_sets.py index 1820a79256f..7b95a9dc945 100644 --- a/src/sage/sets/disjoint_union_enumerated_sets.py +++ b/src/sage/sets/disjoint_union_enumerated_sets.py @@ -602,6 +602,4 @@ def Element(self): """ if not self._facade: return ElementWrapper - else: - return NotImplemented - + return NotImplemented diff --git a/src/sage/sets/family.py b/src/sage/sets/family.py index c1bf734381c..10c59a02490 100644 --- a/src/sage/sets/family.py +++ b/src/sage/sets/family.py @@ -1380,6 +1380,23 @@ def __setstate__(self, state): """ self.__init__(state['_enumeration']) + def map(self, f, name=None): + r""" + Return the family `( f(\mathtt{self}[i]) )_{i \in I}`, + where `I` is the index set of ``self``. + + The result is again a :class:`TrivialFamily`. + + EXAMPLES:: + + sage: from sage.sets.family import TrivialFamily + sage: f = TrivialFamily(['a', 'b', 'd']) + sage: g = f.map(lambda x: x + '1'); g + Family ('a1', 'b1', 'd1') + """ + # tuple([... for ...]) is faster than tuple(... for ...) + return Family(tuple([f(x) for x in self._enumeration]), name=name) + from sage.sets.non_negative_integers import NonNegativeIntegers from sage.rings.infinity import Infinity diff --git a/src/sage/sets/finite_set_maps.py b/src/sage/sets/finite_set_maps.py index fd4a3ed08ba..ce5029d8032 100644 --- a/src/sage/sets/finite_set_maps.py +++ b/src/sage/sets/finite_set_maps.py @@ -585,4 +585,3 @@ def __init__(self, domain, action, category=None): self._action = action Element = FiniteSetEndoMap_Set - diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index da04658324f..4cf80c3522d 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -818,7 +818,7 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): index_set = tuple(names) from sage.sets.finite_enumerated_set import FiniteEnumeratedSet - if isinstance(index_set, dict): # dict of {name: index} -- not likely to be used + if isinstance(index_set, dict): # dict of {name: index} -- not likely to be used if names is not None: raise ValueError("cannot give index_set as a dict and names") names = normalize_names(-1, tuple(index_set.keys())) @@ -841,4 +841,3 @@ def standardize_names_index_set(names=None, index_set=None, ngens=None): " the number of generators") return (names, index_set) - diff --git a/src/sage/structure/proof/proof.py b/src/sage/structure/proof/proof.py index c667704db92..24532380e8a 100644 --- a/src/sage/structure/proof/proof.py +++ b/src/sage/structure/proof/proof.py @@ -253,4 +253,3 @@ def __exit__(self, *args): True """ _proof_prefs._require_proof[self._subsystem] = self._t_orig - diff --git a/src/sage/symbolic/ginac/ex.h b/src/sage/symbolic/ginac/ex.h index 7d220d2d25d..6a164af270f 100644 --- a/src/sage/symbolic/ginac/ex.h +++ b/src/sage/symbolic/ginac/ex.h @@ -677,19 +677,19 @@ std::ostream & operator<<(std::ostream & os, const exset & e); std::ostream & operator<<(std::ostream & os, const exmap & e); /* Function objects for STL sort() etc. */ -struct ex_is_less : public std::binary_function { +struct ex_is_less { bool operator() (const ex &lh, const ex &rh) const { return lh.compare(rh) < 0; } }; -struct ex_is_equal : public std::binary_function { +struct ex_is_equal { bool operator() (const ex &lh, const ex &rh) const { return lh.is_equal(rh); } }; -struct op0_is_equal : public std::binary_function { +struct op0_is_equal { bool operator() (const ex &lh, const ex &rh) const { return lh.op(0).is_equal(rh.op(0)); } }; -struct ex_swap : public std::binary_function { +struct ex_swap { void operator() (ex &lh, ex &rh) const { lh.swap(rh); } }; diff --git a/src/sage/symbolic/ginac/expair.h b/src/sage/symbolic/ginac/expair.h index 75177f6e49a..38b34e18404 100644 --- a/src/sage/symbolic/ginac/expair.h +++ b/src/sage/symbolic/ginac/expair.h @@ -91,7 +91,7 @@ class expair }; /** Function object for insertion into third argument of STL's sort() etc. */ -struct expair_is_less : public std::binary_function { +struct expair_is_less { bool operator()(const expair &lh, const expair &rh) const { return lh.is_less(rh); } }; @@ -99,11 +99,11 @@ struct expair_is_less : public std::binary_function { * into third argument of STL's sort(). Note that this does not define a * strict weak ordering since for any symbol x we have neither 3*x<2*x or * 2*x<3*x. Handle with care! */ -struct expair_rest_is_less : public std::binary_function { +struct expair_rest_is_less { bool operator()(const expair &lh, const expair &rh) const { return (lh.rest.compare(rh.rest)<0); } }; -struct expair_swap : public std::binary_function { +struct expair_swap { void operator()(expair &lh, expair &rh) const { lh.swap(rh); } }; diff --git a/src/sage/symbolic/ginac/order.h b/src/sage/symbolic/ginac/order.h index 63d5373ae90..7c65d6a7d69 100644 --- a/src/sage/symbolic/ginac/order.h +++ b/src/sage/symbolic/ginac/order.h @@ -35,7 +35,7 @@ namespace GiNaC { -class print_order : public std::binary_function { +class print_order { private: const tinfo_t& function_id() const; const tinfo_t& fderivative_id() const; @@ -96,9 +96,7 @@ class print_order_mul : public print_order { // We have to define the following class to sort held expressions // E.g. 3*x+2*x which does not get simplified to 5*x. -class print_order_pair : - public std::binary_function -{ +class print_order_pair { public: bool operator() (const expair &lh, const expair &rh) const; bool compare_degrees(const expair &lhex, const expair &rhex) const; diff --git a/src/sage/symbolic/ginac/ptr.h b/src/sage/symbolic/ginac/ptr.h index 7f3061cfe43..531e30ca869 100644 --- a/src/sage/symbolic/ginac/ptr.h +++ b/src/sage/symbolic/ginac/ptr.h @@ -158,8 +158,7 @@ namespace std { /** Specialization of std::less for ptr to enable ordering of ptr * objects (e.g. for the use as std::map keys). */ -template struct less< GiNaC::ptr > - : public binary_function, GiNaC::ptr, bool> { +template struct less< GiNaC::ptr > { bool operator()(const GiNaC::ptr &lhs, const GiNaC::ptr &rhs) const { return less()(lhs.p, rhs.p); diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 8c007727799..61a44d022d4 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -721,6 +721,28 @@ def map_isym(isym): result._index_maps = tuple(index_maps) return result + def tensor(self, *args, **kwds): + # Until https://trac.sagemath.org/ticket/30373 is done, + # TensorProductFunctor._functor_name is "tensor", so here we delegate. + r""" + Return the tensor product of ``self`` and ``others``. + + This method is invoked when :class:`~sage.categories.tensor.TensorProductFunctor` + is applied to parents. + + It just delegates to :meth:`tensor_product`. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(QQ, 2); M + 2-dimensional vector space over the Rational Field + sage: M20 = M.tensor_module(2, 0); M20 + Free module of type-(2,0) tensors on the 2-dimensional vector space over the Rational Field + sage: tensor([M20, M20]) + Free module of type-(4,0) tensors on the 2-dimensional vector space over the Rational Field + """ + return self.tensor_product(*args, **kwds) + def rank(self) -> int: r""" Return the rank of the free module ``self``. @@ -2122,7 +2144,7 @@ def _test_basis(self, tester=None, **options): TestSuite(b).run(verbose=tester._verbose, prefix=tester._prefix + " ", raise_on_failure=is_sub_testsuite) - def tensor(self, tensor_type, name=None, latex_name=None, sym=None, + def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, antisym=None): r""" Construct a tensor on the free module ``self``. @@ -2131,10 +2153,81 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, - ``tensor_type`` -- pair ``(k, l)`` with ``k`` being the contravariant rank and ``l`` the covariant rank + + - ``name`` -- (default: ``None``) string; name given to the tensor + + - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to + denote the tensor; if none is provided, the LaTeX symbol is set + to ``name`` + + - ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries + among the tensor arguments: each symmetry is described by a tuple + containing the positions of the involved arguments, with the + convention ``position = 0`` for the first argument. For instance: + + * ``sym = (0,1)`` for a symmetry between the 1st and 2nd arguments + * ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd + arguments and a symmetry between the 2nd, 4th and 5th arguments. + + - ``antisym`` -- (default: ``None``) antisymmetry or iterable of + antisymmetries among the arguments, with the same convention + as for ``sym`` + + OUTPUT: + + - instance of + :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor` + representing the tensor defined on ``self`` with the provided + characteristics + + EXAMPLES: + + Tensors on a rank-3 free module:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: t = M._tensor((1,0), name='t') ; t + Element t of the Rank-3 free module M over the Integer Ring + """ + from .comp import CompWithSym + sym, antisym = CompWithSym._canonicalize_sym_antisym( + tensor_type[0] + tensor_type[1], sym, antisym) + # Special cases: + if tensor_type == (1,0): + return self.element_class(self, name=name, latex_name=latex_name) + elif tensor_type == (0,1): + return self.linear_form(name=name, latex_name=latex_name) + elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: + if len(antisym[0]) == tensor_type[1]: + return self.alternating_form(tensor_type[1], name=name, + latex_name=latex_name) + elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: + if len(antisym[0]) == tensor_type[0]: + return self.alternating_contravariant_tensor(tensor_type[0], + name=name, latex_name=latex_name) + # Generic case: + return self.tensor_module(*tensor_type).element_class(self, + tensor_type, name=name, latex_name=latex_name, + sym=sym, antisym=antisym) + + def tensor(self, *args, **kwds): + r""" + Construct a tensor on the free module ``self`` or a tensor product with other modules. + + If ``args`` consist of other parents, just delegate to :meth:`tensor_product`. + + Otherwise, construct a tensor from the following input. + + INPUT: + + - ``tensor_type`` -- pair ``(k, l)`` with ``k`` being the + contravariant rank and ``l`` the covariant rank + - ``name`` -- (default: ``None``) string; name given to the tensor + - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote the tensor; if none is provided, the LaTeX symbol is set to ``name`` + - ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries among the tensor arguments: each symmetry is described by a tuple containing the positions of the involved arguments, with the @@ -2189,26 +2282,12 @@ def tensor(self, tensor_type, name=None, latex_name=None, sym=None, sage: M.tensor((3,0), antisym=[[]]) Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring """ - from .comp import CompWithSym - sym, antisym = CompWithSym._canonicalize_sym_antisym( - tensor_type[0] + tensor_type[1], sym, antisym) - # Special cases: - if tensor_type == (1,0): - return self.element_class(self, name=name, latex_name=latex_name) - elif tensor_type == (0,1): - return self.linear_form(name=name, latex_name=latex_name) - elif tensor_type[0] == 0 and tensor_type[1] > 1 and antisym: - if len(antisym[0]) == tensor_type[1]: - return self.alternating_form(tensor_type[1], name=name, - latex_name=latex_name) - elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym: - if len(antisym[0]) == tensor_type[0]: - return self.alternating_contravariant_tensor(tensor_type[0], - name=name, latex_name=latex_name) - # Generic case: - return self.tensor_module(*tensor_type).element_class(self, - tensor_type, name=name, latex_name=latex_name, - sym=sym, antisym=antisym) + # Until https://trac.sagemath.org/ticket/30373 is done, + # TensorProductFunctor._functor_name is "tensor", so this method + # also needs to double as the tensor product construction + if isinstance(args[0], Parent): + return self.tensor_product(*args, **kwds) + return self._tensor(*args, **kwds) def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None): r""" diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 39174258ebb..b04e8581148 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -58,6 +58,7 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.categories.modules import Modules from sage.misc.cachefunc import cached_method from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule_abstract from sage.tensor.modules.free_module_tensor import FreeModuleTensor @@ -126,7 +127,7 @@ class TensorFreeModule(FiniteRankFreeModule_abstract): ``T`` is a module (actually a free module) over `\ZZ`:: sage: T.category() - Category of finite dimensional modules over Integer Ring + Category of tensor products of finite dimensional modules over Integer Ring sage: T in Modules(ZZ) True sage: T.rank() @@ -336,7 +337,7 @@ class TensorFreeModule(FiniteRankFreeModule_abstract): Element = FreeModuleTensor - def __init__(self, fmodule, tensor_type, name=None, latex_name=None): + def __init__(self, fmodule, tensor_type, name=None, latex_name=None, category=None): r""" TESTS:: @@ -347,33 +348,47 @@ def __init__(self, fmodule, tensor_type, name=None, latex_name=None): """ self._fmodule = fmodule self._tensor_type = tuple(tensor_type) + ring = fmodule._ring rank = pow(fmodule._rank, tensor_type[0] + tensor_type[1]) if self._tensor_type == (0,1): # case of the dual + category = Modules(ring).FiniteDimensional().or_subcategory(category) if name is None and fmodule._name is not None: name = fmodule._name + '*' if latex_name is None and fmodule._latex_name is not None: latex_name = fmodule._latex_name + r'^*' else: + category = Modules(ring).FiniteDimensional().TensorProducts().or_subcategory(category) if name is None and fmodule._name is not None: name = 'T^' + str(self._tensor_type) + '(' + fmodule._name + \ ')' if latex_name is None and fmodule._latex_name is not None: latex_name = r'T^{' + str(self._tensor_type) + r'}\left(' + \ fmodule._latex_name + r'\right)' - super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name) + super().__init__(fmodule._ring, rank, name=name, latex_name=latex_name, category=category) fmodule._all_modules.add(self) - def construction(self): + def tensor_factors(self): r""" - TESTS:: + Return the tensor factors of this tensor module. + + EXAMPLES:: sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: T = M.tensor_module(2, 3) - sage: T.construction() is None - True + sage: T.tensor_factors() + [Rank-3 free module M over the Integer Ring, + Rank-3 free module M over the Integer Ring, + Dual of the Rank-3 free module M over the Integer Ring, + Dual of the Rank-3 free module M over the Integer Ring, + Dual of the Rank-3 free module M over the Integer Ring] """ - # No construction until https://trac.sagemath.org/ticket/31276 provides tensor_product methods - return None + if self._tensor_type == (0,1): # case of the dual + raise NotImplementedError + factors = [self._fmodule] * self._tensor_type[0] + dmodule = self._fmodule.dual() + if self._tensor_type[1]: + factors += [dmodule] * self._tensor_type[1] + return factors #### Parent Methods diff --git a/src/sage/tensor/modules/tensor_free_submodule.py b/src/sage/tensor/modules/tensor_free_submodule.py index 5f6964f8546..ff4f739ac0d 100644 --- a/src/sage/tensor/modules/tensor_free_submodule.py +++ b/src/sage/tensor/modules/tensor_free_submodule.py @@ -178,6 +178,24 @@ def power_name(op, s, latex=False): latex_name=latex_name, category=category, ambient=ambient) + def construction(self): + # TODO: Define the symmetry group and its action (https://trac.sagemath.org/ticket/34495), + # return the construction functor for invariant subobjects. + r""" + Return the functorial construction of ``self``. + + This implementation just returns ``None``. + + EXAMPLES:: + + sage: M = FiniteRankFreeModule(ZZ, 3, name='M') + sage: Sym2M = M.tensor_module(2, 0, sym=range(2)); Sym2M + Free module of fully symmetric type-(2,0) tensors on the Rank-3 free module M over the Integer Ring + sage: Sym2M.construction() is None + True + """ + return None + @cached_method def _basis_sym(self): r""" diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py index 2e188829ed8..976b912de2a 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/calculus_doctest.py @@ -552,4 +552,3 @@ ) """ - 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 e964bcd4b70..864549d1958 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 @@ -1052,4 +1052,3 @@ 645490122795799841856164638490742749440 """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py index e08cf0fb5bb..94c50977d79 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/domaines_doctest.py @@ -442,4 +442,3 @@ (4) * (x + 2)^2 * (x^2 + 3) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py index abc31568dd3..aa3eed32f3b 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/float_doctest.py @@ -476,4 +476,3 @@ 1.73205080756887729352744634151? """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py index 472b7167ac9..0caad449666 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/graphique_doctest.py @@ -260,4 +260,3 @@ Graphics3d Object """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py index 35d367d8de7..c1d8fa977e5 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/graphtheory_doctest.py @@ -417,4 +417,3 @@ sage: g.show(edge_colors=edge_coloring(g, hex_colors=True)) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py index 518e958cad4..fcb293eb698 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/integration_doctest.py @@ -289,4 +289,3 @@ mpf('2.7135204235459511323824699502438') """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py index 902b3c1aec2..5b99bdfa6ac 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/linalg_doctest.py @@ -458,4 +458,3 @@ True """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py index d4910d7b691..f3aa2201ac8 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/lp_doctest.py @@ -233,4 +233,3 @@ ....: if p.get_values(B(u,v), convert=ZZ, tolerance=1e-3) == 1] ) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py index f36b207d7e3..bef4a2b6c62 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/mpoly_doctest.py @@ -559,4 +559,3 @@ 45 """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py index 909d7d3c746..3a7104637ec 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/nonlinear_doctest.py @@ -489,4 +489,3 @@ 1/2*pi - (e^(1/2*pi) - 10)*e^(-1/2*pi) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py index 8a1bed213bc..46a4d4d2bec 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/numbertheory_doctest.py @@ -154,4 +154,3 @@ 17 """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py index e8b8b0415aa..9b3eade3687 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/polynomes_doctest.py @@ -404,4 +404,3 @@ (x^562949953421312 + 1, 562949953421312*x^562949953421311) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py index 7b8218b4899..fae01daa748 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/premierspas_doctest.py @@ -179,4 +179,3 @@ bla """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py index dd2db19fd8a..3f036d5d362 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/programmation_doctest.py @@ -661,4 +661,3 @@ ....: return len(D) == len (Set(D.values())) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py index f53f813d793..50f936f8cba 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/recequadiff_doctest.py @@ -385,4 +385,3 @@ 2**n*C0 + 2**(n + 1)*n """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py index ca748ba2059..947f9f53a22 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/calculus_doctest.py @@ -263,4 +263,3 @@ True """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py index 4cd1f78259c..5f372f505b0 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/combinat_doctest.py @@ -216,4 +216,3 @@ [0, 1, 1, 2, 5, 14, 42, 132, 429] """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py index 03b4731f545..df3eb03d8fe 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/domaines_doctest.py @@ -58,4 +58,3 @@ """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py index 7e1d7f0c0e4..5d5d4686ec7 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/float_doctest.py @@ -140,4 +140,3 @@ [-1.0000000000000000 .. 1.0000000000000000] """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py index e11b6bad8d9..bb9550918bf 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/integration_doctest.py @@ -55,4 +55,3 @@ [-0.285398163397448, -0.00524656673640445, -0.00125482109302663] """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py index 4e24775c753..7e164a3bffc 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linalg_doctest.py @@ -55,4 +55,3 @@ False """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py index 839ad0d7ec7..e89d7c06fb5 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/linsolve_doctest.py @@ -24,4 +24,3 @@ True """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py index 5219f6f6552..d60adc9dd8b 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/lp_doctest.py @@ -46,4 +46,3 @@ True """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py index f056b349b3e..d4b92c1dfd6 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/mpoly_doctest.py @@ -114,4 +114,3 @@ 1/16*u^2*v^2 - 3/8*u^2*v + 7/16*u^2 + 1/8*v^2 - 1/8*v - 1/8 """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py index afa1a637b7e..f99860f7b9c 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/nonlinear_doctest.py @@ -110,4 +110,3 @@ 1/2*pi - (e^(1/2*pi) - 10)*e^(-1/2*pi) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py index ceae289f561..2dbd0b018e5 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/numbertheory_doctest.py @@ -166,4 +166,3 @@ + 4/5*s3^3*x3^15 - 9/32*s3^2*x3^16 + 1/17*s3*x3^17 """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py index 2908f38254d..f8cefd2f6e8 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/polynomes_doctest.py @@ -106,4 +106,3 @@ + 21844/6081075*x^13 + O(x^15) """ - diff --git a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py index 2dfe2109434..01d0e1bc143 100644 --- a/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py +++ b/src/sage/tests/books/computational-mathematics-with-sagemath/sol/recequadiff_doctest.py @@ -57,4 +57,3 @@ -sqrt(2*_C + 2*log(x))*x """ - diff --git a/src/sage/tests/combinatorial_hopf_algebras.py b/src/sage/tests/combinatorial_hopf_algebras.py index 83a732a170f..6ac40f7aad5 100644 --- a/src/sage/tests/combinatorial_hopf_algebras.py +++ b/src/sage/tests/combinatorial_hopf_algebras.py @@ -48,4 +48,3 @@ sage: all(go2(n) for n in range(6)) # not tested (needs more morphisms) True """ - diff --git a/src/sage/tests/functools_partial_src.py b/src/sage/tests/functools_partial_src.py index 01e4af0f574..1fb24e15b34 100644 --- a/src/sage/tests/functools_partial_src.py +++ b/src/sage/tests/functools_partial_src.py @@ -22,4 +22,3 @@ def base(x): return x test_func = partial(base, 6) - diff --git a/src/sage/tests/gosper-sum.py b/src/sage/tests/gosper-sum.py index 95266ac235c..abdb622b18c 100644 --- a/src/sage/tests/gosper-sum.py +++ b/src/sage/tests/gosper-sum.py @@ -214,4 +214,3 @@ sage: t.simplify_full().is_trivial_zero() False """ - diff --git a/src/sage/typeset/unicode_characters.py b/src/sage/typeset/unicode_characters.py index 4eacf326c43..c4aa7bdd5fb 100644 --- a/src/sage/typeset/unicode_characters.py +++ b/src/sage/typeset/unicode_characters.py @@ -99,5 +99,3 @@ unicode_mathbbR = '\u211D' # 'ℝ' unicode_mathbbC = '\u2102' # 'ℂ' - - diff --git a/src/sage/version.py b/src/sage/version.py index 94cf8afef07..96d65f23372 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.8.beta0' -date = '2022-09-25' -banner = 'SageMath version 9.8.beta0, Release Date: 2022-09-25' +version = '9.8.beta1' +date = '2022-09-29' +banner = 'SageMath version 9.8.beta1, Release Date: 2022-09-29'