diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index d5935789219..f1b387bd230 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -89,7 +89,7 @@ jobs: targets: build doc-html targets_optional: ptest tox_packages_factors: >- - ["minimal] + ["minimal"] docker_push_repository: ghcr.io/${{ github.repository }}/ maximal-pre: diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8eff13405f8..3a90fcee237 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -18,7 +18,7 @@ on: default: >- ["ubuntu-trusty-toolchain-gcc_9", "ubuntu-xenial-toolchain-gcc_9", - "ubuntu-bionic-gcc_8", + "ubuntu-bionic-gcc_8-python3.8", "ubuntu-focal", "ubuntu-jammy", "ubuntu-kinetic", @@ -26,14 +26,14 @@ on: "debian-bullseye", "debian-bookworm", "debian-sid", - "linuxmint-19-gcc_8", - "linuxmint-19.3-gcc_8", + "linuxmint-19-gcc_8-python3.8", + "linuxmint-19.3-gcc_8-python3.8", "linuxmint-20.1", "linuxmint-20.2", "linuxmint-20.3", "linuxmint-21", - "fedora-29", - "fedora-30", + "fedora-29-python3.8", + "fedora-30-python3.8", "fedora-31", "fedora-32", "fedora-33", @@ -42,17 +42,16 @@ on: "fedora-36", "fedora-37", "centos-7-devtoolset-gcc_11", - "centos-stream-8", - "centos-stream-9", + "centos-stream-8-python3.9", + "centos-stream-9-python3.9", "gentoo-python3.9", "gentoo-python3.10", "archlinux-latest", - "opensuse-15.3-gcc_11", - "opensuse-15.4-gcc_11", - "opensuse-tumbleweed", + "opensuse-15.3-gcc_11-python3.9", + "opensuse-15.4-gcc_11-python3.10", + "opensuse-tumbleweed-python3.10", "conda-forge", - "ubuntu-bionic-i386", - "manylinux-2_24-i686", + "ubuntu-bionic-gcc_8-i386", "debian-buster-i386", ] tox_packages_factors: @@ -128,6 +127,7 @@ jobs: FROM_DOCKER_REPOSITORY: ${{ inputs.from_docker_repository }} FROM_DOCKER_TARGET: ${{ inputs.from_docker_target }} FROM_DOCKER_TAG: ${{ inputs.from_docker_tag }} + EXTRA_CONFIGURE_ARGS: --enable-fat-binary steps: - name: Check out SageMath diff --git a/.gitignore b/.gitignore index 4440aee8f9a..d598d2e633f 100644 --- a/.gitignore +++ b/.gitignore @@ -131,9 +131,15 @@ __pycache__/ # Generated Cython files *.so **/*.so +/src/cython_debug +# Most C and C++ files are generated by Cython and should not +# be included in the sdist. /src/sage/**/*.c /src/sage/**/*.cpp +# C header generated by Cython /src/sage/modular/arithgroup/farey_symbol.h +# List of C and C++ files that are actual source files, +# NOT generated by Cython. The same list appears in src/MANIFEST.in !/src/sage/cpython/debugimpl.c !/src/sage/graphs/base/boost_interface.cpp !/src/sage/graphs/cliquer/cl.c @@ -156,7 +162,6 @@ __pycache__/ !/src/sage/stats/distributions/dgs_gauss_dp.c !/src/sage/stats/distributions/dgs_gauss_mp.c !/src/sage/symbolic/ginac/*.cpp -/src/cython_debug # Temporary build files build/temp.*/ diff --git a/.gitpod-setup-trac-remote.sh b/.gitpod-setup-trac-remote.sh new file mode 100755 index 00000000000..4ca3b19f26d --- /dev/null +++ b/.gitpod-setup-trac-remote.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# Exit on error +set -e + +# Setup trac as remote +## In order to push to trac, generate a new key with `ssh-keygen -f tempkey` and save the private key to gitpod `gp env PRIVATE_SSH_KEY="$( /dev/null || true # might still exists from a previous run/prebuild +if [[ -n "${PRIVATE_SSH_KEY}" ]]; then + # Setup ssh key for authentication with trac + mkdir -p ~/.ssh + echo $PRIVATE_SSH_KEY | sed 's/\(-----\(BEGIN\|END\) OPENSSH PRIVATE KEY-----\)/\n\1\n/g' > ~/.ssh/id_rsa + sed -i '/^$/d' ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + echo "PubkeyAcceptedKeyTypes +ssh-rsa" > ~/.ssh/config + ssh-keyscan -H trac.sagemath.org >> ~/.ssh/known_hosts + + # Setup trac repo + git remote add trac git@trac.sagemath.org:sage.git -t master -t develop -t $(git branch --show-current) + git remote set-url --push trac git@trac.sagemath.org:sage.git + git fetch trac + git branch -u trac/$(git branch --show-current) +else + # Fallback to sagemath mirror + git remote add trac https://github.com/sagemath/sagetrac-mirror.git -t master -t develop + git remote set-url --push trac pushing-needs-ssh-key +fi diff --git a/.gitpod.yml b/.gitpod.yml index fcd6027c88d..52ac8d7184c 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -5,53 +5,24 @@ image: # Start up tasks. https://www.gitpod.io/docs/config-start-tasks/ tasks: - name: Setup - init: | - # Create conda environment + # Create conda environment, then configure and build sage + init: >- ./bootstrap-conda - mamba env create --file src/environment-dev.yml --prefix venv - conda config --append envs_dirs $(pwd) - conda activate $(pwd)/venv - - # Build sage - ./bootstrap - ./configure --enable-build-as-root --with-python=$CONDA_PREFIX/bin/python --prefix=$CONDA_PREFIX - pip install --no-build-isolation -v -v -e ./pkgs/sage-conf ./pkgs/sage-setup - pip install --no-build-isolation -v -v -e ./src - - command: | - # Activate conda environment - conda config --append envs_dirs $(pwd) - conda activate $(pwd)/venv - - # RestructuredText extension recommends python extension, although we have already installed it - ## So disable the recommendation dialog + && mamba env create --file src/environment-dev.yml --prefix venv + && conda config --append envs_dirs $(pwd) + && conda activate $(pwd)/venv + && ./bootstrap + && ./configure --enable-build-as-root --with-python=$CONDA_PREFIX/bin/python --prefix=$CONDA_PREFIX + && pip install --no-build-isolation -v -v -e ./pkgs/sage-conf ./pkgs/sage-setup + && pip install --no-build-isolation -v -v -e ./src + # Activate conda environment, set up Trac remote + # RestructuredText extension recommends python extension, although we have already installed it + # So disable the recommendation dialog + command: >- echo "{\"restructuredtext.pythonRecommendation.disabled\": true}" > /workspace/.vscode-remote/data/Machine/settings.json - - # Setup trac as remote - ## In order to push to trac, generate a new key with `ssh-keygen -f tempkey` and save the private key to gitpod `gp env PRIVATE_SSH_KEY="$( /dev/null # might still exists from a previous run/prebuild - if [[ -n "${PRIVATE_SSH_KEY}" ]]; then - # Setup ssh key for authentication with trac - mkdir -p ~/.ssh - echo $PRIVATE_SSH_KEY | sed 's/\(-----\(BEGIN\|END\) OPENSSH PRIVATE KEY-----\)/\n\1\n/g' > ~/.ssh/id_rsa - sed -i '/^$/d' ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - echo "PubkeyAcceptedKeyTypes +ssh-rsa" > ~/.ssh/config - ssh-keyscan -H trac.sagemath.org >> ~/.ssh/known_hosts - - # Setup trac repo - git remote add trac git@trac.sagemath.org:sage.git -t master -t develop -t $(git branch --show-current) - git remote set-url --push trac git@trac.sagemath.org:sage.git - git fetch trac - git branch -u trac/$(git branch --show-current) - else - # Fallback to sagemath mirror - git remote add trac https://github.com/sagemath/sagetrac-mirror.git -t master -t develop - git remote set-url --push trac pushing-needs-ssh-key - fi - + && conda config --append envs_dirs $(pwd) + && conda activate $(pwd)/venv + && ./.gitpod-setup-trac-remote.sh env: SAGE_NUM_THREADS: 8 diff --git a/.vscode/settings.json b/.vscode/settings.json index 10822524b25..e414fb65d7f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,11 +27,12 @@ "python.linting.enabled": true, // The following pycodestyle arguments are the same as the pycodestyle-minimal // tox environnment, see the file SAGE_ROOT/src/tox.ini - "python.linting.pycodestyleArgs": ["--select=E111,E306,E401,E701,E702,E703,W605,E711,E712,E713,E721,E722"], + "python.linting.pycodestyleArgs": ["--select=E111,E306,E401,E701,E702,E703,W391,W605,E711,E712,E713,E721,E722"], "cSpell.words": [ "furo", "Conda", "sagemath", "Cython" - ] + ], + "editor.formatOnType": true } diff --git a/.zenodo.json b/.zenodo.json index 06bf86e4065..81ea9dde6d0 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.beta3", + "version": "9.8.beta3", "upload_type": "software", - "publication_date": "2022-09-25", + "publication_date": "2022-10-30", "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.beta3", "relation": "isSupplementTo" }, { diff --git a/Makefile b/Makefile index 004a6750920..414398ddf0d 100644 --- a/Makefile +++ b/Makefile @@ -101,7 +101,7 @@ pypi-wheels: rm -f venv/var/lib/sage/installed/$$a-*; \ done for a in $(PYPI_WHEEL_PACKAGES); do \ - $(MAKE) SAGE_EDITABLE=no $$a; \ + $(MAKE) SAGE_EDITABLE=no SAGE_WHEELS=yes $$a; \ done @echo "Built wheels are in venv/var/lib/sage/wheels/" @@ -112,7 +112,7 @@ wheels: rm -f venv/var/lib/sage/installed/$$a-*; \ done for a in $(WHEEL_PACKAGES); do \ - $(MAKE) SAGE_EDITABLE=no $$a; \ + $(MAKE) SAGE_EDITABLE=no SAGE_WHEELS=yes $$a; \ done @echo "Built wheels are in venv/var/lib/sage/wheels/" 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..ff069aea672 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 9.8.beta0, Release Date: 2022-09-25 +SageMath version 9.8.beta3, Release Date: 2022-10-30 diff --git a/build/bin/sage-build-env b/build/bin/sage-build-env index ed999b703f0..87cd0fde5f3 100644 --- a/build/bin/sage-build-env +++ b/build/bin/sage-build-env @@ -31,6 +31,10 @@ if [ "x$SAGE_BUILD_ENV_SOURCED" = "x" ]; then if [ "x$SAGE_EDITABLE" = "x" ]; then export SAGE_EDITABLE="$CONFIGURED_SAGE_EDITABLE" fi + # Likewise for SAGE_WHEELS + if [ "x$SAGE_WHEELS" = "x" ]; then + export SAGE_WHEELS="$CONFIGURED_SAGE_WHEELS" + fi # This is usually blank if the system GMP is used, or $SAGE_LOCAL otherwise if [ -n "$SAGE_GMP_PREFIX" ]; then diff --git a/build/bin/sage-build-env-config.in b/build/bin/sage-build-env-config.in index 58d6bd5e5d7..b00fd2a3f99 100644 --- a/build/bin/sage-build-env-config.in +++ b/build/bin/sage-build-env-config.in @@ -58,3 +58,4 @@ export SAGE_SUITESPARSE_PREFIX="@SAGE_SUITESPARSE_PREFIX@" export SAGE_CONFIGURE_FFLAS_FFPACK="@SAGE_CONFIGURE_FFLAS_FFPACK@" export CONFIGURED_SAGE_EDITABLE="@SAGE_EDITABLE@" +export CONFIGURED_SAGE_WHEELS="@SAGE_WHEELS@" 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/bin/sage-pip-install b/build/bin/sage-pip-install index 08978fe5717..71f436a4b47 100755 --- a/build/bin/sage-pip-install +++ b/build/bin/sage-pip-install @@ -28,7 +28,7 @@ PIP=pip3 # We should avoid running pip while installing a package because that # is prone to race conditions. Therefore, we use a lockfile while # running pip. This is implemented in the Python script sage-flock -LOCK="$SAGE_LOCAL/var/lock/$PIP.lock" +LOCK="$SAGE_VENV/var/lock/$PIP.lock" # Trac #33155: Pythons installed using the python.org macOS installers # for Python < 3.10 identify macOS Big Sur and newer as "10.16", causing diff --git a/build/bin/sage-pip-uninstall b/build/bin/sage-pip-uninstall index 3017627dbbc..616f86a065b 100755 --- a/build/bin/sage-pip-uninstall +++ b/build/bin/sage-pip-uninstall @@ -14,7 +14,7 @@ PIP=pip3 # We should avoid running pip while uninstalling a package because that # is prone to race conditions. Therefore, we use a lockfile while # running pip. This is implemented in the Python script sage-flock -LOCK="$SAGE_LOCAL/var/lock/$PIP.lock" +LOCK="$SAGE_VENV/var/lock/$PIP.lock" # --disable-pip-version-check: Don't periodically check PyPI to determine whether a new version of pip is available # --no-input: Disable prompting for input. diff --git a/build/bin/sage-site b/build/bin/sage-site index 0472f5652b3..f9d13d53047 100755 --- a/build/bin/sage-site +++ b/build/bin/sage-site @@ -98,7 +98,7 @@ fi if [ "$1" = '-package' -o "$1" = "--package" ]; then shift - exec sage-package $@ + exec sage-package "$@" fi if [ "$1" = '-optional' -o "$1" = "--optional" ]; then diff --git a/build/make/Makefile.in b/build/make/Makefile.in index ea54177f241..9148f3d7577 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,8 +676,8 @@ $(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' && \ - rm -f "$$($(4))/$(SPKG_INST_RELDIR)/$(1)-*" && \ + 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 ( \ echo; \ @@ -704,7 +704,7 @@ $(1)-$(4)-uninstall: . '$$(SAGE_ROOT)/build/bin/sage-build-env-config' && \ . '$$(SAGE_ROOT)/build/bin/sage-build-env' && \ '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-uninstall' - -rm -f "$$($(4))/$(SPKG_INST_RELDIR)/$(1)-$(2)" + -rm -f "$$($(4))/$(SPKG_INST_RELDIR)/$(1)"-* $(1)-uninstall: $(1)-$(4)-uninstall diff --git a/build/pkgs/_develop/dependencies b/build/pkgs/_develop/dependencies index f50a34b8495..f37c427ebcd 100644 --- a/build/pkgs/_develop/dependencies +++ b/build/pkgs/_develop/dependencies @@ -1 +1 @@ -_bootstrap git pytest pytest_xdist +_bootstrap git pytest pytest_xdist github_cli 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/_python3.10/distros/arch.txt b/build/pkgs/_python3.10/distros/arch.txt new file mode 100644 index 00000000000..92826c681b4 --- /dev/null +++ b/build/pkgs/_python3.10/distros/arch.txt @@ -0,0 +1 @@ +python310 diff --git a/build/pkgs/_python3.10/distros/cygwin.txt b/build/pkgs/_python3.10/distros/cygwin.txt new file mode 100644 index 00000000000..92826c681b4 --- /dev/null +++ b/build/pkgs/_python3.10/distros/cygwin.txt @@ -0,0 +1 @@ +python310 diff --git a/build/pkgs/_python3.10/distros/debian.txt b/build/pkgs/_python3.10/distros/debian.txt new file mode 100644 index 00000000000..9b7529828a1 --- /dev/null +++ b/build/pkgs/_python3.10/distros/debian.txt @@ -0,0 +1,3 @@ +python3.10 +python3.10-dev +python3.10-venv diff --git a/build/pkgs/_python3.10/distros/fedora.txt b/build/pkgs/_python3.10/distros/fedora.txt new file mode 100644 index 00000000000..90e42c91602 --- /dev/null +++ b/build/pkgs/_python3.10/distros/fedora.txt @@ -0,0 +1,2 @@ +python310 +python310-devel diff --git a/build/pkgs/_python3.10/distros/freebsd.txt b/build/pkgs/_python3.10/distros/freebsd.txt new file mode 100644 index 00000000000..92826c681b4 --- /dev/null +++ b/build/pkgs/_python3.10/distros/freebsd.txt @@ -0,0 +1 @@ +python310 diff --git a/build/pkgs/_python3.10/distros/homebrew.txt b/build/pkgs/_python3.10/distros/homebrew.txt new file mode 100644 index 00000000000..b669c26e698 --- /dev/null +++ b/build/pkgs/_python3.10/distros/homebrew.txt @@ -0,0 +1 @@ +python@3.10 diff --git a/build/pkgs/_python3.10/distros/macports.txt b/build/pkgs/_python3.10/distros/macports.txt new file mode 100644 index 00000000000..92826c681b4 --- /dev/null +++ b/build/pkgs/_python3.10/distros/macports.txt @@ -0,0 +1 @@ +python310 diff --git a/build/pkgs/_python3.10/distros/opensuse.txt b/build/pkgs/_python3.10/distros/opensuse.txt new file mode 100644 index 00000000000..90e42c91602 --- /dev/null +++ b/build/pkgs/_python3.10/distros/opensuse.txt @@ -0,0 +1,2 @@ +python310 +python310-devel diff --git a/build/pkgs/_python3.11/distros/arch.txt b/build/pkgs/_python3.11/distros/arch.txt new file mode 100644 index 00000000000..1d66f45569a --- /dev/null +++ b/build/pkgs/_python3.11/distros/arch.txt @@ -0,0 +1 @@ +python311 diff --git a/build/pkgs/_python3.11/distros/cygwin.txt b/build/pkgs/_python3.11/distros/cygwin.txt new file mode 100644 index 00000000000..1d66f45569a --- /dev/null +++ b/build/pkgs/_python3.11/distros/cygwin.txt @@ -0,0 +1 @@ +python311 diff --git a/build/pkgs/_python3.11/distros/debian.txt b/build/pkgs/_python3.11/distros/debian.txt new file mode 100644 index 00000000000..a3128e4751f --- /dev/null +++ b/build/pkgs/_python3.11/distros/debian.txt @@ -0,0 +1,3 @@ +python3.11 +python3.11-dev +python3.11-venv diff --git a/build/pkgs/_python3.11/distros/fedora.txt b/build/pkgs/_python3.11/distros/fedora.txt new file mode 100644 index 00000000000..a478404f8fb --- /dev/null +++ b/build/pkgs/_python3.11/distros/fedora.txt @@ -0,0 +1,2 @@ +python311 +python311-devel diff --git a/build/pkgs/_python3.11/distros/freebsd.txt b/build/pkgs/_python3.11/distros/freebsd.txt new file mode 100644 index 00000000000..1d66f45569a --- /dev/null +++ b/build/pkgs/_python3.11/distros/freebsd.txt @@ -0,0 +1 @@ +python311 diff --git a/build/pkgs/_python3.11/distros/homebrew.txt b/build/pkgs/_python3.11/distros/homebrew.txt new file mode 100644 index 00000000000..f80da9b2e50 --- /dev/null +++ b/build/pkgs/_python3.11/distros/homebrew.txt @@ -0,0 +1 @@ +python@3.11 diff --git a/build/pkgs/_python3.11/distros/macports.txt b/build/pkgs/_python3.11/distros/macports.txt new file mode 100644 index 00000000000..1d66f45569a --- /dev/null +++ b/build/pkgs/_python3.11/distros/macports.txt @@ -0,0 +1 @@ +python311 diff --git a/build/pkgs/_python3.11/distros/opensuse.txt b/build/pkgs/_python3.11/distros/opensuse.txt new file mode 100644 index 00000000000..a478404f8fb --- /dev/null +++ b/build/pkgs/_python3.11/distros/opensuse.txt @@ -0,0 +1,2 @@ +python311 +python311-devel diff --git a/build/pkgs/_python3.8/distros/arch.txt b/build/pkgs/_python3.8/distros/arch.txt new file mode 100644 index 00000000000..398ae3228b3 --- /dev/null +++ b/build/pkgs/_python3.8/distros/arch.txt @@ -0,0 +1 @@ +python38 diff --git a/build/pkgs/_python3.8/distros/cygwin.txt b/build/pkgs/_python3.8/distros/cygwin.txt new file mode 100644 index 00000000000..398ae3228b3 --- /dev/null +++ b/build/pkgs/_python3.8/distros/cygwin.txt @@ -0,0 +1 @@ +python38 diff --git a/build/pkgs/_python3.8/distros/debian.txt b/build/pkgs/_python3.8/distros/debian.txt new file mode 100644 index 00000000000..11476fe0595 --- /dev/null +++ b/build/pkgs/_python3.8/distros/debian.txt @@ -0,0 +1,3 @@ +python3.8 +python3.8-dev +python3.8-venv diff --git a/build/pkgs/_python3.8/distros/fedora.txt b/build/pkgs/_python3.8/distros/fedora.txt new file mode 100644 index 00000000000..1f9ac08ba8e --- /dev/null +++ b/build/pkgs/_python3.8/distros/fedora.txt @@ -0,0 +1,2 @@ +python38 +python38-devel diff --git a/build/pkgs/_python3.8/distros/freebsd.txt b/build/pkgs/_python3.8/distros/freebsd.txt new file mode 100644 index 00000000000..398ae3228b3 --- /dev/null +++ b/build/pkgs/_python3.8/distros/freebsd.txt @@ -0,0 +1 @@ +python38 diff --git a/build/pkgs/_python3.8/distros/homebrew.txt b/build/pkgs/_python3.8/distros/homebrew.txt new file mode 100644 index 00000000000..ea9989e790c --- /dev/null +++ b/build/pkgs/_python3.8/distros/homebrew.txt @@ -0,0 +1 @@ +python@3.8 diff --git a/build/pkgs/_python3.8/distros/macports.txt b/build/pkgs/_python3.8/distros/macports.txt new file mode 100644 index 00000000000..398ae3228b3 --- /dev/null +++ b/build/pkgs/_python3.8/distros/macports.txt @@ -0,0 +1 @@ +python38 diff --git a/build/pkgs/_python3.8/distros/opensuse.txt b/build/pkgs/_python3.8/distros/opensuse.txt new file mode 100644 index 00000000000..1f9ac08ba8e --- /dev/null +++ b/build/pkgs/_python3.8/distros/opensuse.txt @@ -0,0 +1,2 @@ +python38 +python38-devel diff --git a/build/pkgs/_python3.9/distros/arch.txt b/build/pkgs/_python3.9/distros/arch.txt new file mode 100644 index 00000000000..6a2d05c5edb --- /dev/null +++ b/build/pkgs/_python3.9/distros/arch.txt @@ -0,0 +1 @@ +python39 diff --git a/build/pkgs/_python3.9/distros/cygwin.txt b/build/pkgs/_python3.9/distros/cygwin.txt new file mode 100644 index 00000000000..6a2d05c5edb --- /dev/null +++ b/build/pkgs/_python3.9/distros/cygwin.txt @@ -0,0 +1 @@ +python39 diff --git a/build/pkgs/_python3.9/distros/debian.txt b/build/pkgs/_python3.9/distros/debian.txt new file mode 100644 index 00000000000..e113156b021 --- /dev/null +++ b/build/pkgs/_python3.9/distros/debian.txt @@ -0,0 +1,3 @@ +python3.9 +python3.9-dev +python3.9-venv diff --git a/build/pkgs/_python3.9/distros/fedora.txt b/build/pkgs/_python3.9/distros/fedora.txt new file mode 100644 index 00000000000..046ffc713b3 --- /dev/null +++ b/build/pkgs/_python3.9/distros/fedora.txt @@ -0,0 +1,2 @@ +python39 +python39-devel diff --git a/build/pkgs/_python3.9/distros/freebsd.txt b/build/pkgs/_python3.9/distros/freebsd.txt new file mode 100644 index 00000000000..6a2d05c5edb --- /dev/null +++ b/build/pkgs/_python3.9/distros/freebsd.txt @@ -0,0 +1 @@ +python39 diff --git a/build/pkgs/_python3.9/distros/homebrew.txt b/build/pkgs/_python3.9/distros/homebrew.txt new file mode 100644 index 00000000000..62a4a244e21 --- /dev/null +++ b/build/pkgs/_python3.9/distros/homebrew.txt @@ -0,0 +1 @@ +python@3.9 diff --git a/build/pkgs/_python3.9/distros/macports.txt b/build/pkgs/_python3.9/distros/macports.txt new file mode 100644 index 00000000000..6a2d05c5edb --- /dev/null +++ b/build/pkgs/_python3.9/distros/macports.txt @@ -0,0 +1 @@ +python39 diff --git a/build/pkgs/_python3.9/distros/opensuse.txt b/build/pkgs/_python3.9/distros/opensuse.txt new file mode 100644 index 00000000000..046ffc713b3 --- /dev/null +++ b/build/pkgs/_python3.9/distros/opensuse.txt @@ -0,0 +1,2 @@ +python39 +python39-devel diff --git a/build/pkgs/antic/SPKG.rst b/build/pkgs/antic/SPKG.rst new file mode 100644 index 00000000000..d6c32377957 --- /dev/null +++ b/build/pkgs/antic/SPKG.rst @@ -0,0 +1,18 @@ +antic: Algebraic Number Theory In C +=================================== + +Description +----------- + +Algebraic Number Theory In C + +License +------- + +LGPL 2.1 + +Upstream Contact +---------------- + +https://github.com/wbhart/antic + diff --git a/build/pkgs/antic/checksums.ini b/build/pkgs/antic/checksums.ini new file mode 100644 index 00000000000..fc8711ecd13 --- /dev/null +++ b/build/pkgs/antic/checksums.ini @@ -0,0 +1,5 @@ +tarball=antic-VERSION.tar.gz +sha1=940d8ea2c3512b9d49ee3101cf043f777764bd8f +md5=4e896420dd6344b53b307871efb2cbb4 +cksum=1938565125 +upstream_url=https://github.com/wbhart/antic/archive/refs/tags/vVERSION.tar.gz diff --git a/build/pkgs/antic/dependencies b/build/pkgs/antic/dependencies new file mode 100644 index 00000000000..c95d2836ce5 --- /dev/null +++ b/build/pkgs/antic/dependencies @@ -0,0 +1,4 @@ +$(MP_LIBRARY) mpfr flint + +---------- +All lines of this file are ignored except the first. diff --git a/build/pkgs/antic/distros/arch.txt b/build/pkgs/antic/distros/arch.txt new file mode 100644 index 00000000000..83c7cab14e4 --- /dev/null +++ b/build/pkgs/antic/distros/arch.txt @@ -0,0 +1 @@ +antic diff --git a/build/pkgs/antic/distros/conda.txt b/build/pkgs/antic/distros/conda.txt new file mode 100644 index 00000000000..83c7cab14e4 --- /dev/null +++ b/build/pkgs/antic/distros/conda.txt @@ -0,0 +1 @@ +antic diff --git a/build/pkgs/antic/distros/debian.txt b/build/pkgs/antic/distros/debian.txt new file mode 100644 index 00000000000..8fdcd3e5721 --- /dev/null +++ b/build/pkgs/antic/distros/debian.txt @@ -0,0 +1 @@ +libantic-dev diff --git a/build/pkgs/antic/distros/fedora.txt b/build/pkgs/antic/distros/fedora.txt new file mode 100644 index 00000000000..1b16da9f64b --- /dev/null +++ b/build/pkgs/antic/distros/fedora.txt @@ -0,0 +1 @@ +antic-devel diff --git a/build/pkgs/antic/distros/freebsd.txt b/build/pkgs/antic/distros/freebsd.txt new file mode 100644 index 00000000000..116ff3a26f3 --- /dev/null +++ b/build/pkgs/antic/distros/freebsd.txt @@ -0,0 +1 @@ +math/antic diff --git a/build/pkgs/antic/distros/opensuse.txt b/build/pkgs/antic/distros/opensuse.txt new file mode 100644 index 00000000000..1b16da9f64b --- /dev/null +++ b/build/pkgs/antic/distros/opensuse.txt @@ -0,0 +1 @@ +antic-devel diff --git a/build/pkgs/antic/distros/repology.txt b/build/pkgs/antic/distros/repology.txt new file mode 100644 index 00000000000..83c7cab14e4 --- /dev/null +++ b/build/pkgs/antic/distros/repology.txt @@ -0,0 +1 @@ +antic diff --git a/build/pkgs/antic/package-version.txt b/build/pkgs/antic/package-version.txt new file mode 100644 index 00000000000..3a4036fb450 --- /dev/null +++ b/build/pkgs/antic/package-version.txt @@ -0,0 +1 @@ +0.2.5 diff --git a/build/pkgs/antic/spkg-install.in b/build/pkgs/antic/spkg-install.in new file mode 100644 index 00000000000..c57fa884a20 --- /dev/null +++ b/build/pkgs/antic/spkg-install.in @@ -0,0 +1,19 @@ +cd src + +# Copied from build/pkgs/flint/spkg-install.in: +# Trac #29607: We must always supply --with-gmp, --with-mpfr, +# --with-ntl because otherwise FLINT's configure script uses +# /usr/local, which is always wrong. +# This is why we do not use $SAGE_CONFIGURE_GMP etc. here. +# The value $SAGE_LOCAL is always a safe choice even if the library +# is coming from the system and is found using what is in +# LIBRARY_PATH or LDFLAGS etc. +./configure \ + --disable-static \ + --prefix="$SAGE_LOCAL" \ + --with-gmp="$SAGE_LOCAL" \ + --with-mpfr="$SAGE_LOCAL" \ + --with-flint="$SAGE_LOCAL" || sdh_die "Error: Failed to configure antic." + +sdh_make verbose +sdh_make_install diff --git a/build/pkgs/antic/type b/build/pkgs/antic/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/antic/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/cddlib/distros/homebrew.txt b/build/pkgs/cddlib/distros/homebrew.txt index 11ade1bfb9a..f9afcc0b330 100644 --- a/build/pkgs/cddlib/distros/homebrew.txt +++ b/build/pkgs/cddlib/distros/homebrew.txt @@ -1,3 +1 @@ -# Until https://trac.sagemath.org/ticket/29413 is done, we cannot use homebrew's cddlib, -# which already uses the new upstream include header locations. -#cddlib +cddlib diff --git a/build/pkgs/cddlib/spkg-configure.m4 b/build/pkgs/cddlib/spkg-configure.m4 index ad227f032ed..8508f28512d 100644 --- a/build/pkgs/cddlib/spkg-configure.m4 +++ b/build/pkgs/cddlib/spkg-configure.m4 @@ -40,15 +40,8 @@ EOF AC_MSG_RESULT([yes]) ]) ]) - dnl Recent versions (>= 0.94k) of cddlib put these headers in - dnl a "cddlib" subdirectory, and Debian currently relocates them - dnl under "cdd". But for now they're at the top-level, in e.g. - dnl /usr/include/cdd.h. The lattE and gfan packages within - dnl SageMath both look for them there, so that's where we have to - dnl check, passing up a chance to detect cddlib on Fedora and Debian - dnl for now. Once all of cddlib's consumers know about the new (or - dnl both) locations, we can update this check to support them. - dnl See https://trac.sagemath.org/ticket/29413 + dnl Recent versions (>= 0.94k) of cddlib put cddlib's headers in + dnl a "cddlib" subdirectory. AC_CHECK_HEADER([cddlib/cdd.h],[],[sage_spkg_install_cddlib=yes],[ #include #include diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index d7e7fc0fcc1..c69394ff5dc 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=103db8ec9f403e7d8c2a36fe7a9d03f8ace86667 +md5=67c1a87314dd1cd7eb9c426105f01c81 +cksum=878105096 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index abdbdc62467..d00f65abb0a 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -04fbc829e9850eedf555acc683666c55cb7052d7 +412cc5c0045f1ae9f8f6d98d75754d5d443d58fd diff --git a/build/pkgs/database_knotinfo/checksums.ini b/build/pkgs/database_knotinfo/checksums.ini index 01afb61648f..9b521522202 100644 --- a/build/pkgs/database_knotinfo/checksums.ini +++ b/build/pkgs/database_knotinfo/checksums.ini @@ -1,5 +1,5 @@ tarball=database_knotinfo-VERSION.tar.gz -sha1=187e6b5ee2a935e3a50bc7648b181dfc7cb7bfa2 -md5=90822e09a1a84c8dbb84e20773c367f1 -cksum=1855405219 +sha1=16039d4e399efc78e4b1278527019f4bcdfdde13 +md5=3095993756f6b51d14c35adae5a75930 +cksum=2884062991 upstream_url=https://pypi.io/packages/source/d/database_knotinfo/database_knotinfo-VERSION.tar.gz diff --git a/build/pkgs/database_knotinfo/package-version.txt b/build/pkgs/database_knotinfo/package-version.txt index bb762ff812e..eef52011e7f 100644 --- a/build/pkgs/database_knotinfo/package-version.txt +++ b/build/pkgs/database_knotinfo/package-version.txt @@ -1 +1 @@ -2021.10.1 +2022.7.1 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/e_antic/checksums.ini b/build/pkgs/e_antic/checksums.ini index 15e0fcd9a9d..82757976c54 100644 --- a/build/pkgs/e_antic/checksums.ini +++ b/build/pkgs/e_antic/checksums.ini @@ -1,5 +1,5 @@ tarball=e-antic-VERSION.tar.gz -sha1=f51d90fcffb2c849eebc1013eb14984f9ad59719 -md5=84ab45f0e1eb3ddbbfb175927506b7bc -cksum=3161097188 -upstream_url=https://www.labri.fr/perso/vdelecro/e-antic/e-antic-VERSION.tar.gz +sha1=0fa6ba4a1f13e881f369f9185fe42c7f4bc10a18 +md5=5d77933d78dd08109b0a2c8403892eb6 +cksum=3304746077 +upstream_url=https://github.com/flatsurf/e-antic/releases/download/VERSION/e-antic-VERSION.tar.gz diff --git a/build/pkgs/e_antic/dependencies b/build/pkgs/e_antic/dependencies index ff67f31325b..fea1ffbda45 100644 --- a/build/pkgs/e_antic/dependencies +++ b/build/pkgs/e_antic/dependencies @@ -1,4 +1,4 @@ -$(MP_LIBRARY) flint arb +$(MP_LIBRARY) flint arb antic boost_cropped ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/e_antic/distros/arch.txt b/build/pkgs/e_antic/distros/arch.txt new file mode 100644 index 00000000000..31c9da4b82f --- /dev/null +++ b/build/pkgs/e_antic/distros/arch.txt @@ -0,0 +1 @@ +e-antic diff --git a/build/pkgs/e_antic/distros/debian.txt b/build/pkgs/e_antic/distros/debian.txt new file mode 100644 index 00000000000..43fbfebd54c --- /dev/null +++ b/build/pkgs/e_antic/distros/debian.txt @@ -0,0 +1 @@ +libeantic-dev diff --git a/build/pkgs/e_antic/distros/fedora.txt b/build/pkgs/e_antic/distros/fedora.txt new file mode 100644 index 00000000000..79e976c0953 --- /dev/null +++ b/build/pkgs/e_antic/distros/fedora.txt @@ -0,0 +1 @@ +e-antic-devel diff --git a/build/pkgs/e_antic/distros/freebsd.txt b/build/pkgs/e_antic/distros/freebsd.txt new file mode 100644 index 00000000000..647f5d36fac --- /dev/null +++ b/build/pkgs/e_antic/distros/freebsd.txt @@ -0,0 +1 @@ +math/e-antic diff --git a/build/pkgs/e_antic/distros/opensuse.txt b/build/pkgs/e_antic/distros/opensuse.txt new file mode 100644 index 00000000000..79e976c0953 --- /dev/null +++ b/build/pkgs/e_antic/distros/opensuse.txt @@ -0,0 +1 @@ +e-antic-devel diff --git a/build/pkgs/e_antic/package-version.txt b/build/pkgs/e_antic/package-version.txt index 1a030947e83..6085e946503 100644 --- a/build/pkgs/e_antic/package-version.txt +++ b/build/pkgs/e_antic/package-version.txt @@ -1 +1 @@ -0.1.9 +1.2.1 diff --git a/build/pkgs/e_antic/spkg-install.in b/build/pkgs/e_antic/spkg-install.in index 0c0f5d01a1f..fcaf76055b3 100644 --- a/build/pkgs/e_antic/spkg-install.in +++ b/build/pkgs/e_antic/spkg-install.in @@ -1,10 +1,6 @@ -############################################################################### -# -# e-antic Sage install script -# -############################################################################### cd src -sdh_configure +# Following https://github.com/Normaliz/Normaliz/blob/master/install_scripts_opt/install_nmz_e-antic.sh +sdh_configure --without-byexample --without-doc --without-benchmark --without-pyeantic sdh_make sdh_make_install diff --git a/build/pkgs/flint/patches/0001-flint.h-On-GCC-4.9-do-not-use-_Thread_local.patch b/build/pkgs/flint/patches/0001-flint.h-On-GCC-4.9-do-not-use-_Thread_local.patch deleted file mode 100644 index f37e9c73476..00000000000 --- a/build/pkgs/flint/patches/0001-flint.h-On-GCC-4.9-do-not-use-_Thread_local.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 54e5a36901bcbe5dedadcf3fc670eb00a7ab9193 Mon Sep 17 00:00:00 2001 -From: Matthias Koeppe -Date: Sun, 21 Nov 2021 11:33:59 -0800 -Subject: [PATCH] flint.h: On GCC < 4.9, do not use _Thread_local - ---- - flint.h | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/flint.h b/flint.h -index 2cd15fb29..9d082f7f0 100644 ---- a/flint.h -+++ b/flint.h -@@ -157,7 +157,10 @@ FLINT_DLL void flint_set_abort(FLINT_NORETURN void (*func)(void)); - #define flint_bitcnt_t ulong - - #if FLINT_USES_TLS --#if __STDC_VERSION__ >= 201112L -+#if defined(__GNUC__) && __STDC_VERSION__ >= 201112L && __GNUC__ == 4 && __GNUC_MINOR__ < 9 -+/* GCC 4.7, 4.8 with -std=gnu11 purport to support C11 via __STDC_VERSION__ but lack _Thread_local */ -+#define FLINT_TLS_PREFIX __thread -+#elif __STDC_VERSION__ >= 201112L - #define FLINT_TLS_PREFIX _Thread_local - #elif defined(_MSC_VER) - #define FLINT_TLS_PREFIX __declspec(thread) --- -2.33.0 - diff --git a/build/pkgs/furo/checksums.ini b/build/pkgs/furo/checksums.ini index 2ba1678635d..b2f2ee12484 100644 --- a/build/pkgs/furo/checksums.ini +++ b/build/pkgs/furo/checksums.ini @@ -1,5 +1,5 @@ tarball=furo-VERSION-py3-none-any.whl -sha1=b9261dbe404cc13d399d50db0122fe48d7daeb23 -md5=fb331872d4d8a7d33f56aeb5df1f333f -cksum=3430203884 +sha1=c27ec5ecd6eb2bd30741d632a29fc1bbcc26e170 +md5=43edbca958fcdcb9df2683a81852a4e6 +cksum=1356193603 upstream_url=https://pypi.io/packages/py3/f/furo/furo-VERSION-py3-none-any.whl diff --git a/build/pkgs/furo/package-version.txt b/build/pkgs/furo/package-version.txt index 95f879eb816..b7fb725c655 100644 --- a/build/pkgs/furo/package-version.txt +++ b/build/pkgs/furo/package-version.txt @@ -1 +1 @@ -2022.6.21 +2022.9.29 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/gcc/build-gcc b/build/pkgs/gcc/build-gcc index 1b3c72b1298..a185603d453 100755 --- a/build/pkgs/gcc/build-gcc +++ b/build/pkgs/gcc/build-gcc @@ -54,9 +54,11 @@ fi if [ -n "$AS" -a "$AS" != "as" ]; then CONFIGURE_AS="--with-as=$AS" fi +unset AS if [ -n "$LD" -a "$LD" != "ld" ]; then CONFIGURE_LD="--with-ld=$LD" fi +unset LD # Use SAGE_CXX_WITHOUT_STD instead of CXX. # This fixes #29162 (gfortran 9.2.0 compile error on debian-jessie with gcc 4.9.2) diff --git a/build/pkgs/gcc/checksums.ini b/build/pkgs/gcc/checksums.ini index 2ea976e85c1..996f8360f45 100644 --- a/build/pkgs/gcc/checksums.ini +++ b/build/pkgs/gcc/checksums.ini @@ -1,5 +1,5 @@ tarball=gcc-VERSION.tar.xz -sha1=cf86a48278f9a6f4b03d4390550577b20353b4e9 -md5=4ee3e8c4c99e7b3444eb79f00f5f7a7e -cksum=215110545 +sha1=5dce6dc0091b8049b530d1587513a07201691760 +md5=73bafd0af874439dcdb9fc063b6fb069 +cksum=2807184004 upstream_url=https://mirrors.kernel.org/gnu/gcc/gcc-VERSION/gcc-VERSION.tar.xz diff --git a/build/pkgs/gcc/package-version.txt b/build/pkgs/gcc/package-version.txt index f628d2eafc5..685332623b2 100644 --- a/build/pkgs/gcc/package-version.txt +++ b/build/pkgs/gcc/package-version.txt @@ -1 +1 @@ -11.3.0 +12.2.0 diff --git a/build/pkgs/gcc/patches/gcc-12.2.0-arm.patch b/build/pkgs/gcc/patches/gcc-12.2.0-arm.patch new file mode 100644 index 00000000000..bcaade28c15 --- /dev/null +++ b/build/pkgs/gcc/patches/gcc-12.2.0-arm.patch @@ -0,0 +1,14243 @@ +diff --git a/Makefile.def b/Makefile.def +index 72d58549645..25b8563a808 100644 +--- a/Makefile.def ++++ b/Makefile.def +@@ -47,7 +47,8 @@ host_modules= { module= fixincludes; bootstrap=true; + host_modules= { module= flex; no_check_cross= true; }; + host_modules= { module= gas; bootstrap=true; }; + host_modules= { module= gcc; bootstrap=true; +- extra_make_flags="$(EXTRA_GCC_FLAGS)"; }; ++ extra_make_flags="$(EXTRA_GCC_FLAGS)"; ++ extra_configure_flags='--enable-pie-tools=@enable_pie_tools@'; }; + host_modules= { module= gmp; lib_path=.libs; bootstrap=true; + // Work around in-tree gmp configure bug with missing flex. + extra_configure_flags='--disable-shared LEX="touch lex.yy.c"'; +diff --git a/Makefile.in b/Makefile.in +index 593495e1650..807c5947895 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -112,6 +112,9 @@ GCC_SHLIB_SUBDIR = @GCC_SHLIB_SUBDIR@ + # If the build should make suitable code for shared host resources. + host_shared = @host_shared@ + ++# If we should build compilers and supporting tools as PIE. ++enable_pie_tools = @enable_pie_tools@ ++ + # Build programs are put under this directory. + BUILD_SUBDIR = @build_subdir@ + # This is set by the configure script to the arguments to use when configuring +@@ -12012,7 +12015,7 @@ configure-gcc: + $$s/$$module_srcdir/configure \ + --srcdir=$${topdir}/$$module_srcdir \ + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ +- --target=${target_alias} \ ++ --target=${target_alias} --enable-pie-tools=@enable_pie_tools@ \ + || exit 1 + @endif gcc + +@@ -12047,7 +12050,8 @@ configure-stage1-gcc: + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ + --target=${target_alias} \ + \ +- $(STAGE1_CONFIGURE_FLAGS) ++ $(STAGE1_CONFIGURE_FLAGS) \ ++ --enable-pie-tools=@enable_pie_tools@ + @endif gcc-bootstrap + + .PHONY: configure-stage2-gcc maybe-configure-stage2-gcc +@@ -12080,7 +12084,8 @@ configure-stage2-gcc: + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ +- $(STAGE2_CONFIGURE_FLAGS) ++ $(STAGE2_CONFIGURE_FLAGS) \ ++ --enable-pie-tools=@enable_pie_tools@ + @endif gcc-bootstrap + + .PHONY: configure-stage3-gcc maybe-configure-stage3-gcc +@@ -12113,7 +12118,8 @@ configure-stage3-gcc: + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ +- $(STAGE3_CONFIGURE_FLAGS) ++ $(STAGE3_CONFIGURE_FLAGS) \ ++ --enable-pie-tools=@enable_pie_tools@ + @endif gcc-bootstrap + + .PHONY: configure-stage4-gcc maybe-configure-stage4-gcc +@@ -12146,7 +12152,8 @@ configure-stage4-gcc: + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ +- $(STAGE4_CONFIGURE_FLAGS) ++ $(STAGE4_CONFIGURE_FLAGS) \ ++ --enable-pie-tools=@enable_pie_tools@ + @endif gcc-bootstrap + + .PHONY: configure-stageprofile-gcc maybe-configure-stageprofile-gcc +@@ -12179,7 +12186,8 @@ configure-stageprofile-gcc: + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ +- $(STAGEprofile_CONFIGURE_FLAGS) ++ $(STAGEprofile_CONFIGURE_FLAGS) \ ++ --enable-pie-tools=@enable_pie_tools@ + @endif gcc-bootstrap + + .PHONY: configure-stagetrain-gcc maybe-configure-stagetrain-gcc +@@ -12212,7 +12220,8 @@ configure-stagetrain-gcc: + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ +- $(STAGEtrain_CONFIGURE_FLAGS) ++ $(STAGEtrain_CONFIGURE_FLAGS) \ ++ --enable-pie-tools=@enable_pie_tools@ + @endif gcc-bootstrap + + .PHONY: configure-stagefeedback-gcc maybe-configure-stagefeedback-gcc +@@ -12245,7 +12254,8 @@ configure-stagefeedback-gcc: + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ +- $(STAGEfeedback_CONFIGURE_FLAGS) ++ $(STAGEfeedback_CONFIGURE_FLAGS) \ ++ --enable-pie-tools=@enable_pie_tools@ + @endif gcc-bootstrap + + .PHONY: configure-stageautoprofile-gcc maybe-configure-stageautoprofile-gcc +@@ -12278,7 +12288,8 @@ configure-stageautoprofile-gcc: + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ +- $(STAGEautoprofile_CONFIGURE_FLAGS) ++ $(STAGEautoprofile_CONFIGURE_FLAGS) \ ++ --enable-pie-tools=@enable_pie_tools@ + @endif gcc-bootstrap + + .PHONY: configure-stageautofeedback-gcc maybe-configure-stageautofeedback-gcc +@@ -12311,7 +12322,8 @@ configure-stageautofeedback-gcc: + $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \ + --target=${target_alias} \ + --with-build-libsubdir=$(HOST_SUBDIR) \ +- $(STAGEautofeedback_CONFIGURE_FLAGS) ++ $(STAGEautofeedback_CONFIGURE_FLAGS) \ ++ --enable-pie-tools=@enable_pie_tools@ + @endif gcc-bootstrap + + +diff --git a/Makefile.tpl b/Makefile.tpl +index ef58fac2b9a..925da105c18 100644 +--- a/Makefile.tpl ++++ b/Makefile.tpl +@@ -115,6 +115,9 @@ GCC_SHLIB_SUBDIR = @GCC_SHLIB_SUBDIR@ + # If the build should make suitable code for shared host resources. + host_shared = @host_shared@ + ++# If we should build compilers and supporting tools as PIE. ++enable_pie_tools = @enable_pie_tools@ ++ + # Build programs are put under this directory. + BUILD_SUBDIR = @build_subdir@ + # This is set by the configure script to the arguments to use when configuring +diff --git a/config/mh-darwin b/config/mh-darwin +index b72835ae953..bb4112773c9 100644 +--- a/config/mh-darwin ++++ b/config/mh-darwin +@@ -11,7 +11,8 @@ + # non-bootstrapped compiler), later stages will be built by GCC which supports + # the required flags. + +-# We cannot use mdynamic-no-pic when building shared host resources. ++# We cannot use mdynamic-no-pic when building shared host resources, or for PIE ++# tool executables, which also enables host-shared. + + ifeq (${host_shared},no) + BOOTSTRAP_TOOL_CAN_USE_MDYNAMIC_NO_PIC := $(shell \ +diff --git a/configure b/configure +index 5dcaab14ae9..c690bbec82b 100755 +--- a/configure ++++ b/configure +@@ -685,6 +685,7 @@ get_gcc_base_ver + extra_host_zlib_configure_flags + extra_host_libiberty_configure_flags + stage1_languages ++enable_pie_tools + host_shared + extra_linker_plugin_flags + extra_linker_plugin_configure_flags +@@ -830,6 +831,7 @@ enable_lto + enable_linker_plugin_configure_flags + enable_linker_plugin_flags + enable_host_shared ++enable_pie_tools + enable_stage1_languages + enable_objc_gc + with_target_bdw_gc +@@ -1558,6 +1560,8 @@ Optional Features: + additional flags for configuring and building linker + plugins [none] + --enable-host-shared build host code as shared libraries ++ --enable-pie-tools build Position Independent Executables for the ++ compilers and other tools + --enable-stage1-languages[=all] + choose additional languages to build during stage1. + Mostly useful for compiler development +@@ -8410,6 +8414,20 @@ else + fi + fi + ++case $target in ++ *-darwin2* | *-darwin1[56789]*) ++ # For these versions, we default to using embedded rpaths. ++ if test "x$enable_darwin_at_rpath" != "xno"; then ++ poststage1_ldflags="$poststage1_ldflags -nodefaultrpaths" ++ fi ++ ;; ++ *-darwin*) ++ # For these versions, we only use embedded rpaths on demand. ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ poststage1_ldflags="$poststage1_ldflags -nodefaultrpaths" ++ fi ++ ;; ++esac + + + # GCC GRAPHITE dependency isl. +@@ -8663,6 +8681,42 @@ else + fi + + ++# Check whether --enable-pie-tools was given. ++# Checked early because it can affect host make fragments. ++# Check whether --enable-pie-tools was given. ++if test "${enable_pie_tools+set}" = set; then : ++ enableval=$enable_pie_tools; enable_pie_tools=$enableval ++ case $target in ++ aarch64-*-darwin1[1-9]*) ++ if test x$enable_pie_tools != xyes ; then ++ echo configure.ac: warning: aarch64-darwin must use PIE, pie-tools setting ignored. 1>&2 ++ enable_pie_tools=yes ++ host_shared=yes ++ fi ;; ++ *) ;; ++ esac ++else ++ case $target in ++ # PIE is the default for macOS 10.7+ so reflect that in the configure. ++ # However, we build 32b toolchains mdynamic-no-pic by default which is ++ # not compatible with PIE. ++ x86_64-*-darwin1[1-9]* | *-*-darwin2*) enable_pie_tools=yes ;; ++ *) enable_pie_tools=no ;; ++ esac ++fi ++ ++ ++case $target in ++ *-*-darwin*) ++ if test x$enable_pie_tools = xyes && test x$host_shared != xyes ; then ++ echo configure.ac: warning: for Darwin PIE requires PIC code, switching host-shared on 1>&2 ++ host_shared=yes ++ fi ;; ++ *) ;; ++esac ++ ++ ++ + + # By default, C and C++ are the only stage 1 languages. + stage1_languages=,c, +diff --git a/configure.ac b/configure.ac +index 85977482aee..72bd20fda66 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1827,6 +1827,20 @@ AC_ARG_WITH(boot-ldflags, + if test "$poststage1_libs" = ""; then + poststage1_ldflags="-static-libstdc++ -static-libgcc" + fi]) ++case $target in ++ *-darwin2* | *-darwin1[[56789]]*) ++ # For these versions, we default to using embedded rpaths. ++ if test "x$enable_darwin_at_rpath" != "xno"; then ++ poststage1_ldflags="$poststage1_ldflags -nodefaultrpaths" ++ fi ++ ;; ++ *-darwin*) ++ # For these versions, we only use embedded rpaths on demand. ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ poststage1_ldflags="$poststage1_ldflags -nodefaultrpaths" ++ fi ++ ;; ++esac + AC_SUBST(poststage1_ldflags) + + # GCC GRAPHITE dependency isl. +@@ -1931,7 +1945,41 @@ AC_ARG_ENABLE(host-shared, + x86_64-*-darwin* | aarch64-*-darwin*) host_shared=yes ;; + *) host_shared=no ;; + esac]) ++ ++# Check whether --enable-pie-tools was given. ++# Checked early because it can affect host make fragments. ++AC_ARG_ENABLE(pie-tools, ++[AS_HELP_STRING([--enable-pie-tools], ++ [build Position Independent Executables for the compilers and other tools])], ++[enable_pie_tools=$enableval ++ case $target in ++ aarch64-*-darwin1[[1-9]]*) ++ if test x$enable_pie_tools != xyes ; then ++ echo configure.ac: warning: aarch64-darwin must use PIE, pie-tools setting ignored. 1>&2 ++ enable_pie_tools=yes ++ host_shared=yes ++ fi ;; ++ *) ;; ++ esac], ++[case $target in ++ # PIE is the default for macOS 10.7+ so reflect that in the configure. ++ # However, we build 32b toolchains mdynamic-no-pic by default which is ++ # not compatible with PIE. ++ x86_64-*-darwin1[[1-9]]* | *-*-darwin2*) enable_pie_tools=yes ;; ++ *) enable_pie_tools=no ;; ++ esac]) ++ ++case $target in ++ *-*-darwin*) ++ if test x$enable_pie_tools = xyes && test x$host_shared != xyes ; then ++ echo configure.ac: warning: for Darwin PIE requires PIC code, switching host-shared on 1>&2 ++ host_shared=yes ++ fi ;; ++ *) ;; ++esac ++ + AC_SUBST(host_shared) ++AC_SUBST([enable_pie_tools]) + + # By default, C and C++ are the only stage 1 languages. + stage1_languages=,c, +diff --git a/contrib/compare-debug b/contrib/compare-debug +index cf80ae32695..678a897c931 100755 +--- a/contrib/compare-debug ++++ b/contrib/compare-debug +@@ -60,9 +60,19 @@ trap 'rm -f "$1.$suf1" "$2.$suf2"' 0 1 2 15 + case `uname -s` in + Darwin) + # The strip command on darwin does not remove all debug info. +- # Fortunately, we can use ld to do it instead. +- ld -S -r -no_uuid "$1" -o "$1.$suf1" +- ld -S -r -no_uuid "$2" -o "$2.$suf2" ++ # Fortunately, we can use ld to do it instead, but even ld on earlier ++ # system versions can be fussy about what it finds - make sure we use ++ # a ld that understands coalesced sections. ++ case `uname -r` in ++ 8*) ++ ld64 -S -r -no_uuid "$1" -o "$1.$suf1" ++ ld64 -S -r -no_uuid "$2" -o "$2.$suf2" ++ ;; ++ *) ++ ld -S -r -no_uuid "$1" -o "$1.$suf1" ++ ld -S -r -no_uuid "$2" -o "$2.$suf2" ++ ;; ++ esac + ;; + *) + cp "$1" "$1.$suf1" +diff --git a/fixincludes/configure b/fixincludes/configure +index 6e2d67b655b..b3bca666a4d 100755 +--- a/fixincludes/configure ++++ b/fixincludes/configure +@@ -2644,7 +2644,7 @@ ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + # _LT_DARWIN_LINKER_FEATURES + # -------------------------- +-# Checks for linker and compiler features on darwin ++# Checks for linker and compiler features on Darwin / macOS / iOS + + + # _LT_SYS_MODULE_PATH_AIX +diff --git a/gcc/Makefile.in b/gcc/Makefile.in +index 31ff95500c9..255a10c2ce8 100644 +--- a/gcc/Makefile.in ++++ b/gcc/Makefile.in +@@ -270,11 +270,15 @@ COMPILER += $(CET_HOST_FLAGS) + NO_PIE_CFLAGS = @NO_PIE_CFLAGS@ + NO_PIE_FLAG = @NO_PIE_FLAG@ + +-# We don't want to compile the compilers with -fPIE, it make PCH fail. ++ifneq (@enable_pie_tools@,yes) ++# Build and link the compilers and tools without PIE. + COMPILER += $(NO_PIE_CFLAGS) +- +-# Link with -no-pie since we compile the compiler with -fno-PIE. + LINKER += $(NO_PIE_FLAG) ++else ++# FIXME these need to be configured. ++COMPILER += -fPIE ++LINKER += -pie ++endif + + # Like LINKER, but use a mutex for serializing front end links. + ifeq (@DO_LINK_MUTEX@,true) +@@ -407,6 +411,7 @@ ifeq ($(enable_plugin),yes) + endif + + enable_host_shared = @enable_host_shared@ ++enable_default_pie = @enable_default_pie@ + + enable_as_accelerator = @enable_as_accelerator@ + +@@ -1153,6 +1158,8 @@ LANG_MAKEFRAGS = @all_lang_makefrags@ + # Used by gcc/jit/Make-lang.in + LD_VERSION_SCRIPT_OPTION = @ld_version_script_option@ + LD_SONAME_OPTION = @ld_soname_option@ ++@ENABLE_DARWIN_AT_RPATH_TRUE@DARWIN_RPATH = @rpath ++@ENABLE_DARWIN_AT_RPATH_FALSE@DARWIN_RPATH = ${libdir} + + # Flags to pass to recursive makes. + # CC is set by configure. +@@ -1942,9 +1949,12 @@ cs-tconfig.h: Makefile + $(SHELL) $(srcdir)/mkconfig.sh tconfig.h + + cs-tm.h: Makefile +- TARGET_CPU_DEFAULT="$(target_cpu_default)" \ +- HEADERS="$(tm_include_list)" DEFINES="$(tm_defines)" \ +- $(SHELL) $(srcdir)/mkconfig.sh tm.h ++@ENABLE_DARWIN_AT_RPATH_FALSE@ TARGET_CPU_DEFAULT="$(target_cpu_default)" \ ++@ENABLE_DARWIN_AT_RPATH_FALSE@ HEADERS="$(tm_include_list)" DEFINES="$(tm_defines)" \ ++@ENABLE_DARWIN_AT_RPATH_FALSE@ $(SHELL) $(srcdir)/mkconfig.sh tm.h ++@ENABLE_DARWIN_AT_RPATH_TRUE@ TARGET_CPU_DEFAULT="$(target_cpu_default)" \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ HEADERS="$(tm_include_list)" DEFINES="$(tm_defines) DARWIN_AT_RPATH=1" \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ $(SHELL) $(srcdir)/mkconfig.sh tm.h + + cs-tm_p.h: Makefile + TARGET_CPU_DEFAULT="" \ +@@ -4116,6 +4126,9 @@ site.exp: ./config.status Makefile + echo "set COMPAT_OPTIONS \"$(COMPAT_OPTIONS)\"" >> ./site.tmp; \ + else true; \ + fi ++ @if test "x@enable_darwin_at_rpath@" = "xyes" ; then \ ++ echo "set ENABLE_DARWIN_AT_RPATH 1" >> ./site.tmp; \ ++ fi + @echo "## All variables above are generated by configure. Do Not Edit ##" >> ./site.tmp + @cat ./site.tmp > site.exp + @cat site.bak | sed \ +diff --git a/gcc/aclocal.m4 b/gcc/aclocal.m4 +index 6be36df5190..126e09bbcd1 100644 +--- a/gcc/aclocal.m4 ++++ b/gcc/aclocal.m4 +@@ -12,6 +12,56 @@ + # PARTICULAR PURPOSE. + + m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) ++# AM_CONDITIONAL -*- Autoconf -*- ++ ++# Copyright (C) 1997-2017 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_CONDITIONAL(NAME, SHELL-CONDITION) ++# ------------------------------------- ++# Define a conditional. ++AC_DEFUN([AM_CONDITIONAL], ++[AC_PREREQ([2.52])dnl ++ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], ++ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl ++AC_SUBST([$1_TRUE])dnl ++AC_SUBST([$1_FALSE])dnl ++_AM_SUBST_NOTMAKE([$1_TRUE])dnl ++_AM_SUBST_NOTMAKE([$1_FALSE])dnl ++m4_define([_AM_COND_VALUE_$1], [$2])dnl ++if $2; then ++ $1_TRUE= ++ $1_FALSE='#' ++else ++ $1_TRUE='#' ++ $1_FALSE= ++fi ++AC_CONFIG_COMMANDS_PRE( ++[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then ++ AC_MSG_ERROR([[conditional "$1" was never defined. ++Usually this means the macro was only invoked conditionally.]]) ++fi])]) ++ ++# Copyright (C) 2006-2017 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# _AM_SUBST_NOTMAKE(VARIABLE) ++# --------------------------- ++# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. ++# This macro is traced by Automake. ++AC_DEFUN([_AM_SUBST_NOTMAKE]) ++ ++# AM_SUBST_NOTMAKE(VARIABLE) ++# -------------------------- ++# Public sister of _AM_SUBST_NOTMAKE. ++AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) ++ + m4_include([../libtool.m4]) + m4_include([../ltoptions.m4]) + m4_include([../ltsugar.m4]) +diff --git a/gcc/ada/Makefile.rtl b/gcc/ada/Makefile.rtl +index aaf853e3a2a..b20218310f3 100644 +--- a/gcc/ada/Makefile.rtl ++++ b/gcc/ada/Makefile.rtl +@@ -2822,6 +2822,15 @@ ifeq ($(strip $(filter-out darwin%,$(target_os))),) + TOOLS_TARGET_PAIRS = indepsw.adb 8 * 1024 * 1024) ++ { ++ emit_move_insn (tmp_reg, gen_rtx_HIGH (mode, sym)); ++ emit_insn (gen_add_losym (dest, tmp_reg, sym)); ++ /* FIXME: add the SI option if/when we support ilp32. */ ++ emit_insn (gen_adddi3 (dest, dest, off)); ++ return; ++ } ++ /* else small enough positive offset is OK. */ ++ } + emit_move_insn (tmp_reg, gen_rtx_HIGH (mode, copy_rtx (imm))); + emit_insn (gen_add_losym (dest, tmp_reg, imm)); + return; +@@ -4598,6 +4621,7 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, + return; + } + ++ case SYMBOL_MO_SMALL_GOT: + case SYMBOL_SMALL_GOT_4G: + emit_insn (gen_rtx_SET (dest, imm)); + return; +@@ -6659,6 +6683,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) + case SYMBOL_SMALL_TLSIE: + case SYMBOL_SMALL_GOT_28K: + case SYMBOL_SMALL_GOT_4G: ++ case SYMBOL_MO_SMALL_GOT: + case SYMBOL_TINY_GOT: + case SYMBOL_TINY_TLSIE: + if (const_offset != 0) +@@ -6672,6 +6697,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) + /* FALLTHRU */ + + case SYMBOL_SMALL_ABSOLUTE: ++ case SYMBOL_MO_SMALL_PCR: + case SYMBOL_TINY_ABSOLUTE: + case SYMBOL_TLSLE12: + case SYMBOL_TLSLE24: +@@ -7251,6 +7277,7 @@ aarch64_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) + gcc_unreachable (); + } + ++#if !TARGET_MACHO + static bool + aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, + const_tree type, int *nregs) +@@ -7260,6 +7287,7 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, + &pcum->aapcs_vfp_rmode, + nregs, NULL, pcum->silent_p); + } ++#endif + + /* Given MODE and TYPE of a function argument, return the alignment in + bits. The idea is to suppress any stronger alignment requested by +@@ -7343,6 +7371,13 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) + return; + + pcum->aapcs_arg_processed = true; ++ if (TARGET_MACHO) ++ { ++ /* Set suitable defaults for queries. */ ++ pcum->darwinpcs_arg_boundary ++ = aarch64_function_arg_alignment (mode, type, &abi_break); ++ pcum->darwinpcs_arg_padding = BITS_PER_UNIT; ++ } + + pure_scalable_type_info pst_info; + if (type && pst_info.analyze_registers (type)) +@@ -7399,13 +7434,29 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) + /* No frontends can create types with variable-sized modes, so we + shouldn't be asked to pass or return them. */ + size = GET_MODE_SIZE (mode).to_constant (); ++ ++ if (TARGET_MACHO) ++ /* Since we can pack things on the stack, we need the unrounded size. */ ++ pcum->darwinpcs_stack_bytes = size; ++ + size = ROUND_UP (size, UNITS_PER_WORD); + + allocate_ncrn = (type) ? !(FLOAT_TYPE_P (type)) : !FLOAT_MODE_P (mode); ++ bool is_ha = false; ++#if !TARGET_MACHO + allocate_nvrn = aarch64_vfp_is_call_candidate (pcum_v, + mode, + type, + &nregs); ++#else ++ /* We care if the value is a homogenous aggregate when laying out the stack, ++ so use this call directly. */ ++ allocate_nvrn ++ = aarch64_vfp_is_call_or_return_candidate (mode, type, ++ &pcum->aapcs_vfp_rmode, ++ &nregs, &is_ha, ++ pcum->silent_p); ++#endif + gcc_assert (!sve_p || !allocate_nvrn); + + /* allocate_ncrn may be false-positive, but allocate_nvrn is quite reliable. +@@ -7420,7 +7471,13 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) + if (!pcum->silent_p && !TARGET_FLOAT) + aarch64_err_no_fpadvsimd (mode); + +- if (nvrn + nregs <= NUM_FP_ARG_REGS) ++ if (TARGET_MACHO ++ && !arg.named) ++ { ++ pcum->aapcs_nextnvrn = NUM_FP_ARG_REGS; ++ goto on_stack; ++ } ++ else if (nvrn + nregs <= NUM_FP_ARG_REGS) + { + pcum->aapcs_nextnvrn = nvrn + nregs; + if (!aarch64_composite_type_p (type, mode)) +@@ -7450,6 +7507,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) + } + pcum->aapcs_reg = par; + } ++ pcum->darwinpcs_stack_bytes = 0; + return; + } + else +@@ -7466,10 +7524,18 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) + /* C6 - C9. though the sign and zero extension semantics are + handled elsewhere. This is the case where the argument fits + entirely general registers. */ ++ + if (allocate_ncrn && (ncrn + nregs <= NUM_ARG_REGS)) + { + gcc_assert (nregs == 0 || nregs == 1 || nregs == 2); + ++ if (TARGET_MACHO ++ && !arg.named) ++ { ++ pcum->aapcs_nextncrn = NUM_ARG_REGS; ++ goto on_stack; ++ } ++ + /* C.8 if the argument has an alignment of 16 then the NGRN is + rounded up to the next even number. */ + if (nregs == 2 +@@ -7479,7 +7545,9 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) + alignment nregs should be > 2 and therefore it should be + passed by reference rather than value. */ + && (aarch64_function_arg_alignment (mode, type, &abi_break) +- == 16 * BITS_PER_UNIT)) ++ == 16 * BITS_PER_UNIT) ++ /* Darwin PCS deletes rule C.8. */ ++ && !TARGET_MACHO) + { + if (abi_break && warn_psabi && currently_expanding_gimple_stmt) + inform (input_location, "parameter passing for argument of type " +@@ -7525,8 +7593,8 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) + } + pcum->aapcs_reg = par; + } +- + pcum->aapcs_nextncrn = ncrn + nregs; ++ pcum->darwinpcs_stack_bytes = 0; + return; + } + +@@ -7536,10 +7604,87 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) + /* The argument is passed on stack; record the needed number of words for + this argument and align the total size if necessary. */ + on_stack: +- pcum->aapcs_stack_words = size / UNITS_PER_WORD; + +- if (aarch64_function_arg_alignment (mode, type, &abi_break) +- == 16 * BITS_PER_UNIT) ++ unsigned int align = aarch64_function_arg_alignment (mode, type, &abi_break); ++ ++ if (TARGET_MACHO) ++ { ++ /* Darwin does not round up the allocation for smaller entities to 8 ++ bytes. It only requires the natural alignment for these. ++ ++ but we don't do this for: ++ * unnamed parms in variadic functions ++ * complex types ++ * unions ++ * aggregates (except for homogeneous ones which are handles as the ++ enclosed type). ++ each entry starts a new slot. ++ ++ 16 byte entities are naturally aligned on the stack. ++ There was no darwinpcs for GCC 9, so neither the implementation ++ change nor the warning should fire here (i.e. we do not need to check ++ if 16byte entities alter the stack size). */ ++ ++gcc_checking_assert (arg.named == pcum->named_p); ++ pcum->darwinpcs_arg_padding = BITS_PER_UNIT; ++ if (!pcum->named_p ++ || TREE_CODE (type) == COMPLEX_TYPE ++ || (TREE_CODE (type) == RECORD_TYPE ++ && !is_ha && !SCALAR_FLOAT_MODE_P (pcum->aapcs_vfp_rmode)) ++ || TREE_CODE (type) == UNION_TYPE) ++ { ++ pcum->aapcs_stack_words = size / UNITS_PER_WORD; ++ pcum->darwinpcs_sub_word_offset = 0; ++ pcum->darwinpcs_sub_word_pos = 0; ++ pcum->darwinpcs_arg_boundary = MAX (align, PARM_BOUNDARY); ++ if (!pcum->named_p) ++ pcum->darwinpcs_arg_padding = PARM_BOUNDARY; ++ return; ++ } ++ ++ /* Updated sub-word offset aligned for the new object. ++ We are looking for the case that the new object will fit after some ++ existing object(s) in the same stack slot. In that case, we do not ++ need to add any more stack space for it. */ ++ int new_off ++ = ROUND_UP (pcum->darwinpcs_sub_word_pos, align / BITS_PER_UNIT); ++ ++ if (new_off >= UNITS_PER_WORD) ++ { ++ /* That exceeds a stack slot, start a new one. */ ++ pcum->darwinpcs_sub_word_offset = 0; ++ pcum->darwinpcs_sub_word_pos = 0; ++ new_off = 0; ++ } ++ /* This is the end of the new object. */ ++ int new_pos = new_off + pcum->darwinpcs_stack_bytes; ++ ++ if (pcum->darwinpcs_sub_word_pos == 0) ++ /* New stack slot, just allocate one or more words, and note where ++ the next arg will start. */ ++ pcum->aapcs_stack_words = size / UNITS_PER_WORD; ++ else if (new_pos <= UNITS_PER_WORD) ++ /* Old stack slot, object starts at new_off and goes to new_pos, we do ++ not add any stack space. */ ++ pcum->darwinpcs_sub_word_offset = new_off; ++ pcum->darwinpcs_sub_word_pos = new_pos; ++ pcum->darwinpcs_arg_boundary = align; ++ if (pcum->last_named_p && new_pos > 0) ++ { ++ /* Round the last named arg to the start of the next stack slot. */ ++ if (new_pos <= 4) ++ pcum->darwinpcs_arg_padding = PARM_BOUNDARY; ++ else if (new_pos <= 6) ++ pcum->darwinpcs_arg_padding = 4 * BITS_PER_UNIT; ++ else if (pcum->darwinpcs_sub_word_pos <= 7) ++ pcum->darwinpcs_arg_padding = 2 * BITS_PER_UNIT; ++ } ++ return; ++ } ++ ++ /* size was already rounded up to PARM_BOUNDARY. */ ++ pcum->aapcs_stack_words = size / UNITS_PER_WORD; ++ if (align == 16 * BITS_PER_UNIT) + { + int new_size = ROUND_UP (pcum->aapcs_stack_size, 16 / UNITS_PER_WORD); + if (pcum->aapcs_stack_size != new_size) +@@ -7592,7 +7737,28 @@ aarch64_init_cumulative_args (CUMULATIVE_ARGS *pcum, + pcum->aapcs_arg_processed = false; + pcum->aapcs_stack_words = 0; + pcum->aapcs_stack_size = 0; ++ pcum->darwinpcs_stack_bytes = 0; ++ pcum->darwinpcs_sub_word_offset = 0; ++ pcum->darwinpcs_sub_word_pos = 0; ++ pcum->darwinpcs_arg_boundary = BITS_PER_UNIT; ++ pcum->darwinpcs_arg_padding = BITS_PER_UNIT; ++ /* If we have been invoked for incoming args, then n_named will have been ++ set to -1, but we should have a function decl - so pick up the named ++ count from that. If that fails, and we end up with -1, this effectively ++ corresponds to assuming that there is an arbitrary number of named ++ args. */ ++ pcum->darwinpcs_n_named = n_named; ++ if (n_named == (unsigned)-1 && fndecl) ++ { ++ tree fnt = TREE_TYPE (fndecl); ++ if (fnt && TYPE_ARG_TYPES (fnt)) ++ pcum->darwinpcs_n_named = list_length (TYPE_ARG_TYPES (fnt)); ++ } ++ pcum->darwinpcs_n_args_processed = 0; ++ pcum->named_p = pcum->darwinpcs_n_named != 0; ++ pcum->last_named_p = pcum->darwinpcs_n_named == 1; + pcum->silent_p = silent_p; ++ pcum->aapcs_vfp_rmode = VOIDmode; + + if (!silent_p + && !TARGET_FLOAT +@@ -7631,8 +7797,10 @@ aarch64_function_arg_advance (cumulative_args_t pcum_v, + || pcum->pcs_variant == ARM_PCS_SVE) + { + aarch64_layout_arg (pcum_v, arg); +- gcc_assert ((pcum->aapcs_reg != NULL_RTX) +- != (pcum->aapcs_stack_words != 0)); ++ pcum->darwinpcs_n_args_processed++; ++ gcc_assert (TARGET_MACHO ++ || (pcum->aapcs_reg != NULL_RTX) ++ != (pcum->aapcs_stack_words != 0)); + pcum->aapcs_arg_processed = false; + pcum->aapcs_ncrn = pcum->aapcs_nextncrn; + pcum->aapcs_nvrn = pcum->aapcs_nextnvrn; +@@ -7640,6 +7808,12 @@ aarch64_function_arg_advance (cumulative_args_t pcum_v, + pcum->aapcs_stack_size += pcum->aapcs_stack_words; + pcum->aapcs_stack_words = 0; + pcum->aapcs_reg = NULL_RTX; ++ pcum->darwinpcs_arg_boundary = BITS_PER_UNIT; ++ pcum->darwinpcs_arg_padding = BITS_PER_UNIT; ++ pcum->named_p ++ = pcum->darwinpcs_n_args_processed < pcum->darwinpcs_n_named; ++ pcum->last_named_p ++ = pcum->darwinpcs_n_args_processed + 1 == pcum->darwinpcs_n_named; + } + } + +@@ -7650,12 +7824,15 @@ aarch64_function_arg_regno_p (unsigned regno) + || (FP_REGNUM_P (regno) && regno < V0_REGNUM + NUM_FP_ARG_REGS)); + } + +-/* Implement FUNCTION_ARG_BOUNDARY. Every parameter gets at least +- PARM_BOUNDARY bits of alignment, but will be given anything up +- to STACK_BOUNDARY bits if the type requires it. This makes sure +- that both before and after the layout of each argument, the Next +- Stacked Argument Address (NSAA) will have a minimum alignment of +- 8 bytes. */ ++/* Implement FUNCTION_ARG_BOUNDARY. ++ For AAPCS64, Every parameter gets at least PARM_BOUNDARY bits of ++ alignment, but will be given anything up to STACK_BOUNDARY bits ++ if the type requires it. This makes sure that both before and after ++ the layout of each argument, the Next Stacked Argument Address (NSAA) ++ will have a minimum alignment of 8 bytes. ++ ++ For darwinpcs, this is only called to lower va_arg entries which are ++ always aligned as for AAPCS64. */ + + static unsigned int + aarch64_function_arg_boundary (machine_mode mode, const_tree type) +@@ -7663,6 +7840,71 @@ aarch64_function_arg_boundary (machine_mode mode, const_tree type) + unsigned int abi_break; + unsigned int alignment = aarch64_function_arg_alignment (mode, type, + &abi_break); ++#if TARGET_MACHO ++ /* This can only work for unnamed args. */ ++ machine_mode comp_mode = VOIDmode; ++ int nregs; ++ bool is_ha; ++ aarch64_vfp_is_call_or_return_candidate (mode, type, &comp_mode, &nregs, ++ &is_ha, /*silent*/true); ++ if (TREE_CODE (type) == COMPLEX_TYPE ++ || (TREE_CODE (type) == RECORD_TYPE ++ && !is_ha && !SCALAR_FLOAT_MODE_P (comp_mode)) ++ || TREE_CODE (type) == UNION_TYPE) ++ return MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); ++ return MIN (alignment, STACK_BOUNDARY); ++#else ++ alignment = MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); ++ if (abi_break & warn_psabi) ++ { ++ abi_break = MIN (MAX (abi_break, PARM_BOUNDARY), STACK_BOUNDARY); ++ if (alignment != abi_break && !TARGET_MACHO) ++ inform (input_location, "parameter passing for argument of type " ++ "%qT changed in GCC 9.1", type); ++ } ++ ++ return alignment; ++#endif ++} ++ ++/* For Darwin, we want to use the arg boundary computed when laying out the ++ function arg, to cope with items packed on the stack and the different ++ rules applied to unnamed parms. */ ++ ++static unsigned int ++aarch64_function_arg_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, ++ const_tree type ATTRIBUTE_UNUSED, ++ cumulative_args_t ca ATTRIBUTE_UNUSED) ++{ ++ unsigned int abi_break; ++ unsigned int alignment = aarch64_function_arg_alignment (mode, type, ++ &abi_break); ++#if TARGET_MACHO ++ CUMULATIVE_ARGS *pcum = get_cumulative_args (ca); ++gcc_checking_assert (pcum->aapcs_arg_processed); ++ ++ bool named_p = pcum->darwinpcs_n_args_processed < pcum->darwinpcs_n_named; ++gcc_checking_assert (named_p == pcum->named_p); ++ machine_mode comp_mode = VOIDmode; ++ int nregs; ++ bool is_ha; ++ aarch64_vfp_is_call_or_return_candidate (mode, type, &comp_mode, &nregs, ++ &is_ha, /*silent*/true); ++ bool no_pack = (TREE_CODE (type) == COMPLEX_TYPE ++ || (TREE_CODE (type) == RECORD_TYPE ++ && !is_ha && !SCALAR_FLOAT_MODE_P (comp_mode)) ++ || TREE_CODE (type) == UNION_TYPE); ++ ++ bool in_regs = (pcum->aapcs_reg != NULL_RTX); ++ ++ if ((named_p && !no_pack) || in_regs) ++ ; /* Leave the alignment as natural. */ ++ else ++ alignment = MAX (alignment, PARM_BOUNDARY); ++gcc_checking_assert (alignment == pcum->darwinpcs_arg_boundary); ++ return MIN (alignment, STACK_BOUNDARY); ++ ++#else + alignment = MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); + if (abi_break & warn_psabi) + { +@@ -7673,6 +7915,44 @@ aarch64_function_arg_boundary (machine_mode mode, const_tree type) + } + + return alignment; ++#endif ++} ++ ++/* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA for darwinpcs which allows ++ non-standard passing of byte-aligned items [D.2]. This is done by pulling ++ the values out of the cumulative args struct. */ ++ ++static unsigned int ++aarch64_function_arg_round_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, ++ const_tree type ATTRIBUTE_UNUSED, ++ cumulative_args_t ca) ++{ ++ CUMULATIVE_ARGS *pcum = get_cumulative_args (ca); ++gcc_checking_assert (pcum->aapcs_arg_processed); ++ bool named_p = pcum->darwinpcs_n_args_processed < pcum->darwinpcs_n_named; ++gcc_checking_assert (named_p == pcum->named_p); ++ bool last_named_p = pcum->darwinpcs_n_args_processed + 1 == pcum->darwinpcs_n_named; ++gcc_checking_assert (last_named_p == pcum->last_named_p); ++ ++ unsigned boundary = BITS_PER_UNIT; ++ if (last_named_p && pcum->darwinpcs_sub_word_pos > 0) ++ { ++ /* Round the last named arg to the start of the next stack slot. */ ++ if (pcum->darwinpcs_sub_word_pos <= 4) ++ boundary = PARM_BOUNDARY; ++ else if (pcum->darwinpcs_sub_word_pos <= 6) ++ boundary = 4 * BITS_PER_UNIT; ++ else if (pcum->darwinpcs_sub_word_pos <= 7) ++ boundary = 2 * BITS_PER_UNIT; ++ } ++ else if (named_p) ++ /* Named args are naturally aligned, but with no rounding. */ ++ ; ++ else ++ /* un-named args are rounded to fill slots. */ ++ boundary = PARM_BOUNDARY; ++gcc_checking_assert (boundary == pcum->darwinpcs_arg_padding); ++ return boundary; + } + + /* Implement TARGET_GET_RAW_RESULT_MODE and TARGET_GET_RAW_ARG_MODE. */ +@@ -10848,6 +11128,7 @@ aarch64_classify_address (struct aarch64_address_info *info, + /* load literal: pc-relative constant pool entry. Only supported + for SI mode or larger. */ + info->type = ADDRESS_SYMBOLIC; ++ info->offset = NULL_RTX; + + if (!load_store_pair_p + && GET_MODE_SIZE (mode).is_constant (&const_size) +@@ -10855,6 +11136,7 @@ aarch64_classify_address (struct aarch64_address_info *info, + { + poly_int64 offset; + rtx sym = strip_offset_and_salt (x, &offset); ++ + return ((LABEL_REF_P (sym) + || (SYMBOL_REF_P (sym) + && CONSTANT_POOL_ADDRESS_P (sym) +@@ -10872,10 +11154,13 @@ aarch64_classify_address (struct aarch64_address_info *info, + poly_int64 offset; + HOST_WIDE_INT const_offset; + rtx sym = strip_offset_and_salt (info->offset, &offset); ++ + if (SYMBOL_REF_P (sym) + && offset.is_constant (&const_offset) + && (aarch64_classify_symbol (sym, const_offset) +- == SYMBOL_SMALL_ABSOLUTE)) ++ == SYMBOL_SMALL_ABSOLUTE ++ || aarch64_classify_symbol (sym, const_offset) ++ == SYMBOL_MO_SMALL_PCR)) + { + /* The symbol and offset must be aligned to the access size. */ + unsigned int align; +@@ -10925,6 +11210,55 @@ aarch64_address_valid_for_prefetch_p (rtx x, bool strict_p) + if (!res) + return false; + ++ /* For ELF targets using GAS, we emit prfm unconditionally; GAS will alter ++ the instruction to pick the prfum form where possible (i.e. when the ++ offset is in the range -256..255) and fall back to prfm otherwise. ++ We can reject cases where the offset exceeds the range usable by both ++ insns [-256..32760], or for offsets > 255 when the value is not divisible ++ by 8. ++ For Mach-O (Darwin) where the assembler uses the LLVM back end, that does ++ not yet do the substitution, so we must reject all prfum cases. */ ++ if (addr.offset) ++ { ++ HOST_WIDE_INT offs = INTVAL (addr.offset); ++ if (offs < -256) /* Out of range for both prfum and prfm. */ ++ return false; ++ if (offs > 32760) /* Out of range for prfm. */ ++ return false; ++ if (offs & 0x07) /* We cannot use prfm. */ ++ { ++ if (offs > 255) /* Out of range for prfum. */ ++ return false; ++ if (TARGET_MACHO) ++ return false; ++ } ++ if (TARGET_MACHO && offs < 0) ++ return false; ++ } ++ ++ /* ... except writeback forms. */ ++ return addr.type != ADDRESS_REG_WB; ++} ++ ++/* Return true if the address X is valid for a PRFUM instruction. ++ STRICT_P is true if we should do strict checking with ++ aarch64_classify_address. */ ++ ++bool ++aarch64_address_valid_for_unscaled_prefetch_p (rtx x, bool strict_p) ++{ ++ struct aarch64_address_info addr; ++ ++ /* PRFUM accepts the same addresses as DImode, but constrained to a range ++ -256..255. */ ++ bool res = aarch64_classify_address (&addr, x, DImode, strict_p); ++ if (!res) ++ return false; ++ ++ if (addr.offset && ((INTVAL (addr.offset) > 255) ++ || (INTVAL (addr.offset) < -256))) ++ return false; ++ + /* ... except writeback forms. */ + return addr.type != ADDRESS_REG_WB; + } +@@ -11609,6 +11943,144 @@ sizetochar (int size) + } + } + ++static void ++output_macho_postfix_expr (FILE *file, rtx x, const char *postfix) ++{ ++ char buf[256]; ++ ++ restart: ++ switch (GET_CODE (x)) ++ { ++ case PC: ++ putc ('.', file); ++ break; ++ ++ case SYMBOL_REF: ++ if (SYMBOL_REF_DECL (x)) ++ assemble_external (SYMBOL_REF_DECL (x)); ++ assemble_name (file, XSTR (x, 0)); ++ fprintf (file, "@%s", postfix); ++ break; ++ ++ case LABEL_REF: ++ x = label_ref_label (x); ++ /* Fall through. */ ++ case CODE_LABEL: ++ ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); ++ assemble_name (file, buf); ++ fprintf (file, "@%s", postfix); ++ break; ++ ++ case CONST_INT: ++ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); ++ break; ++ ++ case CONST: ++ /* This used to output parentheses around the expression, ++ but that does not work on the 386 (either ATT or BSD assembler). */ ++ output_macho_postfix_expr (file, XEXP (x, 0), postfix); ++ break; ++ ++ case CONST_WIDE_INT: ++ /* We do not know the mode here so we have to use a round about ++ way to build a wide-int to get it printed properly. */ ++ { ++ wide_int w = wide_int::from_array (&CONST_WIDE_INT_ELT (x, 0), ++ CONST_WIDE_INT_NUNITS (x), ++ CONST_WIDE_INT_NUNITS (x) ++ * HOST_BITS_PER_WIDE_INT, ++ false); ++ print_decs (w, file); ++ } ++ break; ++ ++ case CONST_DOUBLE: ++ if (CONST_DOUBLE_AS_INT_P (x)) ++ { ++ /* We can use %d if the number is one word and positive. */ ++ if (CONST_DOUBLE_HIGH (x)) ++ fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, ++ (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x), ++ (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x)); ++ else if (CONST_DOUBLE_LOW (x) < 0) ++ fprintf (file, HOST_WIDE_INT_PRINT_HEX, ++ (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x)); ++ else ++ fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); ++ } ++ else ++ /* We can't handle floating point constants; ++ PRINT_OPERAND must handle them. */ ++ output_operand_lossage ("floating constant misused"); ++ break; ++ ++ case CONST_FIXED: ++ fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_FIXED_VALUE_LOW (x)); ++ break; ++ ++ case PLUS: ++ /* Some assemblers need integer constants to appear last (eg masm). */ ++ if (CONST_INT_P (XEXP (x, 0))) ++ { ++ output_macho_postfix_expr (file, XEXP (x, 1), postfix); ++ if (INTVAL (XEXP (x, 0)) >= 0) ++ fprintf (file, "+"); ++ output_addr_const (file, XEXP (x, 0)); ++ } ++ else ++ { ++ output_macho_postfix_expr (file, XEXP (x, 0), postfix); ++ if (!CONST_INT_P (XEXP (x, 1)) ++ || INTVAL (XEXP (x, 1)) >= 0) ++ fprintf (file, "+"); ++ output_addr_const (file, XEXP (x, 1)); ++ } ++ break; ++ ++ case MINUS: ++ /* Avoid outputting things like x-x or x+5-x, ++ since some assemblers can't handle that. */ ++ x = simplify_subtraction (x); ++ if (GET_CODE (x) != MINUS) ++ goto restart; ++ ++ output_macho_postfix_expr (file, XEXP (x, 0), postfix); ++ fprintf (file, "-"); ++ if ((CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0) ++ || GET_CODE (XEXP (x, 1)) == PC ++ || GET_CODE (XEXP (x, 1)) == SYMBOL_REF) ++ output_addr_const (file, XEXP (x, 1)); ++ else ++ { ++ fputs (targetm.asm_out.open_paren, file); ++ output_addr_const (file, XEXP (x, 1)); ++ fputs (targetm.asm_out.close_paren, file); ++ } ++ break; ++ ++ case ZERO_EXTEND: ++ case SIGN_EXTEND: ++ case SUBREG: ++ case TRUNCATE: ++ output_addr_const (file, XEXP (x, 0)); ++ break; ++ ++ case UNSPEC: ++ if (XINT (x, 1) == UNSPEC_SALT_ADDR) ++ { ++ output_macho_postfix_expr (file, XVECEXP (x, 0, 0), postfix); ++ break; ++ } ++ /* FALLTHROUGH */ ++ default: ++ if (targetm.asm_out.output_addr_const_extra (file, x)) ++ break; ++ ++ output_operand_lossage ("invalid expression as operand"); ++ } ++ ++} ++ + /* Print operand X to file F in a target specific manner according to CODE. + The acceptable formatting commands given by CODE are: + 'c': An integer or symbol address without a preceding # +@@ -11677,6 +12149,12 @@ aarch64_print_operand (FILE *f, rtx x, int code) + } + break; + ++ case 'K': ++ output_macho_postfix_expr (f, x, "PAGEOFF"); ++ break; ++ case 'O': ++ output_macho_postfix_expr (f, x, "GOTPAGEOFF"); ++ break; + case 'e': + { + x = unwrap_const_vec_duplicate (x); +@@ -12000,7 +12478,7 @@ aarch64_print_operand (FILE *f, rtx x, int code) + case 'A': + if (GET_CODE (x) == HIGH) + x = XEXP (x, 0); +- ++#if !TARGET_MACHO + switch (aarch64_classify_symbolic_expression (x)) + { + case SYMBOL_SMALL_GOT_4G: +@@ -12031,9 +12509,29 @@ aarch64_print_operand (FILE *f, rtx x, int code) + break; + } + output_addr_const (asm_out_file, x); ++#endif ++#if TARGET_MACHO ++ // FIXME update classify symbolic expression to handle macho. ++ switch (aarch64_classify_symbolic_expression (x)) ++ { ++ case SYMBOL_MO_SMALL_PCR: ++ output_macho_postfix_expr (asm_out_file, x, "PAGE"); ++// asm_fprintf (asm_out_file, "@PAGE;mopcr"); ++ break; ++ case SYMBOL_MO_SMALL_GOT: ++ output_macho_postfix_expr (asm_out_file, x, "GOTPAGE"); ++// asm_fprintf (asm_out_file, "@GOTPAGE;mosg"); ++ break; ++ default: ++ output_macho_postfix_expr (asm_out_file, x, "BLEAH"); ++// asm_fprintf (asm_out_file, "@BLEAH"); ++ break; ++ } ++#endif + break; + + case 'L': ++#if !TARGET_MACHO + switch (aarch64_classify_symbolic_expression (x)) + { + case SYMBOL_SMALL_GOT_4G: +@@ -12071,10 +12569,12 @@ aarch64_print_operand (FILE *f, rtx x, int code) + default: + break; + } ++#endif + output_addr_const (asm_out_file, x); + break; + + case 'G': ++#if !TARGET_MACHO + switch (aarch64_classify_symbolic_expression (x)) + { + case SYMBOL_TLSLE24: +@@ -12083,6 +12583,7 @@ aarch64_print_operand (FILE *f, rtx x, int code) + default: + break; + } ++#endif + output_addr_const (asm_out_file, x); + break; + +@@ -12232,8 +12733,14 @@ aarch64_print_address_internal (FILE *f, machine_mode mode, rtx x, + break; + + case ADDRESS_LO_SUM: ++#if TARGET_MACHO ++ asm_fprintf (f, "[%s, #", reg_names [REGNO (addr.base)]); ++ output_macho_postfix_expr (f, addr.offset, "PAGEOFF"); ++// output_addr_const (f, addr.offset); ++#else + asm_fprintf (f, "[%s, #:lo12:", reg_names [REGNO (addr.base)]); + output_addr_const (f, addr.offset); ++#endif + asm_fprintf (f, "]"); + return true; + +@@ -12703,6 +13210,8 @@ aarch64_asm_output_labelref (FILE* f, const char *name) + asm_fprintf (f, "%U%s", name); + } + ++#if !TARGET_MACHO ++ + static void + aarch64_elf_asm_constructor (rtx symbol, int priority) + { +@@ -12742,6 +13251,7 @@ aarch64_elf_asm_destructor (rtx symbol, int priority) + assemble_aligned_integer (POINTER_BYTES, symbol); + } + } ++#endif + + const char* + aarch64_output_casesi (rtx *operands) +@@ -15048,15 +15558,17 @@ aarch64_init_builtins () + { + aarch64_general_init_builtins (); + aarch64_sve::init_builtins (); +-#ifdef SUBTARGET_INIT_BUILTINS +- SUBTARGET_INIT_BUILTINS; +-#endif ++ aarch64_init_subtarget_builtins (); + } + + /* Implement TARGET_FOLD_BUILTIN. */ + static tree + aarch64_fold_builtin (tree fndecl, int nargs, tree *args, bool) + { ++#ifdef SUBTARGET_FOLD_BUILTIN ++ if (tree res = SUBTARGET_FOLD_BUILTIN (fndecl, nargs, args, false)) ++ return res; ++#endif + unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); + unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; + tree type = TREE_TYPE (TREE_TYPE (fndecl)); +@@ -18326,10 +18838,14 @@ initialize_aarch64_code_model (struct gcc_options *opts) + } + break; + case AARCH64_CMODEL_LARGE: +- if (opts->x_flag_pic) ++ if (TARGET_MACHO) ++ /* We need to implement fPIC here (arm64_32 also accepts the large ++ model). */ ++ ; ++ else if (opts->x_flag_pic) + sorry ("code model %qs with %<-f%s%>", "large", + opts->x_flag_pic > 1 ? "PIC" : "pic"); +- if (opts->x_aarch64_abi == AARCH64_ABI_ILP32) ++ else if (opts->x_aarch64_abi == AARCH64_ABI_ILP32) + sorry ("code model %qs not supported in ilp32 mode", "large"); + break; + case AARCH64_CMODEL_TINY_PIC: +@@ -19252,7 +19768,9 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) + case AARCH64_CMODEL_SMALL_SPIC: + case AARCH64_CMODEL_SMALL_PIC: + case AARCH64_CMODEL_SMALL: +- return SYMBOL_SMALL_ABSOLUTE; ++ return TARGET_MACHO ++ ? SYMBOL_MO_SMALL_PCR ++ : SYMBOL_SMALL_ABSOLUTE; + + default: + gcc_unreachable (); +@@ -19288,10 +19806,22 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) + + return SYMBOL_TINY_ABSOLUTE; + +- + case AARCH64_CMODEL_SMALL_SPIC: + case AARCH64_CMODEL_SMALL_PIC: + case AARCH64_CMODEL_SMALL: ++#if TARGET_MACHO ++ if (TARGET_MACHO) ++ { ++ /* Constant pool addresses are always TU-local and PC- ++ relative. We indirect common, external and weak ++ symbols (but weak only if not hidden). */ ++ if (!CONSTANT_POOL_ADDRESS_P (x) ++ && (MACHO_SYMBOL_MUST_INDIRECT_P (x) ++ || !aarch64_symbol_binds_local_p (x))) ++ return SYMBOL_MO_SMALL_GOT; ++ } ++ else ++#endif + if ((flag_pic || SYMBOL_REF_WEAK (x)) + && !aarch64_symbol_binds_local_p (x)) + return aarch64_cmodel == AARCH64_CMODEL_SMALL_SPIC +@@ -19303,7 +19833,8 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) + || offset_within_block_p (x, offset))) + return SYMBOL_FORCE_TO_MEM; + +- return SYMBOL_SMALL_ABSOLUTE; ++ return TARGET_MACHO ? SYMBOL_MO_SMALL_PCR ++ : SYMBOL_SMALL_ABSOLUTE; + + case AARCH64_CMODEL_LARGE: + /* This is alright even in PIC code as the constant +@@ -19433,7 +19964,10 @@ static GTY(()) tree va_list_type; + void *__vr_top; + int __gr_offs; + int __vr_offs; +- }; */ ++ }; ++ ++ darwinpcs uses 'char *' for the va_list (in common with other platform ++ ports). */ + + static tree + aarch64_build_builtin_va_list (void) +@@ -19441,6 +19975,13 @@ aarch64_build_builtin_va_list (void) + tree va_list_name; + tree f_stack, f_grtop, f_vrtop, f_groff, f_vroff; + ++ /* darwinpcs uses a simple char * for this. */ ++ if (TARGET_MACHO) ++ { ++ va_list_type = build_pointer_type (char_type_node); ++ return va_list_type; ++ } ++ + /* Create the type. */ + va_list_type = lang_hooks.types.make_type (RECORD_TYPE); + /* Give it the required name. */ +@@ -19512,6 +20053,13 @@ aarch64_expand_builtin_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) + int vr_save_area_size = cfun->va_list_fpr_size; + int vr_offset; + ++ /* darwinpcs uses the default, char * va_list impl. */ ++ if (TARGET_MACHO) ++ { ++ std_expand_builtin_va_start (valist, nextarg); ++ return; ++ } ++ + cum = &crtl->args.info; + if (cfun->va_list_gpr_size) + gr_save_area_size = MIN ((NUM_ARG_REGS - cum->aapcs_ncrn) * UNITS_PER_WORD, +@@ -19602,6 +20150,9 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, + HOST_WIDE_INT size, rsize, adjust, align; + tree t, u, cond1, cond2; + ++ if (TARGET_MACHO) ++ return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); ++ + indirect_p = pass_va_arg_by_reference (type); + if (indirect_p) + type = build_pointer_type (type); +@@ -19786,8 +20337,18 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, + field_ptr_t = double_ptr_type_node; + break; + case E_TFmode: +- field_t = long_double_type_node; +- field_ptr_t = long_double_ptr_type_node; ++ if (TARGET_MACHO) ++ { ++ /* Darwin has __float128, and long double is the same as ++ double. */ ++ field_t = float128_type_node; ++ field_ptr_t = aarch64_float128_ptr_type_node; ++ } ++ else ++ { ++ field_t = long_double_type_node; ++ field_ptr_t = long_double_ptr_type_node; ++ } + break; + case E_HFmode: + field_t = aarch64_fp16_type_node; +@@ -19858,6 +20419,9 @@ aarch64_setup_incoming_varargs (cumulative_args_t cum_v, + int gr_saved = cfun->va_list_gpr_size; + int vr_saved = cfun->va_list_fpr_size; + ++ if (TARGET_MACHO) ++ return default_setup_incoming_varargs (cum_v, arg, pretend_size, no_rtl); ++ + /* The caller has advanced CUM up to, but not beyond, the last named + argument. Advance a local copy of CUM past the last "real" named + argument, to find out how many registers are left over. */ +@@ -20685,6 +21249,12 @@ aarch64_autovectorize_vector_modes (vector_modes *modes, bool) + static const char * + aarch64_mangle_type (const_tree type) + { ++ /* The darwinpcs ABI documents say that "__va_list" has to be ++ mangled as char *. */ ++ if (TARGET_MACHO ++ && lang_hooks.types_compatible_p (CONST_CAST_TREE (type), va_list_type)) ++ return "Pc"; ++ + /* The AArch64 ABI documents say that "__va_list" has to be + mangled as if it is in the "std" namespace. */ + if (lang_hooks.types_compatible_p (CONST_CAST_TREE (type), va_list_type)) +@@ -20699,6 +21269,10 @@ aarch64_mangle_type (const_tree type) + return "Dh"; + } + ++ /* TFmode is __float128 for Darwin. */ ++ if (TARGET_MACHO && TYPE_MODE (type) == TFmode) ++ return "g"; ++ + /* Mangle AArch64-specific internal types. TYPE_NAME is non-NULL_TREE for + builtin types. */ + if (TYPE_NAME (type) != NULL) +@@ -21389,7 +21963,8 @@ aarch64_mov_operand_p (rtx x, machine_mode mode) + + /* GOT accesses are valid moves. */ + if (SYMBOL_REF_P (x) +- && aarch64_classify_symbolic_expression (x) == SYMBOL_SMALL_GOT_4G) ++ && (aarch64_classify_symbolic_expression (x) == SYMBOL_SMALL_GOT_4G ++ || aarch64_classify_symbolic_expression (x) == SYMBOL_MO_SMALL_GOT)) + return true; + + if (SYMBOL_REF_P (x) && mode == DImode && CONSTANT_ADDRESS_P (x)) +@@ -22549,7 +23124,9 @@ aarch64_declare_function_name (FILE *stream, const char* name, + aarch64_asm_output_variant_pcs (stream, fndecl, name); + + /* Don't forget the type directive for ELF. */ ++#ifdef ASM_OUTPUT_TYPE_DIRECTIVE + ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function"); ++#endif + ASM_OUTPUT_LABEL (stream, name); + + cfun->machine->label_is_assembled = true; +@@ -22584,12 +23161,17 @@ aarch64_print_patchable_function_entry (FILE *file, + /* Implement ASM_OUTPUT_DEF_FROM_DECLS. Output .variant_pcs for aliases. */ + + void +-aarch64_asm_output_alias (FILE *stream, const tree decl, const tree target) ++aarch64_asm_output_alias (FILE *stream, const tree decl, ++ const tree target ATTRIBUTE_UNUSED) + { + const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); ++#ifdef ASM_OUTPUT_DEF + const char *value = IDENTIFIER_POINTER (target); ++#endif + aarch64_asm_output_variant_pcs (stream, decl, name); ++#ifdef ASM_OUTPUT_DEF + ASM_OUTPUT_DEF (stream, name, value); ++#endif + } + + /* Implement ASM_OUTPUT_EXTERNAL. Output .variant_pcs for undefined +@@ -23213,6 +23795,16 @@ aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width, + } + + gcc_assert (CONST_INT_P (info.u.mov.value)); ++ unsigned HOST_WIDE_INT value = UINTVAL (info.u.mov.value); ++ ++ /* We have signed chars which can result in a sign-extended 8bit value ++ which is then emitted as an unsigned hex value, and the LLVM back end ++ assembler rejects that as being too big. */ ++ if (TARGET_MACHO && (known_eq (GET_MODE_BITSIZE (info.elt_mode), 8))) ++ { ++ unsigned HOST_WIDE_INT mask = (1U << GET_MODE_BITSIZE (info.elt_mode))-1; ++ value &= mask; ++ } + + if (which == AARCH64_CHECK_MOV) + { +@@ -23221,16 +23813,16 @@ aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width, + ? "msl" : "lsl"); + if (lane_count == 1) + snprintf (templ, sizeof (templ), "%s\t%%d0, " HOST_WIDE_INT_PRINT_HEX, +- mnemonic, UINTVAL (info.u.mov.value)); ++ mnemonic, value); + else if (info.u.mov.shift) + snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, " + HOST_WIDE_INT_PRINT_HEX ", %s %d", mnemonic, lane_count, +- element_char, UINTVAL (info.u.mov.value), shift_op, ++ element_char, value, shift_op, + info.u.mov.shift); + else + snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, " + HOST_WIDE_INT_PRINT_HEX, mnemonic, lane_count, +- element_char, UINTVAL (info.u.mov.value)); ++ element_char, value); + } + else + { +@@ -23239,12 +23831,12 @@ aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width, + if (info.u.mov.shift) + snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #" + HOST_WIDE_INT_PRINT_DEC ", %s #%d", mnemonic, lane_count, +- element_char, UINTVAL (info.u.mov.value), "lsl", ++ element_char, value, "lsl", + info.u.mov.shift); + else + snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #" + HOST_WIDE_INT_PRINT_DEC, mnemonic, lane_count, +- element_char, UINTVAL (info.u.mov.value)); ++ element_char, value); + } + return templ; + } +@@ -26355,12 +26947,12 @@ aarch64_libgcc_floating_mode_supported_p (scalar_float_mode mode) + } + + /* Implement TARGET_SCALAR_MODE_SUPPORTED_P - return TRUE +- if MODE is HFmode, and punt to the generic implementation otherwise. */ ++ if MODE is HFmode, or TFmode on Mach-O, and punt to the generic implementation otherwise. */ + + static bool + aarch64_scalar_mode_supported_p (scalar_mode mode) + { +- return (mode == HFmode ++ return (mode == HFmode || (mode == TFmode && TARGET_MACHO) + ? true + : default_scalar_mode_supported_p (mode)); + } +@@ -27118,19 +27710,37 @@ aarch64_sls_emit_shared_blr_thunks (FILE *out_file) + continue; + + const char *name = indirect_symbol_names[regnum]; +- switch_to_section (get_named_section (decl, NULL, 0)); ++ /* If the target uses a unique section for this switch to it. */ ++ if (DECL_SECTION_NAME (decl)) ++ switch_to_section (get_named_section (decl, NULL, 0)); ++ else ++ switch_to_section (text_section); + ASM_OUTPUT_ALIGN (out_file, 2); +- targetm.asm_out.globalize_label (out_file, name); ++ if (!TARGET_MACHO) ++ targetm.asm_out.globalize_label (out_file, name); ++#ifdef ASM_OUTPUT_TYPE_DIRECTIVE ++ ASM_OUTPUT_TYPE_DIRECTIVE (out_file, name, "function"); ++#endif ++ if (TARGET_MACHO) ++ { ++#ifdef ASM_WEAKEN_DECL ++ if (DECL_WEAK (decl)) ++ ASM_WEAKEN_DECL (out_file, decl, name, 0); ++ else ++#endif ++ targetm.asm_out.globalize_decl_name (out_file, decl); ++ } + /* Only emits if the compiler is configured for an assembler that can + handle visibility directives. */ + targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN); +- ASM_OUTPUT_TYPE_DIRECTIVE (out_file, name, "function"); + ASM_OUTPUT_LABEL (out_file, name); + aarch64_sls_emit_function_stub (out_file, regnum); + /* Use the most conservative target to ensure it can always be used by any + function in the translation unit. */ + asm_fprintf (out_file, "\tdsb\tsy\n\tisb\n"); ++#ifdef ASM_DECLARE_FUNCTION_SIZE + ASM_DECLARE_FUNCTION_SIZE (out_file, name, decl); ++#endif + } + } + +@@ -27323,6 +27933,15 @@ aarch64_run_selftests (void) + #undef TARGET_ASM_ALIGNED_SI_OP + #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" + ++#if TARGET_MACHO ++#undef TARGET_ASM_UNALIGNED_HI_OP ++#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t" ++#undef TARGET_ASM_UNALIGNED_SI_OP ++#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t" ++#undef TARGET_ASM_UNALIGNED_DI_OP ++#define TARGET_ASM_UNALIGNED_DI_OP "\t.quad\t" ++#endif ++ + #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK + #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ + hook_bool_const_tree_hwi_hwi_const_tree_true +@@ -27409,6 +28028,12 @@ aarch64_run_selftests (void) + #undef TARGET_FUNCTION_ARG_BOUNDARY + #define TARGET_FUNCTION_ARG_BOUNDARY aarch64_function_arg_boundary + ++#undef TARGET_FUNCTION_ARG_BOUNDARY_CA ++#define TARGET_FUNCTION_ARG_BOUNDARY_CA aarch64_function_arg_boundary_ca ++ ++#undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA ++#define TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA aarch64_function_arg_round_boundary_ca ++ + #undef TARGET_FUNCTION_ARG_PADDING + #define TARGET_FUNCTION_ARG_PADDING aarch64_function_arg_padding + +@@ -27736,7 +28361,7 @@ aarch64_libgcc_floating_mode_supported_p + + /* The architecture reserves bits 0 and 1 so use bit 2 for descriptors. */ + #undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS +-#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 4 ++#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS AARCH64_CUSTOM_FUNCTION_TEST + + #undef TARGET_HARD_REGNO_NREGS + #define TARGET_HARD_REGNO_NREGS aarch64_hard_regno_nregs +diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h +index 359b6e8561f..db5fe441b36 100644 +--- a/gcc/config/aarch64/aarch64.h ++++ b/gcc/config/aarch64/aarch64.h +@@ -58,6 +58,10 @@ + #define TARGET_SIMD (!TARGET_GENERAL_REGS_ONLY && AARCH64_ISA_SIMD) + #define TARGET_FLOAT (!TARGET_GENERAL_REGS_ONLY && AARCH64_ISA_FP) + ++/* If this is non-zero then generated code of the object format, ABI and ++ assembler syntax used by Darwin (Mach-O) platforms. */ ++#define TARGET_MACHO 0 ++ + #define UNITS_PER_WORD 8 + + #define UNITS_PER_VREG 16 +@@ -135,6 +139,12 @@ + /* Heap alignment (same as BIGGEST_ALIGNMENT and STACK_BOUNDARY). */ + #define MALLOC_ABI_ALIGNMENT 128 + ++/* We will and with this value to test if a custom function descriptor needs ++ a static chain. The function boundary must the adjusted so that the bit ++ this represents is no longer part of the address. 0 Disables the custom ++ function descriptors. */ ++#define AARCH64_CUSTOM_FUNCTION_TEST 4 ++ + /* Defined by the ABI */ + #define WCHAR_TYPE "unsigned int" + #define WCHAR_TYPE_SIZE 32 +@@ -1025,6 +1035,24 @@ typedef struct + aapcs_reg == NULL_RTX. */ + int aapcs_stack_size; /* The total size (in words, per 8 byte) of the + stack arg area so far. */ ++ ++ /* In the darwinpcs, items smaller than one word are packed onto the stack ++ naturally aligned. Unnamed parameters passed in a variadic call are, ++ however, aligned the same way as the AAPCS64. This means that we need to ++ pad the last named arg to the next parm boundary (and hence notice when ++ we are processing that arg). */ ++ int darwinpcs_stack_bytes; /* If the argument is passed on the stack, this ++ the byte-size. */ ++ int darwinpcs_sub_word_offset;/* This is the offset of this arg within a word ++ when placing smaller items for darwinpcs. */ ++ int darwinpcs_sub_word_pos; /* The next byte available within the word for ++ darwinpcs. */ ++ unsigned darwinpcs_arg_boundary; /* The computed argument boundary. */ ++ unsigned darwinpcs_arg_padding; /* The computed argument padding. */ ++ unsigned darwinpcs_n_named; /* Number of named arguments. */ ++ unsigned darwinpcs_n_args_processed; /* Processed so far. */ ++ bool named_p; /* Is this arg named? */ ++ bool last_named_p; /* Is this the last named arg? */ + bool silent_p; /* True if we should act silently, rather than + raise an error for invalid calls. */ + } CUMULATIVE_ARGS; +@@ -1309,8 +1337,13 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); + #define ASM_CPU_SPEC \ + MCPU_TO_MARCH_SPEC + ++#ifndef SUBTARGET_EXTRA_SPECS ++#define SUBTARGET_EXTRA_SPECS ++#endif ++ + #define EXTRA_SPECS \ +- { "asm_cpu_spec", ASM_CPU_SPEC } ++ { "asm_cpu_spec", ASM_CPU_SPEC }, \ ++ SUBTARGET_EXTRA_SPECS + + #define ASM_OUTPUT_POOL_EPILOGUE aarch64_asm_output_pool_epilogue + +@@ -1324,6 +1357,10 @@ extern GTY(()) tree aarch64_fp16_ptr_type_node; + extern GTY(()) tree aarch64_bf16_type_node; + extern GTY(()) tree aarch64_bf16_ptr_type_node; + ++/* A pointer to the user-visible __float128 (on Mach-O). Defined in ++ aarch64-builtins.c. */ ++extern GTY(()) tree aarch64_float128_ptr_type_node; ++ + /* The generic unwind code in libgcc does not initialize the frame pointer. + So in order to unwind a function using a frame pointer, the very first + function that is unwound must save the frame pointer. That way the frame +diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md +index 34b8059b45b..c356d3048b5 100644 +--- a/gcc/config/aarch64/aarch64.md ++++ b/gcc/config/aarch64/aarch64.md +@@ -303,6 +303,7 @@ + UNSPEC_TAG_SPACE ; Translate address to MTE tag address space. + UNSPEC_LD1RO + UNSPEC_SALT_ADDR ++ UNSPEC_MACHOPIC_OFFSET + ]) + + (define_c_enum "unspecv" [ +@@ -849,6 +850,37 @@ + [(set_attr "type" "load_4")] + ) + ++(define_insn "prefetch_unscaled" ++ [(prefetch (match_operand:DI 0 "aarch64_unscaled_prefetch_operand" "Du") ++ (match_operand:QI 1 "const_int_operand" "") ++ (match_operand:QI 2 "const_int_operand" ""))] ++ "" ++ { ++ const char * pftype[2][4] = ++ { ++ {"prfum\\tPLDL1STRM, %0", ++ "prfum\\tPLDL3KEEP, %0", ++ "prfum\\tPLDL2KEEP, %0", ++ "prfum\\tPLDL1KEEP, %0"}, ++ {"prfum\\tPSTL1STRM, %0", ++ "prfum\\tPSTL3KEEP, %0", ++ "prfum\\tPSTL2KEEP, %0", ++ "prfum\\tPSTL1KEEP, %0"}, ++ }; ++ ++ int locality = INTVAL (operands[2]); ++ ++ gcc_assert (IN_RANGE (locality, 0, 3)); ++ ++ /* PRFUM accepts the same addresses as a 64-bit LDR so wrap ++ the address into a DImode MEM so that aarch64_print_operand knows ++ how to print it. */ ++ operands[0] = gen_rtx_MEM (DImode, operands[0]); ++ return pftype[INTVAL(operands[1])][locality]; ++ } ++ [(set_attr "type" "load_4")] ++) ++ + (define_insn "trap" + [(trap_if (const_int 1) (const_int 8))] + "" +@@ -1286,7 +1318,7 @@ + ldr\\t%s0, %1 + str\\t%w1, %0 + str\\t%s1, %0 +- adrp\\t%x0, %A1\;ldr\\t%w0, [%x0, %L1] ++ * return TARGET_MACHO ? \"adrp\\t%x0, %A1\;ldr\\t%w0, [%x0, %O1]\" : \"adrp\\t%x0, %A1\;ldr\\t%w0, [%x0, %L1]\"; + adr\\t%x0, %c1 + adrp\\t%x0, %A1 + fmov\\t%s0, %w1 +@@ -1325,7 +1357,7 @@ + ldr\\t%d0, %1 + str\\t%x1, %0 + str\\t%d1, %0 +- * return TARGET_ILP32 ? \"adrp\\t%0, %A1\;ldr\\t%w0, [%0, %L1]\" : \"adrp\\t%0, %A1\;ldr\\t%0, [%0, %L1]\"; ++ * return TARGET_ILP32 ? (TARGET_MACHO ? \"adrp\\t%0, %A1\;ldr\\t%w0, [%0, %O1]\" : \"adrp\\t%0, %A1\;ldr\\t%w0, [%0, %L1]\") : (TARGET_MACHO ? \"adrp\\t%0, %A1\;ldr\\t%0, [%0, %O1]\" : \"adrp\\t%0, %A1\;ldr\\t%0, [%0, %L1]\"); + adr\\t%x0, %c1 + adrp\\t%x0, %A1 + fmov\\t%d0, %x1 +@@ -6857,7 +6889,10 @@ + (lo_sum:P (match_operand:P 1 "register_operand" "r") + (match_operand 2 "aarch64_valid_symref" "S")))] + "" +- "add\\t%0, %1, :lo12:%c2" ++ { return TARGET_MACHO ++ ? "add\\t%0, %1, %K2;momd" ++ : "add\\t%0, %1, :lo12:%c2"; ++ } + [(set_attr "type" "alu_imm")] + ) + +diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt +index 92220b26ee2..15ec719ca2d 100644 +--- a/gcc/config/aarch64/aarch64.opt ++++ b/gcc/config/aarch64/aarch64.opt +@@ -152,6 +152,13 @@ Enum(aarch64_abi) String(ilp32) Value(AARCH64_ABI_ILP32) + EnumValue + Enum(aarch64_abi) String(lp64) Value(AARCH64_ABI_LP64) + ++EnumValue ++Enum(aarch64_abi) String(darwinpcs) Value(AARCH64_ABI_LP64) ++ ++m64 ++Target RejectNegative Alias(mabi=, darwinpcs) ++On Darwin for compatibility with other platform variants. ++ + mpc-relative-literal-loads + Target Save Var(pcrelative_literal_loads) Init(2) Save + PC relative literal loads. +diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md +index ee7587cca16..cb73a2daae8 100644 +--- a/gcc/config/aarch64/constraints.md ++++ b/gcc/config/aarch64/constraints.md +@@ -158,7 +158,9 @@ + A constraint that matches a small GOT access." + (and (match_code "const,symbol_ref") + (match_test "aarch64_classify_symbolic_expression (op) +- == SYMBOL_SMALL_GOT_4G"))) ++ == SYMBOL_SMALL_GOT_4G ++ || aarch64_classify_symbolic_expression (op) ++ == SYMBOL_MO_SMALL_GOT"))) + + (define_constraint "Uss" + "@internal +@@ -490,6 +492,11 @@ + An address valid for a prefetch instruction." + (match_test "aarch64_address_valid_for_prefetch_p (op, true)")) + ++(define_address_constraint "Du" ++ "@internal ++ An address valid for a prefetch instruction with an unscaled offset." ++ (match_test "aarch64_address_valid_for_unscaled_prefetch_p (op, true)")) ++ + (define_constraint "vgb" + "@internal + A constraint that matches an immediate offset valid for SVE LD1B +diff --git a/gcc/config/aarch64/darwin.h b/gcc/config/aarch64/darwin.h +new file mode 100644 +index 00000000000..2a855c11efa +--- /dev/null ++++ b/gcc/config/aarch64/darwin.h +@@ -0,0 +1,280 @@ ++/* Target definitions for Arm64/Aarch64 running on macOS/iOS. ++ ++Copyright The GNU Toolchain Authors. ++Contributed by Iain Sandoe. ++ ++This file is part of GCC. ++ ++GCC 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 3, or (at your option) ++any later version. ++ ++GCC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GCC; see the file COPYING3. If not see ++. */ ++ ++/* Enable Mach-O bits in generic Aarch64 code. */ ++#undef TARGET_MACHO ++#define TARGET_MACHO 1 ++ ++#undef DARWIN_ARM64 ++#define DARWIN_ARM64 1 ++ ++/* FIXME FIXME FIXME - these are mostly guesses right now. */ ++ ++/* FIXME: this is only used in generic code in darwin.c. */ ++#undef TARGET_64BIT ++#define TARGET_64BIT 1 ++ ++#undef PTRDIFF_TYPE ++#define PTRDIFF_TYPE "long int" ++ ++/* NOTE that arm64_32 is a valid thing and corresponds to darwinpcs ++ and TARGET_ILP32, but we are not implementing that for now. */ ++#define TARGET_OS_CPP_BUILTINS() \ ++ do { \ ++ builtin_define ("__LITTLE_ENDIAN__"); \ ++ builtin_define ("__arm64"); \ ++ builtin_define ("__arm64__"); \ ++ darwin_cpp_builtins (pfile); \ ++ } while (0) ++ ++/* In Darwin's arm64 ABI, chars are signed, for consistency with other Darwin ++ architectures. */ ++ ++#undef DEFAULT_SIGNED_CHAR ++#define DEFAULT_SIGNED_CHAR 1 ++ ++#undef LONG_DOUBLE_TYPE_SIZE ++#define LONG_DOUBLE_TYPE_SIZE 64 ++ ++/* Disable custom function descriptors on Darwin, it breaks ABI. */ ++#undef AARCH64_CUSTOM_FUNCTION_TEST ++#define AARCH64_CUSTOM_FUNCTION_TEST 0 ++ ++/* Non-PIE executables are forbidden by the aarch64-darwin security model; ++ remove the option from link-lines since they just produce a warning from ++ ld64 and are then ignored anyway. */ ++#undef DARWIN_NOPIE_SPEC ++#define DARWIN_NOPIE_SPEC \ ++" %insn); +diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md +index c308015ac2c..cd88f93ca2d 100644 +--- a/gcc/config/aarch64/predicates.md ++++ b/gcc/config/aarch64/predicates.md +@@ -261,9 +261,24 @@ + (define_predicate "aarch64_prefetch_operand" + (match_test "aarch64_address_valid_for_prefetch_p (op, false)")) + ++(define_predicate "aarch64_unscaled_prefetch_operand" ++ (match_test "aarch64_address_valid_for_unscaled_prefetch_p (op, false)")) ++ + (define_predicate "aarch64_valid_symref" + (match_code "const, symbol_ref, label_ref") + { ++ if (TARGET_MACHO) ++ { ++ rtx x = op; ++ rtx offset; ++ split_const (x, &x, &offset); ++ if (GET_CODE (x) == CONST) ++ x = XEXP (x, 0); ++ if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_SALT_ADDR) ++ x = XVECEXP (x, 0, 0); ++ if (SYMBOL_REF_P (x) && INTVAL (offset) < 0) ++ return false; ++ } + return (aarch64_classify_symbolic_expression (op) + != SYMBOL_FORCE_TO_MEM); + }) +diff --git a/gcc/config/aarch64/t-aarch64-darwin b/gcc/config/aarch64/t-aarch64-darwin +new file mode 100644 +index 00000000000..a8bfcffad78 +--- /dev/null ++++ b/gcc/config/aarch64/t-aarch64-darwin +@@ -0,0 +1,25 @@ ++# Machine description for AArch64 architecture. ++# Copyright (C) 2020 Free Software Foundation, Inc. ++# ++# This file is part of GCC. ++# ++# GCC 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 3, or (at your option) ++# any later version. ++# ++# GCC is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GCC; see the file COPYING3. If not see ++# . ++ ++LIB1ASMSRC = aarch64/lib1funcs.asm ++LIB1ASMFUNCS = _aarch64_sync_cache_range ++ ++# FIXME - figure out what multilib provisions we should make for ++# a) arm64e ++# b) arm64_32 +diff --git a/gcc/config/darwin-driver.cc b/gcc/config/darwin-driver.cc +index 00287f3d5ec..6df85f57bb4 100644 +--- a/gcc/config/darwin-driver.cc ++++ b/gcc/config/darwin-driver.cc +@@ -268,14 +268,21 @@ darwin_driver_init (unsigned int *decoded_options_count, + bool seenX86_64 = false; + bool seenPPC = false; + bool seenPPC64 = false; ++#if !DARWIN_ARM64 ++ bool seenArm64 = false; + bool seenM32 = false; + bool seenM64 = false; + bool appendM32 = false; + bool appendM64 = false; ++#endif + const char *vers_string = NULL; + bool seen_version_min = false; + bool seen_sysroot_p = false; + bool noexport_p = true; ++#ifdef RPATH_SETS_NODEFAULT ++ bool seen_rpath_p = false; ++ bool seen_nodefaultrpaths_p = false; ++#endif + + for (i = 1; i < *decoded_options_count; i++) + { +@@ -296,6 +303,12 @@ darwin_driver_init (unsigned int *decoded_options_count, + seenPPC = true; + else if (!strcmp ((*decoded_options)[i].arg, "ppc64")) + seenPPC64 = true; ++ else if (!strcmp ((*decoded_options)[i].arg, "arm64")) ++#if !DARWIN_ARM64 ++ seenArm64 = true; ++#else ++ ; /* We accept the option, but don't need to act on it. */ ++#endif + else + error ("this compiler does not support %qs", + (*decoded_options)[i].arg); +@@ -309,7 +322,7 @@ darwin_driver_init (unsigned int *decoded_options_count, + --i; + --*decoded_options_count; + break; +- ++#if !DARWIN_ARM64 + case OPT_m32: + seenM32 = true; + break; +@@ -317,6 +330,7 @@ darwin_driver_init (unsigned int *decoded_options_count, + case OPT_m64: + seenM64 = true; + break; ++#endif + + case OPT_mmacosx_version_min_: + seen_version_min = true; +@@ -349,8 +363,16 @@ darwin_driver_init (unsigned int *decoded_options_count, + gcc_checking_assert ((*decoded_options)[i].arg); + if (startswith ((*decoded_options)[i].arg, "-exported_symbol")) + noexport_p = false; ++#ifdef RPATH_SETS_NODEFAULT ++ else if (strncmp ((*decoded_options)[i].arg, "-rpath", 6) == 0) ++ seen_rpath_p = true; ++#endif + break; + ++#ifdef RPATH_SETS_NODEFAULT ++ case OPT_nodefaultrpaths: ++ seen_nodefaultrpaths_p = true; ++#endif + default: + break; + } +@@ -366,6 +388,9 @@ darwin_driver_init (unsigned int *decoded_options_count, + if (seenPPC || seenPPC64) + warning (0, "this compiler does not support PowerPC" + " (%<-arch%> option ignored)"); ++ else if (seenArm64) ++ warning (0, "this compiler does not support Arm64" ++ " (%<-arch%> option ignored)"); + if (seenX86) + { + if (seenX86_64 || seenM64) +@@ -389,6 +414,9 @@ darwin_driver_init (unsigned int *decoded_options_count, + if (seenX86 || seenX86_64) + warning (0, "this compiler does not support x86" + " (%<-arch%> option ignored)"); ++ else if (seenArm64) ++ warning (0, "this compiler does not support Arm64" ++ " (%<-arch%> option ignored)"); + if (seenPPC) + { + if (seenPPC64 || seenM64) +@@ -408,12 +436,20 @@ darwin_driver_init (unsigned int *decoded_options_count, + if (! seenM64) /* Add -m64 if the User didn't. */ + appendM64 = true; + } ++#elif DARWIN_ARM64 ++ if (seenPPC || seenPPC64) ++ warning (0, "this compiler does not support PowerPC" ++ " (%<-arch%> option ignored)"); ++ if (seenX86 || seenX86_64) ++ warning (0, "this compiler does not support x86" ++ " (%<-arch%> option ignored)"); + #endif + + /* If there is nothing else on the command line, do not add sysroot etc. */ + if (*decoded_options_count <= 1) + return; + ++#if !DARWIN_ARM64 + if (appendM32 || appendM64) + { + ++*decoded_options_count; +@@ -423,6 +459,7 @@ darwin_driver_init (unsigned int *decoded_options_count, + generate_option (appendM32 ? OPT_m32 : OPT_m64, NULL, 1, CL_DRIVER, + &(*decoded_options)[*decoded_options_count - 1]); + } ++#endif + + if (!seen_sysroot_p) + { +@@ -490,4 +527,16 @@ darwin_driver_init (unsigned int *decoded_options_count, + generate_option (OPT_nodefaultexport, NULL, 1, CL_DRIVER, + &(*decoded_options)[*decoded_options_count - 1]); + } ++ ++#ifdef RPATH_SETS_NODEFAULT ++ if (seen_rpath_p && !seen_nodefaultrpaths_p) ++ { ++ ++*decoded_options_count; ++ *decoded_options = XRESIZEVEC (struct cl_decoded_option, ++ *decoded_options, ++ *decoded_options_count); ++ generate_option (OPT_nodefaultrpaths, NULL, 1, CL_DRIVER, ++ &(*decoded_options)[*decoded_options_count - 1]); ++ } ++#endif + } +diff --git a/gcc/config/darwin.cc b/gcc/config/darwin.cc +index f065a13d73d..7cd684c6abe 100644 +--- a/gcc/config/darwin.cc ++++ b/gcc/config/darwin.cc +@@ -118,7 +118,7 @@ static bool ld_init_term_start_labels = false; + section * darwin_sections[NUM_DARWIN_SECTIONS]; + + /* While we transition to using in-tests instead of ifdef'd code. */ +-#if !HAVE_lo_sum ++#if !HAVE_lo_sum || DARWIN_ARM64 + #define gen_macho_high(m,a,b) (a) + #define gen_macho_low(m,a,b,c) (a) + #endif +@@ -1052,6 +1052,7 @@ machopic_legitimize_pic_address (rtx orig, machine_mode mode, rtx reg) + return pic_ref; + } + ++#if !DARWIN_ARM64 + /* Callbacks to output the stub or non-lazy pointers. + Each works on the item in *SLOT,if it has been used. + DATA is the FILE* for assembly output. +@@ -1207,6 +1208,7 @@ machopic_finish (FILE *out_file) + machopic_indirections->traverse_noresize + (out_file); + } ++#endif + + int + machopic_operand_p (rtx op) +@@ -1936,6 +1938,8 @@ darwin_label_is_anonymous_local_objc_name (const char *name) + } + else if (startswith ((const char *)p, "ClassMethods")) + return false; ++ else if (startswith ((const char *)p, "ClassProtocols")) ++ return false; + else if (startswith ((const char *)p, "Instance")) + { + if (p[8] == 'I' || p[8] == 'M') +@@ -2238,6 +2242,8 @@ darwin_emit_except_table_label (FILE *file) + rtx + darwin_make_eh_symbol_indirect (rtx orig, bool ARG_UNUSED (pubvis)) + { ++ if (DARWIN_ARM64) ++ return orig; + if (DARWIN_PPC == 0 && TARGET_64BIT) + return orig; + +@@ -3058,7 +3064,12 @@ darwin_file_end (void) + fprintf (asm_out_file, "\t.long\t0\n\t.long\t%u\n", flags); + } + ++#if !DARWIN_ARM64 + machopic_finish (asm_out_file); ++#else ++ gcc_checking_assert (!machopic_indirections); ++#endif ++ + if (flag_apple_kext) + { + /* These sections are only used for kernel code. */ +diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h +index 51e257dc698..13ba6e61474 100644 +--- a/gcc/config/darwin.h ++++ b/gcc/config/darwin.h +@@ -42,6 +42,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + + #define DARWIN_X86 0 + #define DARWIN_PPC 0 ++#define DARWIN_ARM64 0 + + #define OBJECT_FORMAT_MACHO 1 + +@@ -296,6 +297,31 @@ extern GTY(()) int darwin_ms_struct; + #define DARWIN_CC1_SPEC \ + "% 10.11 mmacosx-version-min= -lgcc_s.1.1) \ ++ %:version-compare(>= 10.11 mmacosx-version-min= -lemutls_w) " ++#endif ++ ++/* We might elect to add a path even when this compiler does not use embedded ++ run paths, so that we can use libraries from an alternate compiler that is ++ using embedded runpaths. */ ++#if DARWIN_DO_EXTRA_RPATH ++# define DARWIN_EXTRA_RPATH \ ++"%{!r:%{!nostdlib:%{!nodefaultrpaths:\ ++ %:version-compare(>= 10.5 mmacosx-version-min= -rpath) \ ++ %:version-compare(>= 10.5 mmacosx-version-min= " DARWIN_ADD_RPATH ") \ ++ }}}" ++#else ++# define DARWIN_EXTRA_RPATH "" ++#endif ++ + #define SUBSUBTARGET_OVERRIDE_OPTIONS \ + do { \ + darwin_override_options (); \ +@@ -387,7 +413,9 @@ extern GTY(()) int darwin_ms_struct; + DARWIN_NOPIE_SPEC \ + DARWIN_RDYNAMIC \ + DARWIN_NOCOMPACT_UNWIND \ +- "}}}}}}} %= 10.6, the unwinder *still* comes from libSystem and +- we find the emutls impl from lemutls_w. In either case, the builtins etc. +- are linked from -lgcc. +- +- When we have specified shared-libgcc or any case that might require +- exceptions, we pull the libgcc content (including emulated tls) from +- -lgcc_s.1 in GCC and the unwinder from /usr/lib/libgcc_s.1 for < 10.6 and +- libSystem for >= 10.6 respectively. +- Otherwise, we just link the emutls/builtins from convenience libs. +- +- If we need exceptions, prior to 10.3.9, then we have to link the static +- eh lib, since there's no shared version on the system. +- +- In all cases, libgcc_s.1 will be installed with the compiler, or any app +- built using it, so we can link the builtins and emutls shared on all. +- + We have to work around that DYLD_XXXX are disabled in macOS 10.11+ which + means that any bootstrap trying to use a shared libgcc with a bumped SO- + name will fail. This means that we do not accept shared libgcc for these +- versions. ++ versions, unless we have embedded run paths enabled, in which case the ++ compiler will add the appropriate path to find the library. ++ ++ For -static-libgcc: < 10.6, use the unwinder in libgcc_eh (and find ++ the emultls impl. there too). + + For -static-libgcc: >= 10.6, the unwinder *still* comes from libSystem and + we find the emutls impl from lemutls_w. In either case, the builtins etc. + are linked from -lgcc. +-> ++ + Otherwise, we just link the shared version of gcc_s.1.1 and pick up + exceptions: + * Prior to 10.3.9, then we have to link the static eh lib, since there +@@ -502,6 +515,10 @@ extern GTY(()) int darwin_ms_struct; + + In all cases, libgcc_s.1.1 will be installed with the compiler, or any app + built using it, so we can link the builtins and emutls shared on all. ++ ++ On most Darwin systems (other than Arm64) we will also install a legacy ++ support libgcc_s.1.dylib to support executables linked with libgcc_ext by ++ earlier GCC versions. + */ + #undef REAL_LIBGCC_SPEC + #define REAL_LIBGCC_SPEC \ +@@ -509,8 +526,7 @@ extern GTY(()) int darwin_ms_struct; + %:version-compare(!> 10.6 mmacosx-version-min= -lgcc_eh) \ + %:version-compare(>= 10.6 mmacosx-version-min= -lemutls_w); \ + shared-libgcc|fexceptions|fobjc-exceptions|fgnu-runtime: \ +- %:version-compare(!> 10.11 mmacosx-version-min= -lgcc_s.1.1) \ +- %:version-compare(>= 10.11 mmacosx-version-min= -lemutls_w) \ ++ " DARWIN_SHARED_LIBGCC " \ + %:version-compare(!> 10.3.9 mmacosx-version-min= -lgcc_eh) \ + %:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_s.10.4) \ + %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5); \ +@@ -545,7 +561,8 @@ extern GTY(()) int darwin_ms_struct; + { "darwin_crt2", DARWIN_CRT2_SPEC }, \ + { "darwin_crt3", DARWIN_CRT3_SPEC }, \ + { "darwin_dylib1", DARWIN_DYLIB1_SPEC }, \ +- { "darwin_bundle1", DARWIN_BUNDLE1_SPEC }, ++ { "darwin_bundle1", DARWIN_BUNDLE1_SPEC }, \ ++ { "darwin_rpaths", DARWIN_RPATH_SPEC }, + + #define DARWIN_CRT1_SPEC \ + "%:version-compare(!> 10.5 mmacosx-version-min= -lcrt1.o) \ +@@ -571,6 +588,17 @@ extern GTY(()) int darwin_ms_struct; + "%{!static:%:version-compare(< 10.6 mmacosx-version-min= -lbundle1.o) \ + %{fgnu-tm: -lcrttms.o}}" + ++#if DARWIN_AT_RPATH ++/* A default rpath, that picks up dependent libraries installed in the same ++ director as one being loaded. */ ++#define DARWIN_RPATH_SPEC \ ++ "%:version-compare(>= 10.5 mmacosx-version-min= -rpath) \ ++ %:version-compare(>= 10.5 mmacosx-version-min= @loader_path) \ ++ %P " ++#else ++#define DARWIN_RPATH_SPEC "" ++#endif ++ + #ifdef HAVE_AS_MMACOSX_VERSION_MIN_OPTION + /* Emit macosx version (but only major). */ + #define ASM_MMACOSX_VERSION_MIN_SPEC \ +diff --git a/gcc/config/darwin.opt b/gcc/config/darwin.opt +index cc7d14c2e4d..b1cb8464d57 100644 +--- a/gcc/config/darwin.opt ++++ b/gcc/config/darwin.opt +@@ -237,6 +237,10 @@ nodefaultexport + Driver RejectNegative + Do not add a default symbol exports to modules or dynamic libraries. + ++nodefaultrpaths ++Driver RejectNegative ++Do not add default run paths (for the compiler library directories) to executables, modules or dynamic libraries. ++ + nofixprebinding + Driver RejectNegative + (Obsolete after 10.3.9) Set MH_NOPREFIXBINDING, in an executable. +diff --git a/gcc/config/i386/darwin.h b/gcc/config/i386/darwin.h +index a55f6b2b874..36a32867281 100644 +--- a/gcc/config/i386/darwin.h ++++ b/gcc/config/i386/darwin.h +@@ -308,3 +308,10 @@ along with GCC; see the file COPYING3. If not see + #define CLEAR_INSN_CACHE(beg, end) \ + extern void sys_icache_invalidate(void *start, size_t len); \ + sys_icache_invalidate ((beg), (size_t)((end)-(beg))) ++ ++/* Disable custom function descriptors for Darwin when we have off-stack ++ trampolines. */ ++#undef X86_CUSTOM_FUNCTION_TEST ++#define X86_CUSTOM_FUNCTION_TEST \ ++ (!flag_off_stack_trampolines && !flag_trampolines) ? 1 : 0 ++ +diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc +index 9dd9fa68722..5cd4b5c0592 100644 +--- a/gcc/config/i386/i386.cc ++++ b/gcc/config/i386/i386.cc +@@ -24698,7 +24698,7 @@ ix86_libgcc_floating_mode_supported_p + #define TARGET_HARD_REGNO_SCRATCH_OK ix86_hard_regno_scratch_ok + + #undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS +-#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1 ++#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS X86_CUSTOM_FUNCTION_TEST + + #undef TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID + #define TARGET_ADDR_SPACE_ZERO_ADDRESS_VALID ix86_addr_space_zero_address_valid +diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h +index 363082ba47b..5f56d7abf65 100644 +--- a/gcc/config/i386/i386.h ++++ b/gcc/config/i386/i386.h +@@ -746,6 +746,12 @@ extern const char *host_detect_local_cpu (int argc, const char **argv); + /* Minimum allocation boundary for the code of a function. */ + #define FUNCTION_BOUNDARY 8 + ++/* We will and with this value to test if a custom function descriptor needs ++ a static chain. The function boundary must the adjusted so that the bit ++ this represents is no longer part of the address. 0 Disables the custom ++ function descriptors. */ ++#define X86_CUSTOM_FUNCTION_TEST 1 ++ + /* C++ stores the virtual bit in the lowest bit of function pointers. */ + #define TARGET_PTRMEMFUNC_VBIT_LOCATION ptrmemfunc_vbit_in_pfn + +diff --git a/gcc/configure b/gcc/configure +index 5ce0557719a..dbc127c59cb 100755 +--- a/gcc/configure ++++ b/gcc/configure +@@ -634,6 +634,7 @@ LIBOBJS + CET_HOST_FLAGS + NO_PIE_FLAG + NO_PIE_CFLAGS ++enable_pie_tools + enable_default_pie + PICFLAG + enable_host_shared +@@ -740,6 +741,8 @@ ORIGINAL_PLUGIN_LD_FOR_TARGET + gcc_cv_ld + ORIGINAL_AS_FOR_TARGET + gcc_cv_as ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_fast_install + objdir + OTOOL64 +@@ -1000,6 +1003,8 @@ enable_static + with_pic + enable_fast_install + enable_libtool_lock ++enable_darwin_at_rpath ++with_darwin_extra_rpath + enable_ld + enable_gold + with_plugin_ld +@@ -1030,6 +1035,7 @@ with_linker_hash_style + with_diagnostics_color + with_diagnostics_urls + enable_default_pie ++enable_pie_tools + enable_cet + enable_s390_excess_float_precision + ' +@@ -1733,6 +1739,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-ld[=ARG] build ld [ARG={default,yes,no}] + --enable-gold[=ARG] build gold [ARG={default,yes,no}] + --enable-gnu-indirect-function +@@ -1790,6 +1798,8 @@ Optional Features: + --disable-libquadmath-support + disable libquadmath support for Fortran + --enable-default-pie enable Position Independent Executable as default ++ --enable-pie-tools build Position Independent Executables for the ++ compilers and other tools + --enable-cet enable Intel CET in host libraries [default=auto] + --enable-s390-excess-float-precision + on s390 targets, evaluate float with double +@@ -1850,6 +1860,9 @@ Optional Packages: + --with-pic try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] ++ --with-darwin-extra-rpath=[ARG] ++ Specify a runpath directory, additional to those ++ provided by the compiler + --with-plugin-ld=[ARG] specify the plugin linker + --with-glibc-version=M.N + assume GCC used with glibc version M.N or later +@@ -3766,15 +3779,24 @@ if test x${gcc_gxx_libcxx_include_dir} != x; then + $as_echo "#define ENABLE_STDLIB_OPTION 1" >>confdefs.h + + else +- $as_echo "#define ENABLE_STDLIB_OPTION 0" >>confdefs.h ++ case $target in ++ *-darwin1[1-9]* | *-darwin2*) ++ # Default this on for Darwin versions which default to libcxx. ++ $as_echo "#define ENABLE_STDLIB_OPTION 1" >>confdefs.h + ++ ;; ++ *) ++ $as_echo "#define ENABLE_STDLIB_OPTION 0" >>confdefs.h ++ ++ ;; ++ esac + fi +-# ??? This logic must match libstdc++-v3/acinclude.m4:GLIBCXX_EXPORT_INSTALL_INFO. ++ + if test x${gcc_gxx_libcxx_include_dir} = x; then ++ libcxx_incdir='include/c++/v1' + if test x${enable_version_specific_runtime_libs} = xyes; then +- gcc_gxx_libcxx_include_dir='${libsubdir}/libc++_include/c++/v1' ++ gcc_gxx_libcxx_include_dir='${libsubdir}/$libcxx_incdir' + else +- libcxx_incdir='libc++_include/c++/$(version)/v1' + if test x$host != x$target; then + libcxx_incdir="$target_alias/$libcxx_incdir" + fi +@@ -17867,6 +17889,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -17884,10 +17947,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -19673,7 +19745,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 19676 "configure" ++#line 19748 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -19779,7 +19851,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 19782 "configure" ++#line 19854 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -20655,6 +20727,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes +@@ -20672,12 +20785,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + if test "$lt_cv_apple_cc_single_mod" != "yes"; then +- archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring${_lt_dsymutil}" ++ else ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ fi + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + +@@ -23028,6 +23154,35 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ ++DARWIN_DO_EXTRA_RPATH=0 ++ ++# Check whether --with-darwin-extra-rpath was given. ++if test "${with_darwin_extra_rpath+set}" = set; then : ++ withval=$with_darwin_extra_rpath; if test x"$withval" != x; then ++ DARWIN_ADD_RPATH="$withval" ++ DARWIN_DO_EXTRA_RPATH=1 ++ fi ++fi ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define DARWIN_DO_EXTRA_RPATH $DARWIN_DO_EXTRA_RPATH ++_ACEOF ++ ++ ++cat >>confdefs.h <<_ACEOF ++#define DARWIN_ADD_RPATH "$DARWIN_ADD_RPATH" ++_ACEOF ++ ++ + # Identify the assembler which will work hand-in-glove with the newly + # built GCC, so that we can examine its features. This is the assembler + # which will be driven by the driver program. +@@ -32429,6 +32584,22 @@ $as_echo "#define ENABLE_DEFAULT_PIE 1" >>confdefs.h + fi + + ++# Check whether --enable-pie-tools was given; this is passed automatically ++# from the top level where it has already been validated. ++# Check whether --enable-pie-tools was given. ++if test "${enable_pie_tools+set}" = set; then : ++ enableval=$enable_pie_tools; enable_pie_tools=$enableval ++else ++ enable_pie_tools=no ++fi ++ ++if test x$enable_pie_tools = xyes ; then ++ ++$as_echo "#define ENABLE_PIE_TOOLS 1" >>confdefs.h ++ ++fi ++ ++ + # Check if -fno-PIE works. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fno-PIE option" >&5 + $as_echo_n "checking for -fno-PIE option... " >&6; } +@@ -32966,6 +33137,10 @@ LTLIBOBJS=$ac_ltlibobjs + + + ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + + : "${CONFIG_STATUS=./config.status}" + ac_write_fail=0 +diff --git a/gcc/configure.ac b/gcc/configure.ac +index 23bee7010a3..2d9159989e4 100644 +--- a/gcc/configure.ac ++++ b/gcc/configure.ac +@@ -249,14 +249,22 @@ if test x${gcc_gxx_libcxx_include_dir} != x; then + AC_DEFINE(ENABLE_STDLIB_OPTION, 1, + [Define if the -stdlib= option should be enabled.]) + else +- AC_DEFINE(ENABLE_STDLIB_OPTION, 0) ++ case $target in ++ *-darwin1[[1-9]]* | *-darwin2*) ++ # Default this on for Darwin versions which default to libcxx. ++ AC_DEFINE(ENABLE_STDLIB_OPTION, 1) ++ ;; ++ *) ++ AC_DEFINE(ENABLE_STDLIB_OPTION, 0) ++ ;; ++ esac + fi +-# ??? This logic must match libstdc++-v3/acinclude.m4:GLIBCXX_EXPORT_INSTALL_INFO. ++ + if test x${gcc_gxx_libcxx_include_dir} = x; then ++ libcxx_incdir='include/c++/v1' + if test x${enable_version_specific_runtime_libs} = xyes; then +- gcc_gxx_libcxx_include_dir='${libsubdir}/libc++_include/c++/v1' ++ gcc_gxx_libcxx_include_dir='${libsubdir}/$libcxx_incdir' + else +- libcxx_incdir='libc++_include/c++/$(version)/v1' + if test x$host != x$target; then + libcxx_incdir="$target_alias/$libcxx_incdir" + fi +@@ -2559,6 +2567,21 @@ AC_PROG_LIBTOOL + AC_SUBST(objdir) + AC_SUBST(enable_fast_install) + ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) ++DARWIN_DO_EXTRA_RPATH=0 ++AC_ARG_WITH(darwin-extra-rpath, ++[AS_HELP_STRING( ++ [[--with-darwin-extra-rpath=[ARG]]], ++ [Specify a runpath directory, additional to those provided by the compiler])], ++[if test x"$withval" != x; then ++ DARWIN_ADD_RPATH="$withval" ++ DARWIN_DO_EXTRA_RPATH=1 ++ fi]) ++AC_DEFINE_UNQUOTED(DARWIN_DO_EXTRA_RPATH, $DARWIN_DO_EXTRA_RPATH, ++ [Should add an extra runpath directory]) ++AC_DEFINE_UNQUOTED(DARWIN_ADD_RPATH, "$DARWIN_ADD_RPATH", ++ [Specify a runpath directory, additional to those provided by the compiler]) ++ + # Identify the assembler which will work hand-in-glove with the newly + # built GCC, so that we can examine its features. This is the assembler + # which will be driven by the driver program. +@@ -7646,6 +7669,19 @@ if test x$enable_default_pie = xyes ; then + fi + AC_SUBST([enable_default_pie]) + ++# Check whether --enable-pie-tools was given; this is passed automatically ++# from the top level where it has already been validated. ++AC_ARG_ENABLE(pie-tools, ++[AS_HELP_STRING([--enable-pie-tools], ++ [build Position Independent Executables for the compilers and other tools])], ++[enable_pie_tools=$enableval], ++[enable_pie_tools=no]) ++if test x$enable_pie_tools = xyes ; then ++ AC_DEFINE(ENABLE_PIE_TOOLS, 1, ++ [Define if you build Position Independent Executables for the compilers and other tools.]) ++fi ++AC_SUBST([enable_pie_tools]) ++ + # Check if -fno-PIE works. + AC_CACHE_CHECK([for -fno-PIE option], + [gcc_cv_c_no_fpie], +diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc +index d7e9980ff1e..ff2a1f6665f 100644 +--- a/gcc/cp/decl2.cc ++++ b/gcc/cp/decl2.cc +@@ -3653,9 +3653,8 @@ get_tls_init_fn (tree var) + if (!flag_extern_tls_init && DECL_EXTERNAL (var)) + return NULL_TREE; + +- /* If the variable is internal, or if we can't generate aliases, +- call the local init function directly. */ +- if (!TREE_PUBLIC (var) || !TARGET_SUPPORTS_ALIASES) ++ /* If the variable is internal call the local init function directly. */ ++ if (!TREE_PUBLIC (var)) + return get_local_tls_init_fn (DECL_SOURCE_LOCATION (var)); + + tree sname = mangle_tls_init_fn (var); +@@ -4801,22 +4800,24 @@ handle_tls_init (void) + finish_expr_stmt (cp_build_modify_expr (loc, guard, NOP_EXPR, + boolean_true_node, + tf_warning_or_error)); ++ auto_vec direct_calls; + for (; vars; vars = TREE_CHAIN (vars)) + { + tree var = TREE_VALUE (vars); + tree init = TREE_PURPOSE (vars); + one_static_initialization_or_destruction (var, init, true); + +- /* Output init aliases even with -fno-extern-tls-init. */ +- if (TARGET_SUPPORTS_ALIASES && TREE_PUBLIC (var)) ++ /* Output inits even with -fno-extern-tls-init. ++ We save the list here and output either an alias or a stub function ++ below. */ ++ if (TREE_PUBLIC (var)) + { +- tree single_init_fn = get_tls_init_fn (var); ++ tree single_init_fn = get_tls_init_fn (var); + if (single_init_fn == NULL_TREE) + continue; +- cgraph_node *alias +- = cgraph_node::get_create (fn)->create_same_body_alias +- (single_init_fn, fn); +- gcc_assert (alias != NULL); ++ if (single_init_fn == fn) ++ continue; ++ direct_calls.safe_push (single_init_fn); + } + } + +@@ -4824,6 +4825,30 @@ handle_tls_init (void) + finish_if_stmt (if_stmt); + finish_function_body (body); + expand_or_defer_fn (finish_function (/*inline_p=*/false)); ++ ++ /* For each TLS var that we have an init function, we either emit an alias ++ between that and the tls_init, or a stub function that just calls the ++ tls_init. */ ++ while (!direct_calls.is_empty()) ++ { ++ tree single_init_fn = direct_calls.pop (); ++ if (TARGET_SUPPORTS_ALIASES) ++ { ++ cgraph_node *alias ++ = cgraph_node::get_create (fn)->create_same_body_alias ++ (single_init_fn, fn); ++ gcc_assert (alias != NULL); ++ } ++ else ++ { ++ start_preparsed_function (single_init_fn, NULL_TREE, SF_PRE_PARSED); ++ tree body = begin_function_body (); ++ tree r = build_call_expr (fn, 0); ++ finish_expr_stmt (r); ++ finish_function_body (body); ++ expand_or_defer_fn (finish_function (/*inline_p=*/false)); ++ } ++ } + } + + /* We're at the end of compilation, so generate any mangling aliases that +diff --git a/gcc/cp/g++spec.cc b/gcc/cp/g++spec.cc +index 8174d652776..2e1e06e6ac9 100644 +--- a/gcc/cp/g++spec.cc ++++ b/gcc/cp/g++spec.cc +@@ -222,7 +222,12 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options, + + case OPT_static_libstdc__: + library = library >= 0 ? 2 : library; ++#ifdef HAVE_LD_STATIC_DYNAMIC ++ /* Remove -static-libstdc++ from the command only if target supports ++ LD_STATIC_DYNAMIC. When not supported, it is left in so that a ++ back-end target can use outfile substitution. */ + args[i] |= SKIPOPT; ++#endif + break; + + case OPT_stdlib_: +diff --git a/gcc/cumulative-args.h b/gcc/cumulative-args.h +new file mode 100644 +index 00000000000..b60928e37f9 +--- /dev/null ++++ b/gcc/cumulative-args.h +@@ -0,0 +1,20 @@ ++#ifndef GCC_CUMULATIVE_ARGS_H ++#define GCC_CUMULATIVE_ARGS_H ++ ++#if CHECKING_P ++ ++struct cumulative_args_t { void *magic; void *p; }; ++ ++#else /* !CHECKING_P */ ++ ++/* When using a GCC build compiler, we could use ++ __attribute__((transparent_union)) to get cumulative_args_t function ++ arguments passed like scalars where the ABI would mandate a less ++ efficient way of argument passing otherwise. However, that would come ++ at the cost of less type-safe !CHECKING_P compilation. */ ++ ++union cumulative_args_t { void *p; }; ++ ++#endif /* !CHECKING_P */ ++ ++#endif /* GCC_CUMULATIVE_ARGS_H */ +diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi +index ff6c338bedb..55c8ba8969f 100644 +--- a/gcc/doc/invoke.texi ++++ b/gcc/doc/invoke.texi +@@ -670,6 +670,7 @@ Objective-C and Objective-C++ Dialects}. + @gccoptlist{-fcall-saved-@var{reg} -fcall-used-@var{reg} @gol + -ffixed-@var{reg} -fexceptions @gol + -fnon-call-exceptions -fdelete-dead-exceptions -funwind-tables @gol ++-foff-stack-trampolines @gol + -fasynchronous-unwind-tables @gol + -fno-gnu-unique @gol + -finhibit-size-directive -fcommon -fno-ident @gol +@@ -680,6 +681,7 @@ Objective-C and Objective-C++ Dialects}. + -fverbose-asm -fpack-struct[=@var{n}] @gol + -fleading-underscore -ftls-model=@var{model} @gol + -fstack-reuse=@var{reuse_level} @gol ++-fstack-use-cumulative-args @gol + -ftrampolines -ftrapv -fwrapv @gol + -fvisibility=@r{[}default@r{|}internal@r{|}hidden@r{|}protected@r{]} @gol + -fstrict-volatile-bitfields -fsync-libcalls} +@@ -17071,6 +17073,17 @@ the behavior of older compilers in which temporaries' stack space is + not reused, the aggressive stack reuse can lead to runtime errors. This + option is used to control the temporary stack reuse optimization. + ++@item -fstack-use-cumulative-args ++@opindex fstack_use_cumulative_args ++This option instructs the compiler to use the ++@code{cumulative_args_t}-based stack layout target hooks, ++@code{TARGET_FUNCTION_ARG_BOUNDARY_CA} and ++@code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA}. If a given target does ++not define these hooks, the default behaviour is to fallback to using ++the standard non-@code{_CA} variants instead. Certain targets (such as ++AArch64 Darwin) require using the more advanced @code{_CA}-based ++hooks: For these targets this option should be enabled by default. ++ + @item -ftrapv + @opindex ftrapv + This option generates traps for signed overflow on addition, subtraction, +@@ -17129,6 +17142,19 @@ instructions. It does not allow exceptions to be thrown from + arbitrary signal handlers such as @code{SIGALRM}. This enables + @option{-fexceptions}. + ++@item -foff-stack-trampolines ++@opindex foff-stack-trampolines ++Certain platforms (such as the Apple M1) do not permit an executable ++stack. Generate calls to @code{__builtin_nested_func_ptr_created} and ++@code{__builtin_nested_func_ptr_deleted} in order to allocate and ++deallocate trampoline space on the executable heap. Please note that ++these functions are implemented in libgcc, and will not be compiled in ++unless you provide @option{--enable-off-stack-trampolines} when ++building gcc. @emph{PLEASE NOTE}: The trampolines are @emph{not} ++guaranteed to be correctly deallocated if you @code{setjmp}, ++instantiate nested functions, and then @code{longjmp} back to a state ++prior to having allocated those nested functions. ++ + @item -fdelete-dead-exceptions + @opindex fdelete-dead-exceptions + Consider that instructions that may throw exceptions but don't otherwise +diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi +index c5006afc00d..366360612e3 100644 +--- a/gcc/doc/tm.texi ++++ b/gcc/doc/tm.texi +@@ -4322,6 +4322,16 @@ with the specified mode and type. The default hook returns + @code{PARM_BOUNDARY} for all arguments. + @end deftypefn + ++@deftypefn {Target Hook} {unsigned int} TARGET_FUNCTION_ARG_BOUNDARY_CA (machine_mode @var{mode}, const_tree @var{type}, cumulative_args_t @var{ca}) ++This is the @code{cumulative_args_t}-based version of ++@code{TARGET_FUNCTION_ARG_BOUNDARY}. Define this hook if you need more ++fine-grained control over argument alignment, e.g. depending on whether ++it is a named argument or not, or any other criteria that you choose to ++place in the @var{ca} structure. ++ ++The default hook will call @code{TARGET_FUNCTION_ARG_BOUNDARY}. ++@end deftypefn ++ + @deftypefn {Target Hook} {unsigned int} TARGET_FUNCTION_ARG_ROUND_BOUNDARY (machine_mode @var{mode}, const_tree @var{type}) + Normally, the size of an argument is rounded up to @code{PARM_BOUNDARY}, + which is the default value for this hook. You can define this hook to +@@ -4329,6 +4339,16 @@ return a different value if an argument size must be rounded to a larger + value. + @end deftypefn + ++@deftypefn {Target Hook} {unsigned int} TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA (machine_mode @var{mode}, const_tree @var{type}, cumulative_args_t @var{ca}) ++This is the @code{cumulative_args_t}-based version of ++@code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}. Define this hook if you need more ++fine-grained control over argument size rounding, e.g. depending on whether ++it is a named argument or not, or any other criteria that you choose to ++place in the @var{ca} structure. ++ ++The default hook will call @code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}. ++@end deftypefn ++ + @defmac FUNCTION_ARG_REGNO_P (@var{regno}) + A C expression that is nonzero if @var{regno} is the number of a hard + register in which function arguments are sometimes passed. This does +diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in +index f869ddd5e5b..2c9f0f0bf14 100644 +--- a/gcc/doc/tm.texi.in ++++ b/gcc/doc/tm.texi.in +@@ -3330,8 +3330,12 @@ required. + + @hook TARGET_FUNCTION_ARG_BOUNDARY + ++@hook TARGET_FUNCTION_ARG_BOUNDARY_CA ++ + @hook TARGET_FUNCTION_ARG_ROUND_BOUNDARY + ++@hook TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA ++ + @defmac FUNCTION_ARG_REGNO_P (@var{regno}) + A C expression that is nonzero if @var{regno} is the number of a hard + register in which function arguments are sometimes passed. This does +diff --git a/gcc/function.cc b/gcc/function.cc +index ad0096a43ef..e5044a60741 100644 +--- a/gcc/function.cc ++++ b/gcc/function.cc +@@ -2445,7 +2445,10 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm, + else if (DECL_CHAIN (parm)) + data->arg.named = 1; /* Not the last non-variadic parm. */ + else if (targetm.calls.strict_argument_naming (all->args_so_far)) +- data->arg.named = 1; /* Only variadic ones are unnamed. */ ++ { ++ data->arg.named = 1; /* Only variadic ones are unnamed. */ ++ data->arg.last_named = 1; ++ } + else + data->arg.named = 0; /* Treat as variadic. */ + +@@ -2502,6 +2505,7 @@ assign_parms_setup_varargs (struct assign_parm_data_all *all, + + function_arg_info last_named_arg = data->arg; + last_named_arg.named = true; ++ last_named_arg.last_named = true; + targetm.calls.setup_incoming_varargs (all->args_so_far, last_named_arg, + &varargs_pretend_bytes, no_rtl); + +@@ -2610,7 +2614,9 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all, + + locate_and_pad_parm (data->arg.mode, data->arg.type, in_regs, + all->reg_parm_stack_space, +- entry_parm ? data->partial : 0, current_function_decl, ++ entry_parm ? data->partial : 0, ++ all->args_so_far, ++ current_function_decl, + &all->stack_args_size, &data->locate); + + /* Update parm_stack_boundary if this parameter is passed in the +@@ -3924,7 +3930,8 @@ gimplify_parameters (gimple_seq *cleanup) + if (data.arg.pass_by_reference) + { + tree type = TREE_TYPE (data.arg.type); +- function_arg_info orig_arg (type, data.arg.named); ++ function_arg_info orig_arg (type, data.arg.named, ++ data.arg.last_named); + if (reference_callee_copied (&all.args_so_far_v, orig_arg)) + { + tree local, t; +@@ -4027,6 +4034,7 @@ gimplify_parameters (gimple_seq *cleanup) + void + locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs, + int reg_parm_stack_space, int partial, ++ cumulative_args_t ca, + tree fndecl ATTRIBUTE_UNUSED, + struct args_size *initial_offset_ptr, + struct locate_and_pad_arg_data *locate) +@@ -4064,9 +4072,23 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs, + ? arg_size_in_bytes (type) + : size_int (GET_MODE_SIZE (passed_mode))); + where_pad = targetm.calls.function_arg_padding (passed_mode, type); +- boundary = targetm.calls.function_arg_boundary (passed_mode, type); +- round_boundary = targetm.calls.function_arg_round_boundary (passed_mode, +- type); ++ ++ if (flag_stack_use_cumulative_args) ++ { ++ boundary = targetm.calls.function_arg_boundary_ca (passed_mode, ++ type, ++ ca); ++ round_boundary = targetm.calls.function_arg_round_boundary_ca ++ (passed_mode, type, ca); ++ } ++ else ++ { ++ boundary = targetm.calls.function_arg_boundary (passed_mode, ++ type); ++ round_boundary = targetm.calls.function_arg_round_boundary ++ (passed_mode, type); ++ } ++ + locate->where_pad = where_pad; + + /* Alignment can't exceed MAX_SUPPORTED_STACK_ALIGNMENT. */ +diff --git a/gcc/function.h b/gcc/function.h +index 098613766be..009a9dc1c44 100644 +--- a/gcc/function.h ++++ b/gcc/function.h +@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see + #ifndef GCC_FUNCTION_H + #define GCC_FUNCTION_H + ++#include "cumulative-args.h" + + /* Stack of pending (incomplete) sequences saved by `start_sequence'. + Each element describes one pending sequence. +@@ -661,6 +662,7 @@ extern int aggregate_value_p (const_tree, const_tree); + extern bool use_register_for_decl (const_tree); + extern gimple_seq gimplify_parameters (gimple_seq *); + extern void locate_and_pad_parm (machine_mode, tree, int, int, int, ++ cumulative_args_t, + tree, struct args_size *, + struct locate_and_pad_arg_data *); + extern void generate_setjmp_warnings (void); +diff --git a/gcc/gcc.cc b/gcc/gcc.cc +index bb07cc244e3..a16c1e4372b 100644 +--- a/gcc/gcc.cc ++++ b/gcc/gcc.cc +@@ -572,6 +572,7 @@ or with constant text in a single argument. + %l process LINK_SPEC as a spec. + %L process LIB_SPEC as a spec. + %M Output multilib_os_dir. ++ %P Output a RUNPATH_OPTION for each directory in startfile_prefixes. + %G process LIBGCC_SPEC as a spec. + %R Output the concatenation of target_system_root and + target_sysroot_suffix. +@@ -1191,6 +1192,10 @@ proper position among the other output files. */ + # define SYSROOT_HEADERS_SUFFIX_SPEC "" + #endif + ++#ifndef RUNPATH_OPTION ++# define RUNPATH_OPTION "-rpath" ++#endif ++ + static const char *asm_debug = ASM_DEBUG_SPEC; + static const char *asm_debug_option = ASM_DEBUG_OPTION_SPEC; + static const char *cpp_spec = CPP_SPEC; +@@ -5895,6 +5900,7 @@ struct spec_path_info { + size_t append_len; + bool omit_relative; + bool separate_options; ++ bool realpaths; + }; + + static void * +@@ -5904,6 +5910,16 @@ spec_path (char *path, void *data) + size_t len = 0; + char save = 0; + ++ /* The path must exist; we want to resolve it to the realpath so that this ++ can be embedded as a runpath. */ ++ if (info->realpaths) ++ path = lrealpath (path); ++ ++ /* However, if we failed to resolve it - perhaps because there was a bogus ++ -B option on the command line, then punt on this entry. */ ++ if (!path) ++ return NULL; ++ + if (info->omit_relative && !IS_ABSOLUTE_PATH (path)) + return NULL; + +@@ -6135,6 +6151,22 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) + info.omit_relative = false; + #endif + info.separate_options = false; ++ info.realpaths = false; ++ ++ for_each_path (&startfile_prefixes, true, 0, spec_path, &info); ++ } ++ break; ++ ++ case 'P': ++ { ++ struct spec_path_info info; ++ ++ info.option = RUNPATH_OPTION; ++ info.append_len = 0; ++ info.omit_relative = false; ++ info.separate_options = true; ++ /* We want to embed the actual paths that have the libraries. */ ++ info.realpaths = true; + + for_each_path (&startfile_prefixes, true, 0, spec_path, &info); + } +@@ -6461,6 +6493,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part) + info.append_len = strlen (info.append); + info.omit_relative = false; + info.separate_options = true; ++ info.realpaths = false; + + for_each_path (&include_prefixes, false, info.append_len, + spec_path, &info); +diff --git a/gcc/ginclude/stddef.h b/gcc/ginclude/stddef.h +index 79e296d4a66..a9caa0467ba 100644 +--- a/gcc/ginclude/stddef.h ++++ b/gcc/ginclude/stddef.h +@@ -427,9 +427,8 @@ typedef struct { + /* _Float128 is defined as a basic type, so max_align_t must be + sufficiently aligned for it. This code must work in C++, so we + use __float128 here; that is only available on some +- architectures, but only on i386 is extra alignment needed for +- __float128. */ +-#ifdef __i386__ ++ architectures. */ ++#if defined(__i386__) || (__APPLE__ && __aarch64__) + __float128 __max_align_f128 __attribute__((__aligned__(__alignof(__float128)))); + #endif + } max_align_t; +diff --git a/gcc/jit/Make-lang.in b/gcc/jit/Make-lang.in +index 6e10abfd0ac..5a39342068d 100644 +--- a/gcc/jit/Make-lang.in ++++ b/gcc/jit/Make-lang.in +@@ -43,6 +43,7 @@ + LIBGCCJIT_VERSION_NUM = 0 + LIBGCCJIT_MINOR_NUM = 0 + LIBGCCJIT_RELEASE_NUM = 1 ++COMMA := , + + ifneq (,$(findstring mingw,$(target))) + LIBGCCJIT_FILENAME = libgccjit-$(LIBGCCJIT_VERSION_NUM).dll +@@ -59,22 +60,18 @@ LIBGCCJIT_AGE = 1 + LIBGCCJIT_BASENAME = libgccjit + + LIBGCCJIT_SONAME = \ +- ${libdir}/$(LIBGCCJIT_BASENAME).$(LIBGCCJIT_VERSION_NUM).dylib ++ $(DARWIN_RPATH)/$(LIBGCCJIT_BASENAME).$(LIBGCCJIT_VERSION_NUM).dylib + LIBGCCJIT_FILENAME = $(LIBGCCJIT_BASENAME).$(LIBGCCJIT_VERSION_NUM).dylib + LIBGCCJIT_LINKER_NAME = $(LIBGCCJIT_BASENAME).dylib + +-# Conditionalize the use of the LD_VERSION_SCRIPT_OPTION and +-# LD_SONAME_OPTION depending if configure found them, using $(if) +-# We have to define a COMMA here, otherwise the commas in the "true" +-# result are treated as separators by the $(if). +-COMMA := , +-LIBGCCJIT_VERSION_SCRIPT_OPTION = \ +- $(if $(LD_VERSION_SCRIPT_OPTION),\ +- -Wl$(COMMA)$(LD_VERSION_SCRIPT_OPTION)$(COMMA)$(srcdir)/jit/libgccjit.map) ++# TODO: translate the libgccjit.map into a form usable by Darwin's linker and ++# then check for linker support for -exported_symbols_list=. Omitting this ++# means that all symbols in the libgccjit library will be visible. ++LIBGCCJIT_VERSION_SCRIPT_OPTION = + +-LIBGCCJIT_SONAME_OPTION = \ +- $(if $(LD_SONAME_OPTION), \ +- -Wl$(COMMA)$(LD_SONAME_OPTION)$(COMMA)$(LIBGCCJIT_SONAME)) ++# This is a work-around fix for cross-compilation where the target linker ++# is ld and the host is ld64. ++LIBGCCJIT_SONAME_OPTION = -Wl,-install_name,$(LIBGCCJIT_SONAME) + + LIBGCCJIT_SONAME_SYMLINK = $(LIBGCCJIT_FILENAME) + LIBGCCJIT_LINKER_NAME_SYMLINK = $(LIBGCCJIT_LINKER_NAME) +@@ -98,7 +95,6 @@ LIBGCCJIT_SONAME_SYMLINK = $(LIBGCCJIT_SONAME) + # LD_SONAME_OPTION depending if configure found them, using $(if) + # We have to define a COMMA here, otherwise the commas in the "true" + # result are treated as separators by the $(if). +-COMMA := , + LIBGCCJIT_VERSION_SCRIPT_OPTION = \ + $(if $(LD_VERSION_SCRIPT_OPTION),\ + -Wl$(COMMA)$(LD_VERSION_SCRIPT_OPTION)$(COMMA)$(srcdir)/jit/libgccjit.map) +diff --git a/gcc/objc/objc-next-runtime-abi-02.cc b/gcc/objc/objc-next-runtime-abi-02.cc +index e50ca6e89f5..9ea63b189c7 100644 +--- a/gcc/objc/objc-next-runtime-abi-02.cc ++++ b/gcc/objc/objc-next-runtime-abi-02.cc +@@ -1033,6 +1033,7 @@ next_runtime_abi_02_protocol_decl (tree p) + else + decl = start_var_decl (objc_v2_protocol_template, buf); + OBJCMETA (decl, objc_meta, meta_protocol); ++ DECL_PRESERVE_P (decl) = 1; + return decl; + } + +@@ -2115,8 +2116,8 @@ build_v2_classrefs_table (void) + expr = convert (objc_class_type, build_fold_addr_expr (expr)); + } + /* The runtime wants this, even if it appears unused, so we must force the +- output. +- DECL_PRESERVE_P (decl) = 1; */ ++ output. */ ++ DECL_PRESERVE_P (decl) = 1; + finish_var_decl (decl, expr); + } + } +@@ -2318,6 +2319,7 @@ build_v2_protocol_list_address_table (void) + expr = convert (objc_protocol_type, build_fold_addr_expr (ref->refdecl)); + OBJCMETA (decl, objc_meta, meta_label_protocollist); + finish_var_decl (decl, expr); ++ DECL_PRESERVE_P (decl) = 1; + } + + /* TODO: delete the vec. */ +diff --git a/gcc/target.def b/gcc/target.def +index d85adf36a39..5eb1fdce24e 100644 +--- a/gcc/target.def ++++ b/gcc/target.def +@@ -4967,6 +4967,18 @@ with the specified mode and type. The default hook returns\n\ + unsigned int, (machine_mode mode, const_tree type), + default_function_arg_boundary) + ++DEFHOOK ++(function_arg_boundary_ca, ++ "This is the @code{cumulative_args_t}-based version of\n\ ++@code{TARGET_FUNCTION_ARG_BOUNDARY}. Define this hook if you need more\n\ ++fine-grained control over argument alignment, e.g. depending on whether\n\ ++it is a named argument or not, or any other criteria that you choose to\n\ ++place in the @var{ca} structure.\n\ ++\n\ ++The default hook will call @code{TARGET_FUNCTION_ARG_BOUNDARY}.", ++ unsigned int, (machine_mode mode, const_tree type, cumulative_args_t ca), ++ default_function_arg_boundary_ca) ++ + DEFHOOK + (function_arg_round_boundary, + "Normally, the size of an argument is rounded up to @code{PARM_BOUNDARY},\n\ +@@ -4976,6 +4988,18 @@ value.", + unsigned int, (machine_mode mode, const_tree type), + default_function_arg_round_boundary) + ++DEFHOOK ++(function_arg_round_boundary_ca, ++ "This is the @code{cumulative_args_t}-based version of\n\ ++@code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}. Define this hook if you need more\n\ ++fine-grained control over argument size rounding, e.g. depending on whether\n\ ++it is a named argument or not, or any other criteria that you choose to\n\ ++place in the @var{ca} structure.\n\ ++\n\ ++The default hook will call @code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}.", ++ unsigned int, (machine_mode mode, const_tree type, cumulative_args_t ca), ++ default_function_arg_round_boundary_ca) ++ + /* Return the diagnostic message string if function without a prototype + is not allowed for this 'val' argument; NULL otherwise. */ + DEFHOOK +diff --git a/gcc/target.h b/gcc/target.h +index d6fa6931499..40c3da87656 100644 +--- a/gcc/target.h ++++ b/gcc/target.h +@@ -51,22 +51,7 @@ + #include "insn-codes.h" + #include "tm.h" + #include "hard-reg-set.h" +- +-#if CHECKING_P +- +-struct cumulative_args_t { void *magic; void *p; }; +- +-#else /* !CHECKING_P */ +- +-/* When using a GCC build compiler, we could use +- __attribute__((transparent_union)) to get cumulative_args_t function +- arguments passed like scalars where the ABI would mandate a less +- efficient way of argument passing otherwise. However, that would come +- at the cost of less type-safe !CHECKING_P compilation. */ +- +-union cumulative_args_t { void *p; }; +- +-#endif /* !CHECKING_P */ ++#include "cumulative-args.h" + + /* Types of memory operation understood by the "by_pieces" infrastructure. + Used by the TARGET_USE_BY_PIECES_INFRASTRUCTURE_P target hook and +diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc +index 399d6f874dc..9d554adcb45 100644 +--- a/gcc/targhooks.cc ++++ b/gcc/targhooks.cc +@@ -850,6 +850,14 @@ default_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED, + return PARM_BOUNDARY; + } + ++unsigned int ++default_function_arg_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, ++ const_tree type ATTRIBUTE_UNUSED, ++ cumulative_args_t ca ATTRIBUTE_UNUSED) ++{ ++ return default_function_arg_boundary (mode, type); ++} ++ + unsigned int + default_function_arg_round_boundary (machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED) +@@ -857,6 +865,14 @@ default_function_arg_round_boundary (machine_mode mode ATTRIBUTE_UNUSED, + return PARM_BOUNDARY; + } + ++unsigned int ++default_function_arg_round_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, ++ const_tree type ATTRIBUTE_UNUSED, ++ cumulative_args_t ca ATTRIBUTE_UNUSED) ++{ ++ return default_function_arg_round_boundary (mode, type); ++} ++ + void + hook_void_bitmap (bitmap regs ATTRIBUTE_UNUSED) + { +diff --git a/gcc/targhooks.h b/gcc/targhooks.h +index ecce55ebe79..ba110ade58b 100644 +--- a/gcc/targhooks.h ++++ b/gcc/targhooks.h +@@ -154,6 +154,12 @@ extern unsigned int default_function_arg_boundary (machine_mode, + const_tree); + extern unsigned int default_function_arg_round_boundary (machine_mode, + const_tree); ++extern unsigned int default_function_arg_boundary_ca (machine_mode, ++ const_tree, ++ cumulative_args_t ca); ++extern unsigned int default_function_arg_round_boundary_ca (machine_mode, ++ const_tree, ++ cumulative_args_t ca); + extern bool hook_bool_const_rtx_commutative_p (const_rtx, int); + extern rtx default_function_value (const_tree, const_tree, bool); + extern HARD_REG_SET default_zero_call_used_regs (HARD_REG_SET); +diff --git a/gcc/testsuite/g++.dg/abi/aarch64_guard1.C b/gcc/testsuite/g++.dg/abi/aarch64_guard1.C +index e2669a89fbf..52be32decc6 100644 +--- a/gcc/testsuite/g++.dg/abi/aarch64_guard1.C ++++ b/gcc/testsuite/g++.dg/abi/aarch64_guard1.C +@@ -12,5 +12,6 @@ int *foo () + return &x; + } + +-// { dg-final { scan-assembler _ZGVZ3foovE1x,8,8 } } ++// { dg-final { scan-assembler _ZGVZ3foovE1x,8,8 { target { ! *-*-darwin* } } } } ++// { dg-final { scan-assembler __DATA,__bss,__ZGVZ3foovE1x,8,3 { target *-*-darwin* } } } + // { dg-final { scan-tree-dump "& 1" "original" } } +diff --git a/gcc/testsuite/g++.dg/abi/arm_va_list.C b/gcc/testsuite/g++.dg/abi/arm_va_list.C +index 4f6f3a46da4..ff9fd8bcf0d 100644 +--- a/gcc/testsuite/g++.dg/abi/arm_va_list.C ++++ b/gcc/testsuite/g++.dg/abi/arm_va_list.C +@@ -8,8 +8,10 @@ + // #include + typedef __builtin_va_list va_list; + +-// { dg-final { scan-assembler "\n_Z1fPSt9__va_list:" } } ++// { dg-final { scan-assembler "\n_Z1fPSt9__va_list:" { target { ! *-*-darwin* } } } } ++// { dg-final { scan-assembler "\n__Z1fPPc:" { target *-*-darwin* } } } + void f(va_list*) {} + +-// { dg-final { scan-assembler "\n_Z1gSt9__va_listS_:" } } ++// { dg-final { scan-assembler "\n_Z1gSt9__va_listS_:" { target { ! *-*-darwin* } } } } ++// { dg-final { scan-assembler "\n__Z1gPcS_:" { target *-*-darwin* } } } + void g(va_list, va_list) {} +diff --git a/gcc/testsuite/g++.dg/cpp0x/pr106435-b.cc b/gcc/testsuite/g++.dg/cpp0x/pr106435-b.cc +new file mode 100644 +index 00000000000..4f581694177 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/cpp0x/pr106435-b.cc +@@ -0,0 +1,17 @@ ++// PR c++/106435 ++#include "pr106435.h" ++ ++//#include ++ ++Foo::Foo() { ++ ++num_calls; ++// std::cout << "Foo::Foo(this=" << this << ")\n"; ++} ++ ++int Foo::func() { ++// std::cout << "Foo::func(this=" << this << ")\n"; ++ return num_calls; ++} ++ ++thread_local Foo Bar::foo; ++thread_local Foo Bar::baz; +diff --git a/gcc/testsuite/g++.dg/cpp0x/pr106435.C b/gcc/testsuite/g++.dg/cpp0x/pr106435.C +new file mode 100644 +index 00000000000..d600976f9f9 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/cpp0x/pr106435.C +@@ -0,0 +1,20 @@ ++// PR c++/106435 ++// { dg-do run { target c++11 } } ++// { dg-additional-sources "pr106435-b.cc" } ++ ++#include "pr106435.h" ++ ++int num_calls = 0; ++ ++extern "C" __attribute__((__noreturn__)) void abort(); ++ ++thread_local Foo Bar::bat; ++ ++int main() { ++ int v = Bar::foo.func(); ++ if (v != 2) ++ abort(); ++ v = Bar::bat.func(); ++ if (v != 3) ++ abort(); ++} +diff --git a/gcc/testsuite/g++.dg/cpp0x/pr106435.h b/gcc/testsuite/g++.dg/cpp0x/pr106435.h +new file mode 100644 +index 00000000000..240de1ee9a9 +--- /dev/null ++++ b/gcc/testsuite/g++.dg/cpp0x/pr106435.h +@@ -0,0 +1,14 @@ ++// PR c++/106435 ++#pragma once ++ ++extern int num_calls; ++struct Foo { ++ Foo(); ++ int func(); ++}; ++ ++struct Bar { ++ thread_local static Foo foo; ++ thread_local static Foo baz; ++ thread_local static Foo bat; ++}; +diff --git a/gcc/testsuite/g++.dg/ext/arm-bf16/bf16-mangle-aarch64-1.C b/gcc/testsuite/g++.dg/ext/arm-bf16/bf16-mangle-aarch64-1.C +index 5426a1814b8..a017ce8ce5f 100644 +--- a/gcc/testsuite/g++.dg/ext/arm-bf16/bf16-mangle-aarch64-1.C ++++ b/gcc/testsuite/g++.dg/ext/arm-bf16/bf16-mangle-aarch64-1.C +@@ -2,12 +2,12 @@ + + /* Test mangling */ + +-/* { dg-final { scan-assembler "\t.global\t_Z1fPu6__bf16" } } */ ++/* { dg-final { scan-assembler {\t.globa?l[ \t]_?_Z1fPu6__bf16} } } */ + void f (__bf16 *x) { } + +-/* { dg-final { scan-assembler "\t.global\t_Z1gPu6__bf16S_" } } */ ++/* { dg-final { scan-assembler {\t.globa?l[ \t]_?_Z1gPu6__bf16S_} } } */ + void g (__bf16 *x, __bf16 *y) { } + +-/* { dg-final { scan-assembler "\t.global\t_ZN1SIu6__bf16u6__bf16E1iE" } } */ ++/* { dg-final { scan-assembler {\t.globa?l[ \t]_?_ZN1SIu6__bf16u6__bf16E1iE} } } */ + template struct S { static int i; }; + template <> int S<__bf16, __bf16>::i = 3; +diff --git a/gcc/testsuite/g++.dg/torture/darwin-cfstring-3.C b/gcc/testsuite/g++.dg/torture/darwin-cfstring-3.C +index ee4b385b17f..eabb3b517a4 100644 +--- a/gcc/testsuite/g++.dg/torture/darwin-cfstring-3.C ++++ b/gcc/testsuite/g++.dg/torture/darwin-cfstring-3.C +@@ -26,5 +26,5 @@ void foo(void) { + + /* { dg-final { scan-assembler "\\.long\[ \\t\]+___CFConstantStringClassReference\n\[ \\t\]*\\.long\[ \\t\]+1992\n\[ \\t\]*\\.long\[ \\t\]+\[lL\]C.*\n\[ \\t\]*\\.long\[ \\t\]+4\n" { target { *-*-darwin* && { ! lp64 } } } } } */ + /* { dg-final { scan-assembler "\\.long\[ \\t\]+___CFConstantStringClassReference\n\[ \\t\]*\\.long\[ \\t\]+1992\n\[ \\t\]*\\.long\[ \\t\]+\[lL\]C.*\n\[ \\t\]*\\.long\[ \\t\]+10\n" { target { *-*-darwin* && { ! lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t___CFConstantStringClassReference\n\t.long\t1992\n\t.space 4\n\t.quad\t.*\n\t.quad\t4\n" { target { *-*-darwin* && { lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t___CFConstantStringClassReference\n\t.long\t1992\n\t.space 4\n\t.quad\t.*\n\t.quad\t10\n" { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t___CFConstantStringClassReference\n\t.(long|word)\t1992\n\t.space 4\n\t.(quad|xword)\t.*\n\t.(quad|xword)\t4\n} { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t___CFConstantStringClassReference\n\t.(long|word)\t1992\n\t.space 4\n\t.(quad|xword)\t.*\n\t.(quad|xword)\t10\n} { target { *-*-darwin* && { lp64 } } } } } */ +diff --git a/gcc/testsuite/g++.target/aarch64/no_unique_address_1.C b/gcc/testsuite/g++.target/aarch64/no_unique_address_1.C +index 5fc68ea5d6d..5faf915fa54 100644 +--- a/gcc/testsuite/g++.target/aarch64/no_unique_address_1.C ++++ b/gcc/testsuite/g++.target/aarch64/no_unique_address_1.C +@@ -1,5 +1,5 @@ + /* { dg-options "-std=c++11 -O -foptimize-sibling-calls -fpeephole2" } */ +-/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */ ++/* { dg-final { check-function-bodies "**" "" "" { target { lp64 && { ! aarch64*-*-darwin* } } } } } */ + + struct X { }; + struct Y { int : 0; }; +diff --git a/gcc/testsuite/g++.target/aarch64/no_unique_address_2.C b/gcc/testsuite/g++.target/aarch64/no_unique_address_2.C +index f0717133ccd..322ec127c79 100644 +--- a/gcc/testsuite/g++.target/aarch64/no_unique_address_2.C ++++ b/gcc/testsuite/g++.target/aarch64/no_unique_address_2.C +@@ -1,5 +1,5 @@ + /* { dg-options "-std=c++17 -O -foptimize-sibling-calls -fpeephole2" } */ +-/* { dg-final { check-function-bodies "**" "" "" { target lp64 } } } */ ++/* { dg-final { check-function-bodies "**" "" "" { target { lp64 && { ! aarch64*-*-darwin* } } } } } */ + + struct X { }; + struct Y { int : 0; }; +diff --git a/gcc/testsuite/g++.target/aarch64/sve/aarch64-sve.exp b/gcc/testsuite/g++.target/aarch64/sve/aarch64-sve.exp +index 03a6537a53e..d4c2052dc59 100644 +--- a/gcc/testsuite/g++.target/aarch64/sve/aarch64-sve.exp ++++ b/gcc/testsuite/g++.target/aarch64/sve/aarch64-sve.exp +@@ -25,6 +25,11 @@ if {![istarget aarch64*-*-*] } then { + return + } + ++# Darwin doesn't support sve ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib g++-dg.exp + +diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle-asm.exp b/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle-asm.exp +index 38140413a97..559e1f37c68 100644 +--- a/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle-asm.exp ++++ b/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle-asm.exp +@@ -24,6 +24,11 @@ if { ![istarget aarch64*-*-*] } { + return + } + ++# Darwin doesn't support sve ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib g++-dg.exp + +diff --git a/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle.exp b/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle.exp +index d1887eb8087..c9fee945c52 100644 +--- a/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle.exp ++++ b/gcc/testsuite/g++.target/aarch64/sve/acle/aarch64-sve-acle.exp +@@ -25,6 +25,11 @@ if {![istarget aarch64*-*-*] } { + return + } + ++# Darwin doesn't support sve ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib g++-dg.exp + +diff --git a/gcc/testsuite/g++.target/aarch64/sve2/acle/aarch64-sve2-acle-asm.exp b/gcc/testsuite/g++.target/aarch64/sve2/acle/aarch64-sve2-acle-asm.exp +index 78e8ecae729..e22ef5f0876 100644 +--- a/gcc/testsuite/g++.target/aarch64/sve2/acle/aarch64-sve2-acle-asm.exp ++++ b/gcc/testsuite/g++.target/aarch64/sve2/acle/aarch64-sve2-acle-asm.exp +@@ -24,6 +24,11 @@ if { ![istarget aarch64*-*-*] } { + return + } + ++# Darwin doesn't support sve ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib g++-dg.exp + +diff --git a/gcc/testsuite/gcc.dg/builtin-apply2.c b/gcc/testsuite/gcc.dg/builtin-apply2.c +index 0f350f4ac16..d1e70b3a3e5 100644 +--- a/gcc/testsuite/gcc.dg/builtin-apply2.c ++++ b/gcc/testsuite/gcc.dg/builtin-apply2.c +@@ -1,7 +1,7 @@ + /* { dg-do run } */ + /* { dg-require-effective-target untyped_assembly } */ + /* { dg-skip-if "Variadic funcs have all args on stack. Normal funcs have args in registers." { "avr-*-* nds32*-*-* amdgcn-*-*" } } */ +-/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs." { "csky*-*-* riscv*-*-* or1k*-*-* msp430-*-* pru-*-* loongarch*-*-*" } } */ ++/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs." { "csky*-*-* riscv*-*-* or1k*-*-* msp430-*-* pru-*-* loongarch*-*-* aarch64-apple-darwin*" } } */ + /* { dg-skip-if "Variadic funcs use Base AAPCS. Normal funcs use VFP variant." { arm*-*-* && arm_hf_eabi } } */ + + /* PR target/12503 */ +diff --git a/gcc/testsuite/gcc.dg/cwsc1.c b/gcc/testsuite/gcc.dg/cwsc1.c +index e793e26116a..7d8b472bdf6 100644 +--- a/gcc/testsuite/gcc.dg/cwsc1.c ++++ b/gcc/testsuite/gcc.dg/cwsc1.c +@@ -6,7 +6,11 @@ + #elif defined(__i386__) + # define CHAIN "%ecx" + #elif defined(__aarch64__) +-# define CHAIN "x18" ++# if defined(__APPLE__) ++# define CHAIN "x16" ++# else ++# define CHAIN "x18" ++# endif + #elif defined(__alpha__) + # define CHAIN "$1" + #elif defined(__arm__) +diff --git a/gcc/testsuite/gcc.dg/darwin-segaddr.c b/gcc/testsuite/gcc.dg/darwin-segaddr.c +index 526db77bd9c..fcc324b3031 100644 +--- a/gcc/testsuite/gcc.dg/darwin-segaddr.c ++++ b/gcc/testsuite/gcc.dg/darwin-segaddr.c +@@ -1,7 +1,8 @@ + /* Check that -segaddr gets through and works. */ + /* { dg-do run { target *-*-darwin* } } */ + /* { dg-options "-O0 -segaddr __TEST 0x200000 -fno-pie" { target { *-*-darwin* && { ! lp64 } } } } */ +-/* { dg-options "-O0 -segaddr __TEST 0x110000000 -fno-pie" { target { *-*-darwin* && lp64 } } } */ ++/* { dg-options "-O0 -segaddr __TEST 0x110000000 -fno-pie" { target { *-*-darwin[1456789]* && lp64 } } } */ ++/* { dg-options "-O0 -segaddr __TEST 0x110000000 " { target { *-*-darwin2* && lp64 } } } */ + + extern void abort (); + +diff --git a/gcc/testsuite/gcc.dg/pr26427.c b/gcc/testsuite/gcc.dg/pr26427.c +index add13ca209e..2c09f28195d 100644 +--- a/gcc/testsuite/gcc.dg/pr26427.c ++++ b/gcc/testsuite/gcc.dg/pr26427.c +@@ -1,4 +1,4 @@ +-/* { dg-warning "this target does not support" "" {target *86*-*-darwin* } 0 } */ ++/* { dg-warning "this target does not support" "" {target *86*-*-darwin* aarch64-*-darwin* } 0 } */ + /* { dg-do run { target { *-*-darwin* } } } */ + /* { dg-options { -fsection-anchors -O } } */ + /* PR target/26427 */ +diff --git a/gcc/testsuite/gcc.dg/pubtypes-2.c b/gcc/testsuite/gcc.dg/pubtypes-2.c +index 116e3489bc0..b3d1231ad44 100644 +--- a/gcc/testsuite/gcc.dg/pubtypes-2.c ++++ b/gcc/testsuite/gcc.dg/pubtypes-2.c +@@ -2,7 +2,8 @@ + /* { dg-options "-O0 -gdwarf-2 -dA" } */ + /* { dg-skip-if "Unmatchable assembly" { mmix-*-* } } */ + /* { dg-final { scan-assembler "__debug_pubtypes" } } */ +-/* { dg-final { scan-assembler {long+[ \t]+0x14d+[ \t]+[#;]+[ \t]+Pub Info Length} } } */ ++/* { dg-final { scan-assembler {long+[ \t]+0x14d+[ \t]+[#;]+[ \t]+Pub Info Length} { target { ! aarch64-*-darwin* } } } } */ ++/* { dg-final { scan-assembler {long+[ \t]+0x163+[ \t]+[#;]+[ \t]+Pub Info Length} { target aarch64-*-darwin* } } } */ + /* { dg-final { scan-assembler "used_struct\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } } */ + /* { dg-final { scan-assembler-not "unused_struct\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } } */ + +diff --git a/gcc/testsuite/gcc.dg/pubtypes-3.c b/gcc/testsuite/gcc.dg/pubtypes-3.c +index 3fb3468fb00..950a9ba72fc 100644 +--- a/gcc/testsuite/gcc.dg/pubtypes-3.c ++++ b/gcc/testsuite/gcc.dg/pubtypes-3.c +@@ -2,7 +2,8 @@ + /* { dg-options "-O0 -gdwarf-2 -dA" } */ + /* { dg-skip-if "Unmatchable assembly" { mmix-*-* } } */ + /* { dg-final { scan-assembler "__debug_pubtypes" } } */ +-/* { dg-final { scan-assembler {long+[ \t]+0x14d+[ \t]+[#;]+[ \t]+Pub Info Length} } } */ ++/* { dg-final { scan-assembler {long+[ \t]+0x14d+[ \t]+[#;]+[ \t]+Pub Info Length} { target { ! aarch64-*-darwin* } } } } */ ++/* { dg-final { scan-assembler {long+[ \t]+0x163+[ \t]+[#;]+[ \t]+Pub Info Length} { target aarch64-*-darwin* } } } */ + /* { dg-final { scan-assembler "used_struct\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } } */ + /* { dg-final { scan-assembler-not "unused_struct\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } } */ + /* { dg-final { scan-assembler-not "\"list_name_type\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } } */ +diff --git a/gcc/testsuite/gcc.dg/pubtypes-4.c b/gcc/testsuite/gcc.dg/pubtypes-4.c +index 83fba8dfabc..7250771587b 100644 +--- a/gcc/testsuite/gcc.dg/pubtypes-4.c ++++ b/gcc/testsuite/gcc.dg/pubtypes-4.c +@@ -2,7 +2,8 @@ + /* { dg-options "-O0 -gdwarf-2 -dA" } */ + /* { dg-skip-if "Unmatchable assembly" { mmix-*-* } } */ + /* { dg-final { scan-assembler "__debug_pubtypes" } } */ +-/* { dg-final { scan-assembler {long+[ \t]+0x184+[ \t]+[#;]+[ \t]+Pub Info Length} } } */ ++/* { dg-final { scan-assembler {long+[ \t]+0x184+[ \t]+[#;]+[ \t]+Pub Info Length} { target { ! aarch64-*-darwin* } } } } */ ++/* { dg-final { scan-assembler {long+[ \t]+0x19a+[ \t]+[#;]+[ \t]+Pub Info Length} { target aarch64-*-darwin* } } } */ + /* { dg-final { scan-assembler "used_struct\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } } */ + /* { dg-final { scan-assembler-not "unused_struct\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } } */ + /* { dg-final { scan-assembler "\"list_name_type\\\\0\"+\[ \t\]+\[#;]+\[ \t\]+external name" } } */ +diff --git a/gcc/testsuite/gcc.dg/rtl/aarch64/big-endian-cse-1.c b/gcc/testsuite/gcc.dg/rtl/aarch64/big-endian-cse-1.c +index 1559a489f25..aa2da0cbca5 100644 +--- a/gcc/testsuite/gcc.dg/rtl/aarch64/big-endian-cse-1.c ++++ b/gcc/testsuite/gcc.dg/rtl/aarch64/big-endian-cse-1.c +@@ -1,4 +1,5 @@ + /* { dg-do compile { target aarch64*-*-* } } */ ++/* { dg-skip-if "Darwin platforms do not support big-endian arm64" *-*-darwin* } */ + /* { dg-require-effective-target lp64 } */ + /* { dg-options "-O3 -mbig-endian" } */ + +diff --git a/gcc/testsuite/gcc.dg/tls/pr78796.c b/gcc/testsuite/gcc.dg/tls/pr78796.c +index 038e5366e41..31e03dd419c 100644 +--- a/gcc/testsuite/gcc.dg/tls/pr78796.c ++++ b/gcc/testsuite/gcc.dg/tls/pr78796.c +@@ -1,7 +1,7 @@ + /* PR target/78796 */ + /* { dg-do run } */ + /* { dg-options "-O2" } */ +-/* { dg-additional-options "-mcmodel=large" { target aarch64-*-* } } */ ++/* { dg-additional-options "-mcmodel=large" { target { { aarch64-*-* } && { ! aarch64-*-darwin* } } } } */ + /* { dg-require-effective-target tls_runtime } */ + /* { dg-add-options tls } */ + +diff --git a/gcc/testsuite/gcc.dg/torture/darwin-cfstring-3.c b/gcc/testsuite/gcc.dg/torture/darwin-cfstring-3.c +index ee4b385b17f..eabb3b517a4 100644 +--- a/gcc/testsuite/gcc.dg/torture/darwin-cfstring-3.c ++++ b/gcc/testsuite/gcc.dg/torture/darwin-cfstring-3.c +@@ -26,5 +26,5 @@ void foo(void) { + + /* { dg-final { scan-assembler "\\.long\[ \\t\]+___CFConstantStringClassReference\n\[ \\t\]*\\.long\[ \\t\]+1992\n\[ \\t\]*\\.long\[ \\t\]+\[lL\]C.*\n\[ \\t\]*\\.long\[ \\t\]+4\n" { target { *-*-darwin* && { ! lp64 } } } } } */ + /* { dg-final { scan-assembler "\\.long\[ \\t\]+___CFConstantStringClassReference\n\[ \\t\]*\\.long\[ \\t\]+1992\n\[ \\t\]*\\.long\[ \\t\]+\[lL\]C.*\n\[ \\t\]*\\.long\[ \\t\]+10\n" { target { *-*-darwin* && { ! lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t___CFConstantStringClassReference\n\t.long\t1992\n\t.space 4\n\t.quad\t.*\n\t.quad\t4\n" { target { *-*-darwin* && { lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t___CFConstantStringClassReference\n\t.long\t1992\n\t.space 4\n\t.quad\t.*\n\t.quad\t10\n" { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t___CFConstantStringClassReference\n\t.(long|word)\t1992\n\t.space 4\n\t.(quad|xword)\t.*\n\t.(quad|xword)\t4\n} { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t___CFConstantStringClassReference\n\t.(long|word)\t1992\n\t.space 4\n\t.(quad|xword)\t.*\n\t.(quad|xword)\t10\n} { target { *-*-darwin* && { lp64 } } } } } */ +diff --git a/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c b/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c +index 552ca1433f4..16643ceb198 100644 +--- a/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c ++++ b/gcc/testsuite/gcc.dg/torture/stackalign/builtin-apply-2.c +@@ -9,7 +9,7 @@ + /* arm_hf_eabi: Variadic funcs use Base AAPCS. Normal funcs use VFP variant. + avr: Variadic funcs don't pass arguments in registers, while normal funcs + do. */ +-/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs" { arm_hf_eabi || { csky*-*-* avr-*-* riscv*-*-* or1k*-*-* msp430-*-* amdgcn-*-* pru-*-* loongarch*-*-* } } } */ ++/* { dg-skip-if "Variadic funcs use different argument passing from normal funcs" { arm_hf_eabi || { csky*-*-* avr-*-* riscv*-*-* or1k*-*-* msp430-*-* amdgcn-*-* pru-*-* loongarch*-*-* aarch64-apple-darwin* } } } */ + /* { dg-skip-if "Variadic funcs have all args on stack. Normal funcs have args in registers." { nds32*-*-* } { v850*-*-* } } */ + /* { dg-require-effective-target untyped_assembly } */ + +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/stdarg-2.c b/gcc/testsuite/gcc.dg/tree-ssa/stdarg-2.c +index 0224997f18a..3684cffdc64 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/stdarg-2.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/stdarg-2.c +@@ -25,9 +25,9 @@ f1 (int i, ...) + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save 0 GPR units and 0 FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save 0 GPR units and 0 FPR units" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save 0 GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save 0 GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save 0 GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save 0 GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save 0 GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save 0 GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save 0 GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -46,9 +46,9 @@ f2 (int i, ...) + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save \[148\] GPR units and 0 FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save 8 GPR units and 1" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save 1 GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save 8 GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save 8 GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -62,10 +62,10 @@ f3 (int i, ...) + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 0 GPR units and \[1-9\]\[0-9\]* FPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 || llp64 } } } } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 0 GPR units and \[1-9\]\[0-9\]* FPR units" "stdarg" { target { powerpc*-*-linux* && { powerpc_fprs && ilp32 } } } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 0 GPR units and 1 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 0 GPR units and 16 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 0 GPR units and 16 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 8 GPR units and 2" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save \[1-9\]\[0-9\]* GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save \[1-9\]\[0-9\]* GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save \[1-9\]\[0-9\]* GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save \[1-9\]\[0-9\]* GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -81,9 +81,9 @@ f4 (int i, ...) + /* { dg-final { scan-tree-dump "f4: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f4: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f4: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f4: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f4: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f4: va_list escapes 1, needs to save all GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f4: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f4: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f4: va_list escapes 1, needs to save all GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -100,9 +100,9 @@ f5 (int i, ...) + /* { dg-final { scan-tree-dump "f5: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f5: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f5: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f5: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f5: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f5: va_list escapes 1, needs to save all GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f5: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f5: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f5: va_list escapes 1, needs to save all GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -121,9 +121,9 @@ f6 (int i, ...) + /* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save (3|12|24) GPR units and 0 FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save 24 GPR units and 1" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save 3 GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save 24 GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save 24 GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save (3|12|24) GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save (3|12|24) GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save (3|12|24) GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save (3|12|24) GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -139,9 +139,9 @@ f7 (int i, ...) + /* { dg-final { scan-tree-dump "f7: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f7: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f7: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f7: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f7: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f7: va_list escapes 1, needs to save all GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f7: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f7: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f7: va_list escapes 1, needs to save all GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -159,9 +159,9 @@ f8 (int i, ...) + /* { dg-final { scan-tree-dump "f8: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f8: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f8: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f8: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f8: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f8: va_list escapes 1, needs to save all GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f8: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f8: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f8: va_list escapes 1, needs to save all GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -177,9 +177,9 @@ f9 (int i, ...) + /* { dg-final { scan-tree-dump "f9: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f9: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f9: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f9: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f9: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f9: va_list escapes 1, needs to save all GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f9: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f9: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f9: va_list escapes 1, needs to save all GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -197,9 +197,9 @@ f10 (int i, ...) + /* { dg-final { scan-tree-dump "f10: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f10: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f10: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f10: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f10: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f10: va_list escapes 1, needs to save all GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f10: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f10: va_list escapes 1, needs to save all GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f10: va_list escapes 1, needs to save all GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -218,9 +218,9 @@ f11 (int i, ...) + /* { dg-final { scan-tree-dump "f11: va_list escapes 0, needs to save (3|12|24) GPR units and 0 FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f11: va_list escapes 0, needs to save 24 GPR units and 1" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f11: va_list escapes 0, needs to save 3 GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f11: va_list escapes 0, needs to save 24 GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f11: va_list escapes 0, needs to save 24 GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f11: va_list escapes 0, needs to save (3|12|24) GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f11: va_list escapes 0, needs to save (3|12|24) GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f11: va_list escapes 0, needs to save (3|12|24) GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f11: va_list escapes 0, needs to save (3|12|24) GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -239,9 +239,9 @@ f12 (int i, ...) + /* { dg-final { scan-tree-dump "f12: va_list escapes 0, needs to save 0 GPR units and \[1-9\]\[0-9\]* FPR units" "stdarg" { target { powerpc*-*-linux* && { powerpc_fprs && ilp32 } } } } } */ + /* { dg-final { scan-tree-dump "f12: va_list escapes 0, needs to save 24 GPR units and 2" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f12: va_list escapes 0, needs to save 0 GPR units and 3 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f12: va_list escapes 0, needs to save 0 GPR units and 48 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f12: va_list escapes 0, needs to save 0 GPR units and 48 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f12: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f12: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f12: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f12: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -260,9 +260,9 @@ f13 (int i, ...) + /* { dg-final { scan-tree-dump "f13: va_list escapes 0, needs to save 0 GPR units and \[1-9\]\[0-9\]* FPR units" "stdarg" { target { powerpc*-*-linux* && { powerpc_fprs && ilp32 } } } } } */ + /* { dg-final { scan-tree-dump "f13: va_list escapes 0, needs to save 24 GPR units and 2" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f13: va_list escapes 0, needs to save 0 GPR units and 3 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f13: va_list escapes 0, needs to save 0 GPR units and 48 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f13: va_list escapes 0, needs to save 0 GPR units and 48 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f13: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f13: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f13: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f13: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -281,9 +281,9 @@ f14 (int i, ...) + /* { dg-final { scan-tree-dump "f14: va_list escapes 0, needs to save \[148\] GPR units and \[1-9\]\[0-9\]* FPR units" "stdarg" { target { powerpc*-*-linux* && { powerpc_fprs && ilp32 } } } } } */ + /* { dg-final { scan-tree-dump "f14: va_list escapes 0, needs to save 24 GPR units and 3" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f14: va_list escapes 0, needs to save 1 GPR units and 2 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f14: va_list escapes 0, needs to save 8 GPR units and 32 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f14: va_list escapes 0, needs to save 8 GPR units and 32 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f14: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f14: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f14: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f14: va_list escapes 0, needs to save \[1-9]\[0-9\]* GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + inline void __attribute__((always_inline)) +@@ -305,11 +305,11 @@ f15 (int i, ...) + /* { dg-final { scan-tree-dump "f15: va_list escapes 0, needs to save \[148\] GPR units and \[1-9\]\[0-9\]* FPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 || llp64 } } } } } } */ + /* { dg-final { scan-tree-dump "f15: va_list escapes 0, needs to save \[148\] GPR units and \[1-9\]\[0-9\]* FPR units" "stdarg" { target { powerpc*-*-linux* && { powerpc_fprs && ilp32 } } } } } */ + /* { dg-final { scan-tree-dump "f15: va_list escapes 0, needs to save 1 GPR units and 2 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f15: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f15: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + + /* We may be able to improve upon this after fixing PR66010/PR66013. */ + /* { dg-final { scan-tree-dump "f15: va_list escapes 1, needs to save all GPR units and all FPR units" "stdarg" { target alpha*-*-linux* } } } */ + + /* { dg-final { scan-tree-dump-not "f15: va_list escapes 0, needs to save 0 GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump-not "f15: va_list escapes 0, needs to save 0 GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump-not "f15: va_list escapes 0, needs to save 0 GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump-not "f15: va_list escapes 0, needs to save 0 GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/stdarg-4.c b/gcc/testsuite/gcc.dg/tree-ssa/stdarg-4.c +index 1a637d6efe4..77cdf384df4 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/stdarg-4.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/stdarg-4.c +@@ -27,9 +27,9 @@ f1 (int i, ...) + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save all GPR units and 0 FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save all GPR units and 1" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save all GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save all GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save all GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f1: va_list escapes \[01\], needs to save all GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f1: va_list escapes \[01\], needs to save all GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f1: va_list escapes \[01\], needs to save all GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f1: va_list escapes \[01\], needs to save all GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -45,9 +45,9 @@ f2 (int i, ...) + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save 0 GPR units and all FPR units" "stdarg" { target { powerpc*-*-linux* && { powerpc_fprs && ilp32 } } } } } */ + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save all GPR units and 2" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save 0 GPR units and all FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save 0 GPR units and all FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save 0 GPR units and all FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f2: va_list escapes \[01\], needs to save all GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f2: va_list escapes \[01\], needs to save all GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f2: va_list escapes \[01\], needs to save all GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f2: va_list escapes \[01\], needs to save all GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + /* Here va_arg can be executed at most as many times as va_start. +@@ -69,9 +69,9 @@ f3 (int i, ...) + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save \[148\] GPR units and 0 FPR units" "stdarg" { target { powerpc*-*-linux* && ilp32 } } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 8 GPR units and 1" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 1 GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 8 GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 8 GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ + + void +@@ -91,7 +91,7 @@ f4 (int i, ...) + /* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 0 GPR units and \[1-9\]\[0-9\]* FPR units" "stdarg" { target { powerpc*-*-linux* && { powerpc_fprs && ilp32 } } } } } */ + /* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 8 GPR units and 2" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 0 GPR units and 1 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 0 GPR units and 16 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 0 GPR units and 16 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ + /* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && ia32 } } } } */ +-/* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target ia64-*-* } } } */ ++/* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target ia64-*-* aarch64-apple-darwin* } } } */ + /* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save \[148\] GPR units" "stdarg" { target { powerpc*-*-* && lp64 } } } } */ +diff --git a/gcc/testsuite/gcc.dg/tree-ssa/stdarg-5.c b/gcc/testsuite/gcc.dg/tree-ssa/stdarg-5.c +index c8ad4fe320d..b0484f2f053 100644 +--- a/gcc/testsuite/gcc.dg/tree-ssa/stdarg-5.c ++++ b/gcc/testsuite/gcc.dg/tree-ssa/stdarg-5.c +@@ -25,7 +25,8 @@ f1 (int i, ...) + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save 0 GPR units and 0 FPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 || llp64 } } } } } } */ + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save all GPR units and 1" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save all GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save all GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save all GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ ++/* { dg-final { scan-tree-dump "f1: va_list escapes 0, needs to save all GPR units" "stdarg" { target aarch64-apple-darwin* } } } */ + + void + f2 (int i, ...) +@@ -39,7 +40,8 @@ f2 (int i, ...) + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save all GPR units and all FPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 || llp64 } } } } } } */ + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save all GPR units and 1" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save all GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save all GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save all GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ ++/* { dg-final { scan-tree-dump "f2: va_list escapes 0, needs to save all GPR units" "stdarg" { target aarch64-apple-darwin* } } } */ + + /* Here va_arg can be executed at most as many times as va_start. */ + void +@@ -58,7 +60,8 @@ f3 (int i, ...) + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 0 GPR units and 0 FPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 || llp64 } } } } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 32 GPR units and 1" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 1 GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 8 GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 8 GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ ++/* { dg-final { scan-tree-dump "f3: va_list escapes 0, needs to save 8 GPR units" "stdarg" { target aarch64-apple-darwin* } } } */ + + void + f4 (int i, ...) +@@ -77,7 +80,8 @@ f4 (int i, ...) + /* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 16 GPR units and 16 FPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 || llp64 } } } } } } */ + /* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 24 GPR units and 1" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 2 GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 24 GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 24 GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ ++/* { dg-final { scan-tree-dump "f4: va_list escapes 0, needs to save 24 GPR units" "stdarg" { target aarch64-apple-darwin* } } } */ + + void + f5 (int i, ...) +@@ -92,7 +96,8 @@ f5 (int i, ...) + /* { dg-final { scan-tree-dump "f5: va_list escapes 0, needs to save 16 GPR units and 0 FPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 || llp64 } } } } } } */ + /* { dg-final { scan-tree-dump "f5: va_list escapes 0, needs to save 32 GPR units and 1" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f5: va_list escapes 0, needs to save (4|2) GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f5: va_list escapes 0, needs to save 16 GPR units and 0 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f5: va_list escapes 0, needs to save 16 GPR units and 0 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ ++/* { dg-final { scan-tree-dump "f5: va_list escapes 0, needs to save 16 GPR units" "stdarg" { target aarch64-apple-darwin* } } } */ + + void + f6 (int i, ...) +@@ -107,7 +112,8 @@ f6 (int i, ...) + /* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save 8 GPR units and 32 FPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 || llp64 } } } } } } */ + /* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save 32 GPR units and 3" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save (3|2) GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save 8 GPR units and 32 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save 8 GPR units and 32 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ ++/* { dg-final { scan-tree-dump "f6: va_list escapes 0, needs to save 24 GPR units" "stdarg" { target aarch64-apple-darwin* } } } */ + + void + f7 (int i, ...) +@@ -122,4 +128,5 @@ f7 (int i, ...) + /* { dg-final { scan-tree-dump "f7: va_list escapes 0, needs to save 0 GPR units and 64 FPR units" "stdarg" { target { { i?86-*-* x86_64-*-* } && { ! { ia32 || llp64 } } } } } } */ + /* { dg-final { scan-tree-dump "f7: va_list escapes 0, needs to save 32 GPR units and 2" "stdarg" { target alpha*-*-linux* } } } */ + /* { dg-final { scan-tree-dump "f7: va_list escapes 0, needs to save 2 GPR units and 0 FPR units" "stdarg" { target s390*-*-linux* } } } */ +-/* { dg-final { scan-tree-dump "f7: va_list escapes 0, needs to save 0 GPR units and 64 FPR units" "stdarg" { target aarch64*-*-* } } } */ ++/* { dg-final { scan-tree-dump "f7: va_list escapes 0, needs to save 0 GPR units and 64 FPR units" "stdarg" { target { { aarch64*-*-* } && { ! aarch64-apple-darwin* } } } } } */ ++/* { dg-final { scan-tree-dump "f7: va_list escapes 0, needs to save 32 GPR units" "stdarg" { target aarch64-apple-darwin* } } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/aapcs64/aapcs64.exp b/gcc/testsuite/gcc.target/aarch64/aapcs64/aapcs64.exp +index 3e652c483c7..34907929bda 100644 +--- a/gcc/testsuite/gcc.target/aarch64/aapcs64/aapcs64.exp ++++ b/gcc/testsuite/gcc.target/aarch64/aapcs64/aapcs64.exp +@@ -25,6 +25,11 @@ if { ![istarget aarch64*-*-*] } then { + return + } + ++if { [istarget *-*-darwin*] } then { ++ # darwinpcs and mach-o will need different test mechanisms. ++ return ++} ++ + torture-init + set-torture-options $C_TORTURE_OPTIONS + set additional_flags "-W -Wall -Wno-abi" +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_dup.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_dup.c +index c42c7acbbe9..76917a6ff5b 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_dup.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_dup.c +@@ -1,4 +1,5 @@ + /* { dg-do assemble { target { aarch64*-*-* } } } */ ++/* { dg-require-effective-target aarch64_asm_bf16_ok } */ + /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ + /* { dg-options "-O2" } */ + /* { dg-add-options arm_v8_2a_bf16_neon } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_get.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_get.c +index 2193753ffbb..d29b222b032 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_get.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_get.c +@@ -1,4 +1,5 @@ + /* { dg-do assemble { target { aarch64*-*-* } } } */ ++/* { dg-require-effective-target aarch64_asm_bf16_ok } */ + /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ + /* { dg-add-options arm_v8_2a_bf16_neon } */ + /* { dg-additional-options "-save-temps" } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_reinterpret.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_reinterpret.c +index f5adf40c648..4e3a3d94416 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_reinterpret.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bf16_reinterpret.c +@@ -1,4 +1,5 @@ + /* { dg-do assemble { target { aarch64*-*-* } } } */ ++/* { dg-require-effective-target aarch64_asm_bf16_ok } */ + /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ + /* { dg-add-options arm_v8_2a_bf16_neon } */ + /* { dg-additional-options "-save-temps" } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvt-compile.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvt-compile.c +index 47af7c494d9..a2f415f67b7 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvt-compile.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvt-compile.c +@@ -1,4 +1,5 @@ + /* { dg-do assemble { target { aarch64*-*-* } } } */ ++/* { dg-require-effective-target aarch64_asm_bf16_ok } */ + /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ + /* { dg-add-options arm_v8_2a_bf16_neon } */ + /* { dg-additional-options "-save-temps" } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvt-nosimd.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvt-nosimd.c +index a914680937d..c6b2ef3e444 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvt-nosimd.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvt-nosimd.c +@@ -2,7 +2,7 @@ + /* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ + /* { dg-require-effective-target aarch64_asm_bf16_ok } */ + /* { dg-additional-options "-save-temps -march=armv8.2-a+bf16+nosimd" } */ +-/* { dg-final { check-function-bodies "**" "" {-O[^0]} } } */ ++/* { dg-final { check-function-bodies "**" "" {-O[^0]} { target { ! aarch64*-*-darwin* } } } } */ + + #include + +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvtnq2-untied.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvtnq2-untied.c +index 4b730e39d4e..fd2abadb457 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvtnq2-untied.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfcvtnq2-untied.c +@@ -1,8 +1,9 @@ + /* { dg-do assemble { target { aarch64*-*-* } } } */ ++/* { dg-require-effective-target aarch64_asm_bf16_ok } */ + /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ + /* { dg-add-options arm_v8_2a_bf16_neon } */ + /* { dg-additional-options "-save-temps" } */ +-/* { dg-final { check-function-bodies "**" "" {-O[^0]} } } */ ++/* { dg-final { check-function-bodies "**" "" {-O[^0]} { target { ! aarch64*-*-darwin* } } } } */ + /* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ + + #include +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfdot-1.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfdot-1.c +index ad51507731b..e57053d2193 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfdot-1.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfdot-1.c +@@ -1,8 +1,9 @@ + /* { dg-do assemble { target { aarch64*-*-* } } } */ ++/* { dg-require-effective-target aarch64_asm_bf16_ok } */ + /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ + /* { dg-add-options arm_v8_2a_bf16_neon } */ + /* { dg-additional-options "-save-temps" } */ +-/* { dg-final { check-function-bodies "**" "" {-O[^0]} } } */ ++/* { dg-final { check-function-bodies "**" "" {-O[^0]} { target { ! aarch64*-*-darwin* } } } } */ + /* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ + + #include +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfdot-2.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfdot-2.c +index ae0a953f7b4..9f5669a8974 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfdot-2.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfdot-2.c +@@ -3,7 +3,7 @@ + /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ + /* { dg-add-options arm_v8_2a_bf16_neon } */ + /* { dg-additional-options "-mbig-endian --save-temps" } */ +-/* { dg-final { check-function-bodies "**" "" {-O[^0]} } } */ ++/* { dg-final { check-function-bodies "**" "" {-O[^0]} { target { ! aarch64*-*-darwin* } } } } */ + /* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ + + #include +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfmlalbt-compile.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfmlalbt-compile.c +index 9810e4ba374..315cabd464b 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfmlalbt-compile.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfmlalbt-compile.c +@@ -1,8 +1,9 @@ + /* { dg-do assemble { target { aarch64*-*-* } } } */ ++/* { dg-require-effective-target aarch64_asm_bf16_ok } */ + /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ + /* { dg-add-options arm_v8_2a_bf16_neon } */ + /* { dg-additional-options "-save-temps" } */ +-/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */ ++/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" { target { ! aarch64*-*-darwin* } } } } */ + + #include + +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfmmla-compile.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfmmla-compile.c +index 0aaa69f0037..ddc391b1332 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfmmla-compile.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/bfmmla-compile.c +@@ -1,8 +1,9 @@ + /* { dg-do assemble { target { aarch64*-*-* } } } */ ++/* { dg-require-effective-target aarch64_asm_bf16_ok } */ + /* { dg-require-effective-target arm_v8_2a_bf16_neon_ok } */ + /* { dg-add-options arm_v8_2a_bf16_neon } */ + /* { dg-additional-options "-save-temps" } */ +-/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" } } */ ++/* { dg-final { check-function-bodies "**" "" "-DCHECK_ASM" { target { ! aarch64*-*-darwin* } } } } */ + + #include + +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vdot-3-1.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vdot-3-1.c +index ac4f821e771..978eac29815 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vdot-3-1.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vdot-3-1.c +@@ -1,8 +1,9 @@ + /* { dg-do assemble { target { aarch64*-*-* } } } */ ++/* { dg-require-effective-target arm_v8_2a_i8mm_neon_hw } */ + /* { dg-require-effective-target arm_v8_2a_i8mm_ok } */ + /* { dg-add-options arm_v8_2a_i8mm } */ + /* { dg-additional-options "-save-temps" } */ +-/* { dg-final { check-function-bodies "**" "" {-O[^0]} } } */ ++/* { dg-final { check-function-bodies "**" "" {-O[^0]} { target { ! aarch64*-*-darwin* } } } } */ + /* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ + + #include +diff --git a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vdot-3-2.c b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vdot-3-2.c +index 61c7c51f5ec..f84ed68e2f7 100644 +--- a/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vdot-3-2.c ++++ b/gcc/testsuite/gcc.target/aarch64/advsimd-intrinsics/vdot-3-2.c +@@ -3,7 +3,7 @@ + /* { dg-require-effective-target arm_v8_2a_i8mm_ok } */ + /* { dg-add-options arm_v8_2a_i8mm } */ + /* { dg-additional-options "-mbig-endian -save-temps" } */ +-/* { dg-final { check-function-bodies "**" "" {-O[^0]} } } */ ++/* { dg-final { check-function-bodies "**" "" {-O[^0]} { target { ! aarch64*-*-darwin* } } } } */ + /* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */ + + #include +diff --git a/gcc/testsuite/gcc.target/aarch64/arm_align_max_pwr.c b/gcc/testsuite/gcc.target/aarch64/arm_align_max_pwr.c +index ffa4d229922..38b9ef01eb7 100644 +--- a/gcc/testsuite/gcc.target/aarch64/arm_align_max_pwr.c ++++ b/gcc/testsuite/gcc.target/aarch64/arm_align_max_pwr.c +@@ -19,5 +19,7 @@ dummy () + return result; + } + +-/* { dg-final { scan-assembler-times "zero\t4" 2 } } */ +-/* { dg-final { scan-assembler "zero\t268435452" } } */ ++/* { dg-final { scan-assembler-times "zero\t4" 2 { target { ! *-*-darwin* } } } } */ ++/* { dg-final { scan-assembler "zero\t268435452" { target { ! *-*-darwin*} } } } */ ++/* { dg-final { scan-assembler-times ".zerofill __DATA,__bss,_y,4,28" 1 { target { *-*-darwin* } } } } */ ++/* { dg-final { scan-assembler-times ".zerofill __DATA,__bss,_x,4,28" 1 { target { *-*-darwin* } } } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-2.c b/gcc/testsuite/gcc.target/aarch64/auto-init-2.c +index 375befd325b..3a0387a5952 100644 +--- a/gcc/testsuite/gcc.target/aarch64/auto-init-2.c ++++ b/gcc/testsuite/gcc.target/aarch64/auto-init-2.c +@@ -12,11 +12,11 @@ enum E { + N3 + }; + +-extern void bar (char, short, int, enum E, long, long long, int *, bool); ++extern void bar (unsigned char, short, int, enum E, long, long long, int *, bool); + + void foo() + { +- char temp1; ++ unsigned char temp1; + short temp2; + int temp3; + enum E temp4; +diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-3.c b/gcc/testsuite/gcc.target/aarch64/auto-init-3.c +index 7008f76b294..85a4e4daeb6 100644 +--- a/gcc/testsuite/gcc.target/aarch64/auto-init-3.c ++++ b/gcc/testsuite/gcc.target/aarch64/auto-init-3.c +@@ -2,13 +2,19 @@ + /* { dg-do compile } */ + /* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */ + +-long double result; ++#ifdef __APPLE__ ++# define TYPE _Float128 ++#else ++# define TYPE long double ++#endif + +-long double foo() ++TYPE result; ++ ++TYPE foo() + { + float temp1; + double temp2; +- long double temp3; ++ TYPE temp3; + + result = temp1 + temp2 + temp3; + return result; +diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-4.c b/gcc/testsuite/gcc.target/aarch64/auto-init-4.c +index 10197045b4c..0c6840ba224 100644 +--- a/gcc/testsuite/gcc.target/aarch64/auto-init-4.c ++++ b/gcc/testsuite/gcc.target/aarch64/auto-init-4.c +@@ -2,13 +2,19 @@ + /* { dg-do compile } */ + /* { dg-options "-O -ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */ + +-long double result; ++#ifdef __APPLE__ ++# define TYPE _Float128 ++#else ++# define TYPE long double ++#endif + +-long double foo() ++TYPE result; ++ ++TYPE foo() + { + float temp1; + double temp2; +- long double temp3; ++ TYPE temp3; + + result = temp1 + temp2 + temp3; + return result; +diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-5.c b/gcc/testsuite/gcc.target/aarch64/auto-init-5.c +index ac69ac3df82..0dda3c201d3 100644 +--- a/gcc/testsuite/gcc.target/aarch64/auto-init-5.c ++++ b/gcc/testsuite/gcc.target/aarch64/auto-init-5.c +@@ -2,14 +2,19 @@ + /* { dg-do compile } */ + /* { dg-options "-ftrivial-auto-var-init=zero" } */ + ++#ifdef __APPLE__ ++# define TYPE _Float128 ++#else ++# define TYPE long double ++#endif + +-_Complex long double result; ++_Complex TYPE result; + +-_Complex long double foo() ++_Complex TYPE foo() + { + _Complex float temp1; + _Complex double temp2; +- _Complex long double temp3; ++ _Complex TYPE temp3; + + result = temp1 + temp2 + temp3; + return result; +diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-6.c b/gcc/testsuite/gcc.target/aarch64/auto-init-6.c +index 0456c66f496..23323115a11 100644 +--- a/gcc/testsuite/gcc.target/aarch64/auto-init-6.c ++++ b/gcc/testsuite/gcc.target/aarch64/auto-init-6.c +@@ -2,14 +2,19 @@ + /* { dg-do compile } */ + /* { dg-options "-ftrivial-auto-var-init=pattern" } */ + ++#ifdef __APPLE__ ++# define TYPE _Float128 ++#else ++# define TYPE long double ++#endif + +-_Complex long double result; ++_Complex TYPE result; + +-_Complex long double foo() ++_Complex TYPE foo() + { + _Complex float temp1; + _Complex double temp2; +- _Complex long double temp3; ++ _Complex TYPE temp3; + + result = temp1 + temp2 + temp3; + return result; +diff --git a/gcc/testsuite/gcc.target/aarch64/c-output-template-2.c b/gcc/testsuite/gcc.target/aarch64/c-output-template-2.c +index ced96d04542..86e4f5fa82c 100644 +--- a/gcc/testsuite/gcc.target/aarch64/c-output-template-2.c ++++ b/gcc/testsuite/gcc.target/aarch64/c-output-template-2.c +@@ -6,4 +6,4 @@ test (void) + __asm__ ("@ %c0" : : "S" (test)); + } + +-/* { dg-final { scan-assembler "@ test" } } */ ++/* { dg-final { scan-assembler "@ _?test" } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/c-output-template-3.c b/gcc/testsuite/gcc.target/aarch64/c-output-template-3.c +index 8bde4cbeb0c..4531a381518 100644 +--- a/gcc/testsuite/gcc.target/aarch64/c-output-template-3.c ++++ b/gcc/testsuite/gcc.target/aarch64/c-output-template-3.c +@@ -7,4 +7,4 @@ test (void) + __asm__ ("@ %c0" : : "S" (&test + 4)); + } + +-/* { dg-final { scan-assembler "@ test\\+4" } } */ ++/* { dg-final { scan-assembler "@ _?test\\+4" } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/c-output-template-4.c b/gcc/testsuite/gcc.target/aarch64/c-output-template-4.c +index c5a93915af1..800d52bfab8 100644 +--- a/gcc/testsuite/gcc.target/aarch64/c-output-template-4.c ++++ b/gcc/testsuite/gcc.target/aarch64/c-output-template-4.c +@@ -7,4 +7,4 @@ test (void) + __asm__ ("@ %c0" : : "S" (&test + 4)); + } + +-/* { dg-final { scan-assembler "@ test\\+4" } } */ ++/* { dg-final { scan-assembler "@ _?test\\+4" } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/cpymem-size.c b/gcc/testsuite/gcc.target/aarch64/cpymem-size.c +index 4a6f2495d22..b8ef4745c6d 100644 +--- a/gcc/testsuite/gcc.target/aarch64/cpymem-size.c ++++ b/gcc/testsuite/gcc.target/aarch64/cpymem-size.c +@@ -6,7 +6,7 @@ + /* + ** cpy_127: + ** mov (w|x)2, 127 +-** b memcpy ++** b _?memcpy + */ + void + cpy_127 (char *out, char *in) +@@ -17,7 +17,7 @@ cpy_127 (char *out, char *in) + /* + ** cpy_128: + ** mov (w|x)2, 128 +-** b memcpy ++** b _?memcpy + */ + void + cpy_128 (char *out, char *in) +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/aarch64-darwin.exp b/gcc/testsuite/gcc.target/aarch64/darwin/aarch64-darwin.exp +new file mode 100644 +index 00000000000..b0b7f49aede +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/aarch64-darwin.exp +@@ -0,0 +1,46 @@ ++# Specific tests for the darwinpcs and codegen. ++# Copyright (C) GNU Toolchain Authors ++# Contributed by Iain Sandoe ++# ++# This file is part of GCC. ++# ++# GCC 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 3, or (at your option) ++# any later version. ++# ++# GCC is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GCC; see the file COPYING3. If not see ++# . */ ++ ++# GCC testsuite that uses the `dg.exp' driver. ++ ++# Exit immediately if this isn't aarch64-darwin. ++ ++if { ![istarget aarch64*-*-darwin*] } then { ++ return ++} ++ ++# Load support procs. ++load_lib gcc-dg.exp ++ ++# If a testcase doesn't have special options, use these. ++global DEFAULT_CFLAGS ++if ![info exists DEFAULT_CFLAGS] then { ++ set DEFAULT_CFLAGS " -ansi -pedantic-errors" ++} ++ ++# Initialize `dg'. ++dg-init ++ ++# Main loop. ++dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \ ++ "" $DEFAULT_CFLAGS ++ ++# All done. ++dg-finish +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/complex-in-regs.c b/gcc/testsuite/gcc.target/aarch64/darwin/complex-in-regs.c +new file mode 100644 +index 00000000000..974f02ca2ec +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/complex-in-regs.c +@@ -0,0 +1,103 @@ ++/* { dg-do compile } */ ++/* we need this for complex and gnu initializers. */ ++/* { dg-options "-std=gnu99 " } */ ++/* We use the sections anchors to make the code easier to match. */ ++/* { dg-additional-options " -O -fsection-anchors -fno-schedule-insns -fno-schedule-insns2 " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++ ++__attribute__((__noinline__)) ++_Complex char ++cc_regs_fun (_Complex char r0, _Complex char r1, ++ _Complex char r2, _Complex char r3, ++ _Complex char r4, _Complex char r5, ++ _Complex char r6, _Complex char r7); ++ ++/* ++**call_cc_regs_fun: ++** ... ++** ldrh w7, \[x0\] ++** ldrh w6, \[x0, 2\] ++** ldrh w5, \[x0, 4\] ++** ldrh w4, \[x0, 6\] ++** ldrh w3, \[x0, 8\] ++** ldrh w2, \[x0, 10\] ++** ldrh w1, \[x0, 12\] ++** ldrh w0, \[x0, 14]\ ++** bl _cc_regs_fun ++** ... ++*/ ++ ++_Complex char ++call_cc_regs_fun (void) ++{ ++ return cc_regs_fun ((_Complex char) (1 + 1i), (_Complex char) (2 + 2i), ++ (_Complex char) (3 + 3i), (_Complex char) (4 + 4i), ++ (_Complex char) (5 + 5i), (_Complex char) (6 + 6i), ++ (_Complex char) (7 + 7i), (_Complex char) (8 + 8i)); ++} ++ ++ ++__attribute__((__noinline__)) ++_Complex short ++cs_regs_fun (_Complex short r0, _Complex short r1, ++ _Complex short r2, _Complex short r3, ++ _Complex short r4, _Complex short r5, ++ _Complex short r6, _Complex short r7); ++ ++/* ++**call_cs_regs_fun: ++** ... ++** ldr w7, \[x0, 16\] ++** ldr w6, \[x0, 20\] ++** ldr w5, \[x0, 24\] ++** ldr w4, \[x0, 28\] ++** ldr w3, \[x0, 32\] ++** ldr w2, \[x0, 36\] ++** ldr w1, \[x0, 40\] ++** ldr w0, \[x0, 44\] ++** bl _cs_regs_fun ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++_Complex short ++call_cs_regs_fun (void) ++{ ++ return cs_regs_fun ((_Complex short) (1 + 1i), (_Complex short) (2 + 2i), ++ (_Complex short) (3 + 3i), (_Complex short) (4 + 4i), ++ (_Complex short) (5 + 5i), (_Complex short) (6 + 6i), ++ (_Complex short) (7 + 7i), (_Complex short) (8 + 8i)); ++} ++ ++__attribute__((__noinline__)) ++_Complex int ++ci_regs_fun (_Complex int r0, _Complex int r1, ++ _Complex int r2, _Complex int r3, ++ _Complex int r4, _Complex int r5, ++ _Complex int r6, _Complex int r7); ++ ++/* ++**call_ci_regs_fun: ++** ... ++** ldr x7, \[x0, 48\] ++** ldr x6, \[x0, 56\] ++** ldr x5, \[x0, 64\] ++** ldr x4, \[x0, 72\] ++** ldr x3, \[x0, 80\] ++** ldr x2, \[x0, 88\] ++** ldr x1, \[x0, 96\] ++** ldr x0, \[x0, 104\] ++** bl _ci_regs_fun ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++_Complex int ++call_ci_regs_fun (void) ++{ ++ return ci_regs_fun ((_Complex int) (1 + 1i), (_Complex int) (2 + 2i), ++ (_Complex int) (3 + 3i), (_Complex int) (4 + 4i), ++ (_Complex int) (5 + 5i), (_Complex int) (6 + 6i), ++ (_Complex int) (7 + 7i), (_Complex int) (8 + 8i)); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d1.c b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d1.c +new file mode 100644 +index 00000000000..e2dd574fac7 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d1.c +@@ -0,0 +1,54 @@ ++/* { dg-do compile } */ ++/* we need this for the empty struct. */ ++/* { dg-options "-std=gnu99 " } */ ++/* { dg-additional-options "-O -fno-schedule-insns -fno-schedule-insns2 " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++/* Make sure we do no consume any registers in passing zero-sized entities */ ++ ++typedef struct es {} Empty; ++ ++__attribute__((__noinline__)) void ++use_no_regs (int a, Empty b, int c, Empty d, Empty e, int f); ++ ++/* ++**call_use_no_regs: ++** ... ++** mov w2, 3 ++** mov w1, 2 ++** mov w0, 1 ++** bl _use_no_regs ++** ... ++*/ ++ ++__attribute__((__noinline__)) void ++call_use_no_regs (void) ++{ ++ Empty e; ++ use_no_regs (1, e, 2, e, e, 3); ++} ++ ++/* Make sure we consume no stack in passing zero-sized entities. */ ++ ++/* ++**call_use_no_stack: ++** ... ++** mov w[0-9]+, 108 ++** strb w[0-9]+, \[sp, 1\] ++** mov w[0-9]+, 106 ++** strb w[0-9]+, \[sp\] ++** ... ++** bl _use_no_stack ++** ... ++*/ ++ ++__attribute__((__noinline__)) void ++use_no_stack (int a, int b, int c, int d, int e, int f, int g, int h, ++ Empty i, char j, Empty k, char l); ++ ++void ++call_use_no_stack (void) ++{ ++ Empty e; ++ use_no_stack (0, 1, 2, 3, 4, 5, 6, 7, e, 'j', e, 'l'); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-00.c b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-00.c +new file mode 100644 +index 00000000000..bd76856308b +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-00.c +@@ -0,0 +1,126 @@ ++/* { dg-do compile } */ ++/* { dg-additional-options " -O -fno-schedule-insns -fno-schedule-insns2 " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++/* In each case we consume the parm registers with 8 ints, forcing ++ the test values to be spilled to the stack. */ ++ ++/* The important thing here is that the chars are assigned to the stack ++ * with no padding - so that they occupy bytes 0-8. */ ++ ++/* ++**call_char_packing: ++** ... ++** mov w[0-9]+, 113 ++** strb w[0-9]+, \[sp, 8\] ++** mov w[0-9]+, 112 ++** strb w[0-9]+, \[sp, 7\] ++** mov w[0-9]+, 111 ++** strb w[0-9]+, \[sp, 6\] ++** mov w[0-9]+, 110 ++** strb w[0-9]+, \[sp, 5\] ++** mov w[0-9]+, 109 ++** strb w[0-9]+, \[sp, 4\] ++** mov w[0-9]+, 108 ++** strb w[0-9]+, \[sp, 3\] ++** mov w[0-9]+, 107 ++** strb w[0-9]+, \[sp, 2\] ++** mov w[0-9]+, 106 ++** strb w[0-9]+, \[sp, 1\] ++** mov w[0-9]+, 105 ++** strb w[0-9]+, \[sp\] ++** mov w7, 7 ++** mov w6, 6 ++** mov w5, 5 ++** mov w4, 4 ++** mov w3, 3 ++** mov w2, 2 ++** mov w1, 1 ++** mov w0, 0 ++** bl _char_packing ++** ... ++*/ ++ ++__attribute__((__noinline__)) void ++char_packing (int a, int b, int c, int d, int e, int f, int g, int h, ++ char i, char j, char k, char l, ++ char m, char n, char o, char p, ++ char q); ++ ++void call_char_packing (void) ++{ ++ char_packing (0, 1, 2, 3, 4, 5, 6, 7, ++ 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q'); ++} ++ ++/* Here we should occupy the first 7 short words on the stack. */ ++ ++/* ++**call_short_packing: ++** ... ++** mov w[0-9]+, 12 ++** strh w[0-9]+, \[sp, 8\] ++** mov w[0-9]+, 11 ++** strh w[0-9]+, \[sp, 6\] ++** mov w[0-9]+, 10 ++** strh w[0-9]+, \[sp, 4\] ++** mov w[0-9]+, 9 ++** strh w[0-9]+, \[sp, 2\] ++** mov w[0-9]+, 8 ++** strh w[0-9]+, \[sp\] ++** mov w7, 7 ++** mov w6, 6 ++** mov w5, 5 ++** mov w4, 4 ++** mov w3, 3 ++** mov w2, 2 ++** mov w1, 1 ++** mov w0, 0 ++** bl _short_packing ++** ... ++*/ ++ ++__attribute__((__noinline__)) void ++short_packing (int a, int b, int c, int d, int e, int f, int g, int h, ++ short i, short j, short k, short l, ++ short m); ++ ++void call_short_packing (void) ++{ ++ short_packing (0, 1, 2, 3, 4, 5, 6, 7, ++ 8, 9, 10, 11, 12); ++} ++ ++/* Here we should occupy the first 3 ints on the stack. */ ++ ++/* ++**call_int_packing: ++** ... ++** mov w[0-9]+, 10 ++** str w[0-9]+, \[sp, 8\] ++** mov w[0-9]+, 9 ++** str w[0-9]+, \[sp, 4\] ++** mov w[0-9]+, 8 ++** str w[0-9]+, \[sp\] ++** mov w7, 7 ++** mov w6, 6 ++** mov w5, 5 ++** mov w4, 4 ++** mov w3, 3 ++** mov w2, 2 ++** mov w1, 1 ++** mov w0, 0 ++** bl _int_packing ++** ... ++*/ ++ ++__attribute__((__noinline__)) void ++int_packing (int a, int b, int c, int d, int e, int f, int g, int h, ++ int i, int j, int k); ++ ++void call_int_packing (void) ++{ ++ int_packing (0, 1, 2, 3, 4, 5, 6, 7, ++ 8, 9, 10); ++} ++ +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-01.c b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-01.c +new file mode 100644 +index 00000000000..d21fd551b4a +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-01.c +@@ -0,0 +1,115 @@ ++/* { dg-do compile } */ ++/* { dg-additional-options " -O -fno-schedule-insns -fno-schedule-insns2 " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++/* In each case we consume the parm registers with 8 ints, forcing ++ the test values to be spilled to the stack. */ ++ ++/* char short char short - everything on 2byte boundaries */ ++ ++/* ++**call_c_s_packing: ++** ... ++** mov w[0-9]+, 109 ++** strb w[0-9]+, \[sp, 8\] ++** mov w[0-9]+, 9 ++** strh w[0-9]+, \[sp, 6\] ++** mov w[0-9]+, 107 ++** strb w[0-9]+, \[sp, 4\] ++** mov w[0-9]+, 8 ++** strh w[0-9]+, \[sp, 2\] ++** mov w[0-9]+, 105 ++** strb w[0-9]+, \[sp\] ++** mov w7, 7 ++** mov w6, 6 ++** mov w5, 5 ++** mov w4, 4 ++** mov w3, 3 ++** mov w2, 2 ++** mov w1, 1 ++** mov w0, 0 ++** bl _c_s_packing ++** ... ++*/ ++ ++__attribute__((__noinline__)) void ++c_s_packing (int a, int b, int c, int d, int e, int f, int g, int h, ++ char i, short j, char k, short l, ++ char m); ++ ++void call_c_s_packing (void) ++{ ++ c_s_packing (0, 1, 2, 3, 4, 5, 6, 7, ++ 'i', 8 , 'k', 9, 'm'); ++} ++ ++/* ++**call_s_c_packing: ++** ... ++** mov w[0-9]+, 109 ++** strb w[0-9]+, \[sp, 7\] ++** mov w[0-9]+, 108 ++** strb w[0-9]+, \[sp, 6\] ++** mov w[0-9]+, 9 ++** strh w[0-9]+, \[sp, 4\] ++** mov w[0-9]+, 106 ++** strb w[0-9]+, \[sp, 2\] ++** mov w[0-9]+, 8 ++** strh w[0-9]+, \[sp\] ++** mov w7, 7 ++** mov w6, 6 ++** mov w5, 5 ++** mov w4, 4 ++** mov w3, 3 ++** mov w2, 2 ++** mov w1, 1 ++** mov w0, 0 ++** bl _s_c_packing ++** ... ++*/ ++ ++__attribute__((__noinline__)) void ++s_c_packing (int a, int b, int c, int d, int e, int f, int g, int h, ++ short i, char j, short k, char l, ++ char m); ++ ++void call_s_c_packing (void) ++{ ++ s_c_packing (0, 1, 2, 3, 4, 5, 6, 7, ++ 8, 'j' , 9, 'l', 'm'); ++} ++ ++/* 0, 2, 4, 0 */ ++ ++/* ++**call_csi_packing: ++** ... ++** mov w[0-9]+, 108 ++** strb w[0-9]+, \[sp, 8\] ++** mov w[0-9]+, 9 ++** str w[0-9]+, \[sp, 4\] ++** mov w[0-9]+, 8 ++** strh w[0-9]+, \[sp, 2\] ++** mov w[0-9]+, 105 ++** strb w[0-9]+, \[sp\] ++** mov w7, 7 ++** mov w6, 6 ++** mov w5, 5 ++** mov w4, 4 ++** mov w3, 3 ++** mov w2, 2 ++** mov w1, 1 ++** mov w0, 0 ++** bl _csi_packing ++** ... ++*/ ++ ++__attribute__((__noinline__)) void ++csi_packing (int a, int b, int c, int d, int e, int f, int g, int h, ++ char i, short j, int k, char l); ++ ++void call_csi_packing (void) ++{ ++ csi_packing (0, 1, 2, 3, 4, 5, 6, 7, ++ 'i', 8 , 9, 'l'); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-02.c b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-02.c +new file mode 100644 +index 00000000000..55e5acdaf41 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-02.c +@@ -0,0 +1,75 @@ ++/* { dg-do compile } */ ++/* we need this for complex literals. */ ++/* { dg-options "-std=gnu99 " } */ ++/* { dg-additional-options "-O -fsection-anchors -fno-schedule-insns -fno-schedule-insns2 " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++ ++__attribute__((__noinline__)) void ++c_cc_packing (int a, int b, int c, int d, int e, int f, int g, int h, ++ _Complex char i, _Complex char j); ++ ++/* We check that these values are not packed on the stack. ++**call_c_cc_packing: ++** ... ++** ldrh w[0-9]+, \[x[0-9]+\] ++** strh w[0-9]+, \[sp, 8\] ++** ldrh w[0-9]+, \[x[0-9]+, 2\] ++** strh w[0-9]+, \[sp\] ++** ... ++** bl _c_cc_packing ++** ... ++*/ ++ ++void ++call_c_cc_packing (void) ++{ ++ c_cc_packing (0, 1, 2, 3, 4, 5, 6, 7, ++ (_Complex char) (1 + 1i),(_Complex char) (2 + 2i)); ++} ++ ++ ++__attribute__((__noinline__)) void ++c_cs_packing (int a, int b, int c, int d, int e, int f, int g, int h, ++ _Complex short i, _Complex short j); ++ ++/* ++**call_c_cs_packing: ++** ... ++** ldr w[0-9]+, \[x[0-9]+, 4\] ++** str w[0-9]+, \[sp, 8\] ++** ldr w[0-9]+, \[x[0-9]+, 8\] ++** str w[0-9]+, \[sp\] ++** ... ++** bl _c_cs_packing ++** ... ++*/ ++ ++void ++call_c_cs_packing (void) ++{ ++ c_cs_packing (0, 1, 2, 3, 4, 5, 6, 7, ++ (_Complex short) (1 + 1i),(_Complex short) (2 + 2i)); ++} ++ ++void c_ci_packing (int a, int b, int c, int d, int e, int f, int g, int h, ++ _Complex int i, _Complex int j); ++ ++/* ++**call_c_ci_packing: ++** ... ++** ldr x[0-9]+, \[x[0-9]+, 12\] ++** str x[0-9]+, \[sp, 8\] ++** ldr x[0-9]+, \[x[0-9]+, 20\] ++** str x[0-9]+, \[sp\] ++** ... ++** bl _c_ci_packing ++** ... ++*/ ++ ++void ++call_c_ci_packing (void) ++{ ++ c_ci_packing (0, 1, 2, 3, 4, 5, 6, 7, ++ (_Complex int) (1 + 1i),(_Complex int) (2 + 2i)); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-03.c b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-03.c +new file mode 100644 +index 00000000000..b0d2593dfd7 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-03.c +@@ -0,0 +1,67 @@ ++/* { dg-do compile } */ ++ ++/* { dg-additional-options "-O -fno-schedule-insns -fno-schedule-insns2 " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++typedef union u { char a; short b; } U; ++typedef struct sf { float a; float b; float c;} SF; ++ ++__attribute__((__noinline__)) void ++u_packing (int a, int b, int c, int d, int e, int f, int g, int h, ++ U i, U j); ++ ++/* We check that these values are not packed on the stack. ++**call_u_packing: ++** ... ++** strh w[0-9]+, \[sp, 8\] ++** strh w[0-9]+, \[sp\] ++** ... ++** bl _u_packing ++** ... ++*/ ++ ++void ++call_u_packing (void) ++{ ++ U x = { 'a' }; ++ u_packing (0, 1, 2, 3, 4, 5, 6, 7, x, x); ++} ++ ++/* But a homogeneous float aggregate is treated as if it were the contained ++ floats. */ ++ ++__attribute__((__noinline__)) void ++sf_packing (float a, float b, float c, float d, ++ float e, float f, float g, float h, ++ SF i, SF j); ++ ++/* So the stores to sp+12 and 20 pack the floats onto the stack. ++**call_sf_packing: ++** ... ++** fmov s1, 1.0e\+0 ++** str s1, \[sp, 48\] ++** fmov s2, 2.0e\+0 ++** str s2, \[sp, 52\] ++** mov w[0-9]+, 1077936128 ++** ldr x[0-9]+, \[sp, 48\] ++** str x[0-9]+, \[sp, 12\] ++** str w[0-9]+, \[sp, 20\] ++** str x[0-9]+, \[sp\] ++** str w[0-9]+, \[sp, 8\] ++** fmov s7, 7.0e\+0 ++** fmov s6, 6.0e\+0 ++** fmov s5, 5.0e\+0 ++** fmov s4, 4.0e\+0 ++** fmov s3, 3.0e\+0 ++** movi v0.2s, #0 ++** bl _sf_packing ++** ... ++*/ ++ ++void ++call_sf_packing (void) ++{ ++ SF A = {1.0F, 2.0F, 3.0F}; ++ sf_packing (0.0F, 1.0F, 2.0F, 3.0F, 4.0F, 5.0F, 6.0F, 7.0F, ++ A, A); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-04.c b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-04.c +new file mode 100644 +index 00000000000..33c60c69b78 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d2-04.c +@@ -0,0 +1,66 @@ ++/* { dg-do compile } */ ++ ++/* { dg-additional-options "-O -fno-schedule-insns -fno-schedule-insns2 " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++typedef short v2hi __attribute__ ((vector_size (4))); ++typedef int v4si __attribute__ ((vector_size (16))); ++ ++v4si t; ++int al = __alignof__ (t); ++ ++__attribute__((__noinline__)) void ++v2hi_packing (v2hi a, v2hi b, v2hi c, v2hi d, v2hi e, v2hi f, v2hi g, v2hi h, ++ v2hi i, v2hi j); ++ ++/* We check that v2hi is packed on the stack. ++**call_v2hi_packing: ++** ... ++** mov w[0-9]+, 1 ++** movk w[0-9]+, 0x2, lsl 16 ++** str w[0-9]+, \[sp, 4\] ++** str w[0-9]+, \[sp\] ++** mov w7, w[0-9]+ ++** mov w6, w[0-9]+ ++** mov w5, w[0-9]+ ++** mov w4, w[0-9]+ ++** mov w3, w[0-9]+ ++** mov w2, w[0-9]+ ++** mov w1, w[0-9]+ ++** bl _v2hi_packing ++** ... ++*/ ++ ++void ++call_v2hi_packing (void) ++{ ++ v2hi x = {1,2}; ++ v2hi_packing (x, x, x, x, x, x, x, x, x, x); ++} ++ ++ ++__attribute__((__noinline__)) void ++v4si_packing (int r0, int r1, int r2, int r3, int r4, int r5, int r6, int r7, ++ v4si a, v4si b, v4si c, v4si d, v4si e, v4si f, v4si g, v4si h, ++ int stack, v4si i, v4si j); ++ ++/* Test that we align a 16b vector on the stack. ++**call_v4si_packing: ++** ... ++** adrp x0, lC0@PAGE ++** ldr q[0-9]+, \[x[0-9]+, #lC0@PAGEOFF\] ++** str q[0-9]+, \[sp, 32\] ++** str q[0-9]+, \[sp, 16\] ++** mov w[0-9]+, 42 ++** str w[0-9]+, \[sp\] ++** ... ++** bl _v4si_packing ++** ... ++*/ ++ ++void ++call_v4si_packing (void) ++{ ++ v4si x = {3,1,2,4}; ++ v4si_packing (0, 1, 2, 3, 4, 5, 6, 7, x, x, x, x, x, x, x, x, 42, x, x); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d3.c b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d3.c +new file mode 100644 +index 00000000000..21c6b696b7c +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d3.c +@@ -0,0 +1,40 @@ ++/* { dg-do compile } */ ++/* { dg-additional-options "-O " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++/* This will fail, because of issue #74 ++**foo: ++** cmp w0, w1 ++** cset w0, eq ++** ret ++*/ ++ ++__attribute__((__noinline__)) ++int ++foo (char a, unsigned char b) ++{ ++ return a == b ? 1 : 0; ++} ++ ++__attribute__((__noinline__)) ++int ++bar (short a, unsigned short b) ++{ ++ return a == b ? 1 : 0; ++} ++ ++void pop (char *, unsigned char *, short *, unsigned short *); ++ ++int main () ++{ ++ char a; ++ unsigned char b; ++ short c; ++ unsigned short d; ++ int result; ++ pop (&a, &b, &c, &d); ++ ++ result = foo (a, b); ++ result += bar (c, d); ++ return result; ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d4.c b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d4.c +new file mode 100644 +index 00000000000..2aab48260f4 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/darwinpcs-d4.c +@@ -0,0 +1,62 @@ ++/* { dg-do compile } */ ++/* we need this for __int128. */ ++/* { dg-options "-std=gnu99 " } */ ++/* { dg-additional-options "-O -fno-schedule-insns -fno-schedule-insns2 " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++/* we should use x0, x1 and x2 - not skip x1. ++**foo: ++** eor x0, x0, x1 ++** orr x0, x0, x2 ++** cmp x0, 0 ++** cset w0, eq ++** ret ++*/ ++ ++__attribute__((__noinline__)) ++int ++foo (unsigned long long x,unsigned __int128 y) ++{ ++ return x == y ? 1 : 0; ++} ++ ++/* we should use x0, x1 and x2. ++**bar: ++** eor x2, x2, x0 ++** orr x2, x2, x1 ++** cmp x2, 0 ++** cset w0, eq ++** ret ++*/ ++ ++__attribute__((__noinline__)) ++int ++bar (unsigned __int128 y, unsigned long long x) ++{ ++ return x == y ? 1 : 0; ++} ++ ++int fooo (unsigned long long x, unsigned __int128 y); ++int baro (unsigned __int128 y, unsigned long long x); ++ ++/* we should use x0, x1 and x2 in both calls. ++**main: ++** ... ++** mov x1, 25 ++** mov x2, 0 ++** mov x0, 10 ++** bl _fooo ++** mov x2, 10 ++** mov x0, 25 ++** mov x1, 0 ++** bl _baro ++** ... ++*/ ++ ++int main () ++{ ++ unsigned long long x = 10; ++ unsigned __int128 y = 25; ++ int r = fooo (x, y); ++ r += baro (y, x); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/float128-00.c b/gcc/testsuite/gcc.target/aarch64/darwin/float128-00.c +new file mode 100644 +index 00000000000..29aec80fbaa +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/float128-00.c +@@ -0,0 +1,38 @@ ++ ++/* we need this for _Float128. */ ++/* { dg-options "-std=gnu99 " } */ ++/* We use the sections anchors to make the code easier to match. */ ++/* { dg-additional-options " -O2 -fsection-anchors " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++/* we should just pass q0 and q1 through ++**foo: ++** ... ++** bl ___addtf3 ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++_Float128 ++foo (_Float128 a, _Float128 b) ++{ ++ return a + b; ++} ++ ++ ++/* we should just load q0 and q1 ++**call_foo: ++** ... ++** ldr q1, \[x[0-9]+\] ++** ... ++** ldr q0, \[x[0-9]+\] ++** b _foo ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++_Float128 ++call_foo (void) ++{ ++ return foo (1.0, 2.0); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/homogeneous-aggr.c b/gcc/testsuite/gcc.target/aarch64/darwin/homogeneous-aggr.c +new file mode 100644 +index 00000000000..bee97557a4d +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/homogeneous-aggr.c +@@ -0,0 +1,25 @@ ++/* { dg-do compile } */ ++/* { dg-additional-options "-O " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++typedef struct sf { float a; float b; float c;} SF; ++ ++__attribute__((__noinline__)) void ++hmg_f (SF a); ++ ++/* we should use registers for each item ++**call_hmg_f: ++** ... ++** fmov s0, 1.0e\+0 ++** fmov s1, 2.0e\+0 ++** fmov s2, 3.0e\+0 ++** bl _hmg_f ++** ... ++*/ ++ ++void ++call_hmg_f (void) ++{ ++ SF A = { 1.0F, 2.0F, 3.0F }; ++ hmg_f (A); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/k+r-00.c b/gcc/testsuite/gcc.target/aarch64/darwin/k+r-00.c +new file mode 100644 +index 00000000000..443fb968811 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/k+r-00.c +@@ -0,0 +1,28 @@ ++/* { dg-do compile } */ ++ ++/* { dg-options "-std=gnu99 " } */ ++/* { dg-additional-options "-O2 -fsection-anchors" } */ ++ ++ ++/* What we care about here is that we get int loads from sp, sp+4 and sp+8. ++ * This code will change when we implement darwinpcs d.3 - since the ++ * promotions will no longer be needed (although they are harmless). ++**test_k_r00: ++** ldrsb w[0-9]+, \[sp, 4\] ++** ldr x[0-9]+, \[sp, 8\] ++** ... ++** ldrsb w[0-9]+, \[sp\] ++** ... ++*/ ++ ++const char * ++test_k_r00 (r0, r1, r2, r3, r4, r5, r6, r7, a, b, c) ++ char r0, r1, r2, r3, r4, r5, r6, r7; ++ char a; ++ char b; ++ const char *c; ++{ ++ if (a > 10 && b < 100) ++ return c; ++ return (char *)0; ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/tu-accesses-0.c b/gcc/testsuite/gcc.target/aarch64/darwin/tu-accesses-0.c +new file mode 100644 +index 00000000000..ba5cc493bc9 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/tu-accesses-0.c +@@ -0,0 +1,82 @@ ++/* { dg-do compile } */ ++/* { dg-options "-O -fcommon -mno-pc-relative-literal-loads" } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++/* This checks that we perform the correct accesses for file-scope vars ++ including GOT indirections. */ ++ ++double gd = 1.0; ++ ++__attribute__((__weak__)) ++double wd = 2.0; ++ ++__attribute__((__visibility__("hidden"))) ++double hd = 3.0; ++ ++__attribute__((__weak__, __visibility__("hidden"))) ++double whd = 4.0; ++ ++extern double ed; ++ ++double cd; ++ ++static double sd = 5.0; ++ ++struct { ++ double a; ++ double b; ++} two_dbls = { 1.0, 42.0 }; ++ ++double arr[3] = { 6.0, 7.0, 8.0 }; ++ ++/* ++**test: ++** adrp x[0-9]+, _gd@PAGE ++** ldr d[0-9]+, \[x[0-9]+, #_gd@PAGEOFF\] ++** adrp x[0-9]+, lC0@PAGE ++** ldr d[0-9]+, \[x[0-9]+, #lC0@PAGEOFF\] ++** fadd d[0-9]+, d[0-9]+, d[0-9]+ ++** adrp x[0-9]+, _wd@GOTPAGE ++** ldr x[0-9]+, \[x[0-9]+, _wd@GOTPAGEOFF\] ++** ldr d[0-9]+, \[x[0-9]+\] ++** fadd d[0-9]+, d[0-9]+, d[0-9]+ ++** adrp x[0-9]+, _hd@PAGE ++** ldr d[0-9]+, \[x[0-9]+, #_hd@PAGEOFF\] ++** fadd d[0-9]+, d[0-9]+, d[0-9]+ ++** adrp x[0-9]+, _whd@PAGE ++** ldr d[0-9]+, \[x[0-9]+, #_whd@PAGEOFF\] ++** fadd d[0-9]+, d[0-9]+, d[0-9]+ ++** adrp x[0-9]+, _ed@GOTPAGE ++** ldr x[0-9]+, \[x[0-9]+, _ed@GOTPAGEOFF\] ++** ldr d[0-9]+, \[x[0-9]+\] ++** fadd d[0-9]+, d[0-9]+, d[0-9]+ ++** adrp x[0-9]+, _cd@GOTPAGE ++** ldr x[0-9]+, \[x[0-9]+, _cd@GOTPAGEOFF\] ++** ldr d[0-9]+, \[x[0-9]+\] ++** fadd d[0-9]+, d[0-9]+, d[0-9]+ ++** fmov d[0-9]+, 5.0e\+0 ++** fadd d[0-9]+, d[0-9]+, d[0-9]+ ++** adrp x[0-9]+, _two_dbls@PAGE\+8 ++** ldr d[0-9]+, \[x[0-9]+, #_two_dbls@PAGEOFF\+8\] ++** fadd d[0-9]+, d[0-9]+, d[0-9]+ ++** adrp x[0-9]+, _arr@PAGE\+16 ++** ldr d[0-9]+, \[x[0-9]+, #_arr@PAGEOFF\+16\] ++** fadd d[0-9]+, d[0-9]+, d[0-9]+ ++** ret ++*/ ++ ++double test (void) ++{ ++ double x = 123456123456123456.0; ++ x += gd; ++ x += wd; ++ x += hd; ++ x += whd; ++ x += ed; ++ x += cd; ++ x += sd; ++ x += two_dbls.b; ++ x += arr[2]; ++ ++ return x; ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/variadic-00.c b/gcc/testsuite/gcc.target/aarch64/darwin/variadic-00.c +new file mode 100644 +index 00000000000..6420fca11d5 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/variadic-00.c +@@ -0,0 +1,91 @@ ++/* { dg-do compile } */ ++ ++/* We use the sections anchors to make the code easier to match. */ ++/* { dg-additional-options " -O -fsection-anchors -fno-schedule-insns -fno-schedule-insns2 " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++#include ++ ++/* What we care about here is that the load of w0 is from the incoming [SP] ++**fooi: ++** sub sp, sp, #16 ++** add x[0-9]+, sp, 24 ++** str x[0-9]+, \[sp, 8\] ++** ldr w0, \[sp, 16\] ++** ... ++*/ ++ ++__attribute__((__noinline__)) int ++fooi (int a, ...) ++{ ++ int x; ++ va_list ap; ++ va_start(ap, a); ++ x = va_arg(ap, int); ++ va_end(ap); ++ return x; ++} ++ ++__attribute__((__noinline__)) int ++fooo (char a, ...); ++ ++/* ++**call_foo: ++** ... ++** mov w[0-9]+, 42 ++** str w[0-9]+, \[sp\] ++** mov w0, 1 ++** bl _fooo ++** ... ++*/ ++ ++__attribute__((__noinline__)) int ++call_foo (void) ++{ ++ int y = fooo (1, 42); ++ return y; ++} ++ ++/* What we care about here is that the load of w0 is from the incoming [SP+8] ++**bari: ++** sub sp, sp, #16 ++** add x[0-9]+, sp, 32 ++** str x[0-9]+, \[sp, 8\] ++** ldr w0, \[sp, 24\] ++** ... ++*/ ++ ++__attribute__((__noinline__)) int ++bari (int a, int b, int c, int d, int e, int f, int g, int h, ++ int i, ...) ++{ ++ int x; ++ va_list ap; ++ va_start(ap, i); ++ x = va_arg(ap, int); ++ va_end(ap); ++ return x; ++} ++ ++/* ++**call_bar: ++** ... ++** mov w[0-9]+, 42 ++** str w[0-9]+, \[sp, 8\] ++** mov w[0-9]+, 9 ++** str w[0-9]+, \[sp\] ++** ... ++ bl _baro ++** ... ++*/ ++ ++__attribute__((__noinline__)) int ++baro (int a, int b, int c, int d, int e, int f, int g, int h, ++ int i, ...); ++ ++__attribute__((__noinline__)) int ++call_bar (void) ++{ ++ int y = baro (1, 2, 3, 4, 5, 6, 7, 8, 9, 42); ++ return y; ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/variadic-01.c b/gcc/testsuite/gcc.target/aarch64/darwin/variadic-01.c +new file mode 100644 +index 00000000000..c055aeae580 +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/variadic-01.c +@@ -0,0 +1,102 @@ ++/* { dg-do compile } */ ++ ++/* we need this for _Float128. */ ++/* { dg-options "-std=gnu99 " } */ ++/* We use the sections anchors to make the code easier to match. */ ++/* { dg-additional-options " -O2 -fsection-anchors " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++#include ++ ++/* What we care about here is that q0 and q1 are loaded from incoming sp and ++ sp+16. ++**foo: ++** ... ++** ldr q1, \[sp, 32\] ++** ldr q0, \[sp, 48\] ++** ... ++** bl ___addtf3 ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++_Float128 ++foo (int n, ...) ++{ ++ _Float128 a, b; ++ va_list ap; ++ ++ va_start(ap, n); ++ a = va_arg(ap, _Float128); ++ b = va_arg(ap, _Float128); ++ va_end(ap); ++ return a + b; ++} ++ ++/* ++**call_foo: ++** ... ++** str q[0-9]+, \[sp, 16\] ++** ... ++** mov w0, 2 ++** str q[0-9]+, \[sp\] ++** bl _foo ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++_Float128 ++call_foo (void) ++{ ++ return foo (2, (_Float128)1.0, (_Float128)2.0); ++} ++ ++/* What we care about here is that q0 and q1 are loaded from incoming sp and ++ sp+32 (with the int at sp+16). ++**bar: ++** ... ++** ldr w[0-9]+, \[x[0-9]+, 16\] ++** ldr q0, \[x[0-9]+\] ++** ... ++** ldr q1, \[x[0-9]+, 32\] ++** bl ___addtf3 ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++_Float128 ++bar (int n, ...) ++{ ++ _Float128 a, b; ++ va_list ap; ++ ++ va_start(ap, n); ++ a = va_arg(ap, _Float128); ++ n = va_arg(ap, int); ++ if (n != 42) ++ __builtin_abort (); ++ b = va_arg(ap, _Float128); ++ va_end(ap); ++ return a + b; ++} ++ ++/* ++**call_bar: ++** ... ++** str q[0-9]+, \[sp, 32\] ++** ... ++** mov w[0-9]+, 42 ++** str w[0-9]+, \[sp, 16\] ++** mov w0, 2 ++** str q[0-9]+, \[sp\] ++** bl _bar ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++_Float128 ++call_bar (void) ++{ ++ return bar (2, (_Float128)1.0, ++ 42, (_Float128)2.0); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/variadic-02.c b/gcc/testsuite/gcc.target/aarch64/darwin/variadic-02.c +new file mode 100644 +index 00000000000..9d796bfc07f +--- /dev/null ++++ b/gcc/testsuite/gcc.target/aarch64/darwin/variadic-02.c +@@ -0,0 +1,104 @@ ++/* { dg-do compile } */ ++ ++/* we need this for __int128. */ ++/* { dg-options "-std=gnu99 " } */ ++/* We use the sections anchors to make the code easier to match. */ ++/* { dg-additional-options " -O2 -fsection-anchors " } */ ++/* { dg-final { check-function-bodies "**" "" "" { target *-*-darwin* } } } */ ++ ++#include ++ ++/* What we care about here is that we load the values from incoming sp and ++ sp + 16. ++**foo: ++** sub sp, sp, #16 ++** ... ++** ldp x[0-9]+, x[0-9]+, \[sp, 16\] ++** ... ++** ldr x[0-9]+, \[sp, 32\] ++** ldr x[0-9]+, \[sp, 40\] ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++__int128 ++foo (int n, ...) ++{ ++ __int128 a, b; ++ va_list ap; ++ ++ va_start(ap, n); ++ a = va_arg(ap, __int128); ++ b = va_arg(ap, __int128); ++ va_end(ap); ++ return a + b; ++} ++ ++/* ++**call_foo: ++** ... ++** stp x[0-9]+, x[0-9]+, \[sp\] ++** mov w0, 2 ++** stp x[0-9]+, x[0-9]+, \[sp, 16\] ++** bl _foo ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++__int128 ++call_foo (void) ++{ ++ return foo (2, (__int128)1, (__int128)2); ++} ++ ++ ++/* sp = one int128, sp+16 = int sp + 32 = other int128 ++**bar: ++** ... ++** sub sp, sp, #16 ++** ... ++** ldp x[0-9]+, x[0-9]+, \[sp, 16\] ++** ... ++** ldr x[0-9]+, \[sp, 48\] ++** ldr x[0-9]+, \[sp, 56\] ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++__int128 ++bar (int n, ...) ++{ ++ __int128 a, b; ++ va_list ap; ++ ++ va_start(ap, n); ++ a = va_arg(ap, __int128); ++ n = va_arg(ap, int); ++ b = va_arg(ap, __int128); ++ va_end(ap); ++ return a + b; ++} ++ ++__attribute__((__noinline__)) ++__int128 ++baro (int n, ...); ++ ++/* ++**call_bar: ++** ... ++** mov w[0-9]+, 42 ++** ... ++** mov w0, 2 ++** stp x[0-9]+, x[0-9]+, \[sp\] ++** str w[0-9]+, \[sp, 16\] ++** stp x[0-9]+, x[0-9]+, \[sp, 32\] ++** bl _baro ++** ... ++*/ ++ ++__attribute__((__noinline__)) ++__int128 ++call_bar (void) ++{ ++ return baro (2, (__int128)1, 42, (__int128)2); ++} +diff --git a/gcc/testsuite/gcc.target/aarch64/dbl_mov_immediate_1.c b/gcc/testsuite/gcc.target/aarch64/dbl_mov_immediate_1.c +index ba6a230457b..cc30dd546f4 100644 +--- a/gcc/testsuite/gcc.target/aarch64/dbl_mov_immediate_1.c ++++ b/gcc/testsuite/gcc.target/aarch64/dbl_mov_immediate_1.c +@@ -41,8 +41,10 @@ double d4(void) + + /* { dg-final { scan-assembler-times "movi\td\[0-9\]+, #?0" 1 } } */ + +-/* { dg-final { scan-assembler-times "adrp\tx\[0-9\]+, \.LC\[0-9\]" 2 } } */ +-/* { dg-final { scan-assembler-times "ldr\td\[0-9\]+, \\\[x\[0-9\], #:lo12:\.LC\[0-9\]\\\]" 2 } } */ ++/* { dg-final { scan-assembler-times "adrp\tx\[0-9\]+, \.LC\[0-9\]" 2 { target { ! *-*-darwin* } } } } */ ++/* { dg-final { scan-assembler-times "ldr\td\[0-9\]+, \\\[x\[0-9\], #:lo12:\.LC\[0-9\]\\\]" 2 { target { ! *-*-darwin* } } } } */ ++/* { dg-final { scan-assembler-times "adrp\tx\[0-9\]+, lC\[0-9\]@PAGE" 2 { target *-*-darwin* } } } */ ++/* { dg-final { scan-assembler-times "ldr\td\[0-9\]+, \\\[x\[0-9\], #lC\[0-9\]@PAGEOFF\\\]" 2 { target *-*-darwin* } } } */ + + /* { dg-final { scan-assembler-times "fmov\td\[0-9\]+, 1\\\.5e\\\+0" 1 } } */ + +diff --git a/gcc/testsuite/gcc.target/aarch64/dwarf-cfa-reg.c b/gcc/testsuite/gcc.target/aarch64/dwarf-cfa-reg.c +index ae5b3797021..8a691add222 100644 +--- a/gcc/testsuite/gcc.target/aarch64/dwarf-cfa-reg.c ++++ b/gcc/testsuite/gcc.target/aarch64/dwarf-cfa-reg.c +@@ -1,5 +1,6 @@ + /* Verify that CFA register is restored to SP after FP is restored. */ + /* { dg-do compile } */ ++/* { dg-skip-if "no cfi insn support yet" *-*-darwin* } */ + /* { dg-options "-O0 -gdwarf-2" } */ + /* { dg-final { scan-assembler ".cfi_restore 30" } } */ + /* { dg-final { scan-assembler ".cfi_restore 29" } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/inline-lrint_1.c b/gcc/testsuite/gcc.target/aarch64/inline-lrint_1.c +index 478875ff874..9a2b2e44893 100644 +--- a/gcc/testsuite/gcc.target/aarch64/inline-lrint_1.c ++++ b/gcc/testsuite/gcc.target/aarch64/inline-lrint_1.c +@@ -15,4 +15,4 @@ TEST (fllf, float , long long, l) + + /* { dg-final { scan-assembler-times "frintx\t\[d,s\]\[0-9\]+, \[d,s\]\[0-9\]+" 6 } } */ + /* { dg-final { scan-assembler-times "fcvtzs\tx\[0-9\]+, \[d,s\]\[0-9\]+" 6 } } */ +-/* { dg-final { scan-assembler-not "bl" } } */ ++/* { dg-final { scan-assembler-not "bl\t" } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/ldp_stp_13.c b/gcc/testsuite/gcc.target/aarch64/ldp_stp_13.c +index 9cc3942f153..52c90a92114 100644 +--- a/gcc/testsuite/gcc.target/aarch64/ldp_stp_13.c ++++ b/gcc/testsuite/gcc.target/aarch64/ldp_stp_13.c +@@ -1,4 +1,5 @@ + /* { dg-do compile } */ ++/* { dg-require-effective-target arm_mabi_ilp32 } */ + /* { dg-options "-O2 -mabi=ilp32" } */ + + long long +diff --git a/gcc/testsuite/gcc.target/aarch64/memset-corner-cases-2.c b/gcc/testsuite/gcc.target/aarch64/memset-corner-cases-2.c +index 9ee96f33255..dec73f98506 100644 +--- a/gcc/testsuite/gcc.target/aarch64/memset-corner-cases-2.c ++++ b/gcc/testsuite/gcc.target/aarch64/memset-corner-cases-2.c +@@ -7,7 +7,7 @@ + /* 127 bytes should use libcall for size. + **set127byte: + ** mov x2, 127 +-** b memset ++** b _?memset + */ + void __attribute__((__noinline__)) + set127byte (int64_t *src, int c) +@@ -18,7 +18,7 @@ set127byte (int64_t *src, int c) + /* 128 bytes should use libcall for size. + **set128byte: + ** mov x2, 128 +-** b memset ++** b _?memset + */ + void __attribute__((__noinline__)) + set128byte (int64_t *src, int c) +diff --git a/gcc/testsuite/gcc.target/aarch64/memset-corner-cases.c b/gcc/testsuite/gcc.target/aarch64/memset-corner-cases.c +index c43f0199adc..733a11e585a 100644 +--- a/gcc/testsuite/gcc.target/aarch64/memset-corner-cases.c ++++ b/gcc/testsuite/gcc.target/aarch64/memset-corner-cases.c +@@ -77,7 +77,7 @@ set256byte (int64_t *src, char c) + **set257byte: + ** mov x2, 257 + ** mov w1, 99 +-** b memset ++** b _?memset + */ + void __attribute__((__noinline__)) + set257byte (int64_t *src) +diff --git a/gcc/testsuite/gcc.target/aarch64/no-inline-lrint_1.c b/gcc/testsuite/gcc.target/aarch64/no-inline-lrint_1.c +index d5e9200562c..7f504ad687f 100644 +--- a/gcc/testsuite/gcc.target/aarch64/no-inline-lrint_1.c ++++ b/gcc/testsuite/gcc.target/aarch64/no-inline-lrint_1.c +@@ -14,6 +14,6 @@ TEST (dlld, double, long long, l) + TEST (fllf, float , long long, l) + + /* { dg-final { scan-assembler-times "frintx\t\[d,s\]\[0-9\]+, \[d,s\]\[0-9\]+" 6 } } */ +-/* { dg-final { scan-assembler-times "bl\tlrint" 4 } } */ +-/* { dg-final { scan-assembler-times "bl\tllrint" 2 } } */ ++/* { dg-final { scan-assembler-times "bl\t_*lrint" 4 } } */ ++/* { dg-final { scan-assembler-times "bl\t_*llrint" 2 } } */ + /* { dg-final { scan-assembler-not "fcvtzs" } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/pr100518.c b/gcc/testsuite/gcc.target/aarch64/pr100518.c +index 5ca599f5d2e..4e7d6bc7d90 100644 +--- a/gcc/testsuite/gcc.target/aarch64/pr100518.c ++++ b/gcc/testsuite/gcc.target/aarch64/pr100518.c +@@ -1,4 +1,5 @@ + /* { dg-do compile } */ ++/* { dg-require-effective-target arm_mabi_ilp32 } */ + /* { dg-options "-mabi=ilp32 -mstrict-align -O2" } */ + + int unsigned_range_min, unsigned_range_max, a11___trans_tmp_1; +diff --git a/gcc/testsuite/gcc.target/aarch64/pr62308.c b/gcc/testsuite/gcc.target/aarch64/pr62308.c +index 1cf6e212dca..4c1a733e84d 100644 +--- a/gcc/testsuite/gcc.target/aarch64/pr62308.c ++++ b/gcc/testsuite/gcc.target/aarch64/pr62308.c +@@ -1,4 +1,5 @@ + /* { dg-do compile } */ ++/* { dg-skip-if "Darwin platforms do not support big-endian arm64" *-*-darwin* } */ + /* { dg-options "-mbig-endian" } */ + + typedef int __attribute__((vector_size(16))) v4si; +diff --git a/gcc/testsuite/gcc.target/aarch64/pr78255.c b/gcc/testsuite/gcc.target/aarch64/pr78255.c +index b078cf3e1c1..fc5d859ee68 100644 +--- a/gcc/testsuite/gcc.target/aarch64/pr78255.c ++++ b/gcc/testsuite/gcc.target/aarch64/pr78255.c +@@ -1,4 +1,5 @@ + /* { dg-do compile } */ ++/* { dg-skip-if "Darwin platforms do not support tiny" *-*-darwin* } */ + /* { dg-options "-O2 -mcmodel=tiny" } */ + + extern int bar (void *); +diff --git a/gcc/testsuite/gcc.target/aarch64/pr78561.c b/gcc/testsuite/gcc.target/aarch64/pr78561.c +index 048d2d7969f..635214edde1 100644 +--- a/gcc/testsuite/gcc.target/aarch64/pr78561.c ++++ b/gcc/testsuite/gcc.target/aarch64/pr78561.c +@@ -1,4 +1,5 @@ + /* { dg-do compile } */ ++/* { dg-skip-if "Darwin platforms do not support tiny" *-*-darwin* } */ + /* { dg-options "-Og -O3 -mcmodel=tiny" } */ + + int +diff --git a/gcc/testsuite/gcc.target/aarch64/pr80295.c b/gcc/testsuite/gcc.target/aarch64/pr80295.c +index b3866d8d6a9..7a7f127b65f 100644 +--- a/gcc/testsuite/gcc.target/aarch64/pr80295.c ++++ b/gcc/testsuite/gcc.target/aarch64/pr80295.c +@@ -1,4 +1,5 @@ + /* { dg-do compile } */ ++/* { dg-require-effective-target arm_mabi_ilp32 } */ + /* { dg-options "-mabi=ilp32" } */ + + void f (void *b) +diff --git a/gcc/testsuite/gcc.target/aarch64/pr87305.c b/gcc/testsuite/gcc.target/aarch64/pr87305.c +index 8beaa9176e0..c3f98e8eaec 100644 +--- a/gcc/testsuite/gcc.target/aarch64/pr87305.c ++++ b/gcc/testsuite/gcc.target/aarch64/pr87305.c +@@ -1,4 +1,5 @@ + /* { dg-do compile } */ ++/* { dg-skip-if "Darwin platforms do not support big-endian arm64" *-*-darwin* } */ + /* { dg-options "-Ofast -mbig-endian -w" } */ + + int cc; +diff --git a/gcc/testsuite/gcc.target/aarch64/pr92424-1.c b/gcc/testsuite/gcc.target/aarch64/pr92424-1.c +index c413a2c306e..59f7435dc83 100644 +--- a/gcc/testsuite/gcc.target/aarch64/pr92424-1.c ++++ b/gcc/testsuite/gcc.target/aarch64/pr92424-1.c +@@ -1,6 +1,7 @@ + /* { dg-do "compile" } */ + /* { dg-options "-O1" } */ + /* { dg-final { check-function-bodies "**" "" } } */ ++/* { dg-skip-if "unimplemented patchable function entry" *-*-darwin* } */ + + /* Note: this test only checks the instructions in the function bodies, + not the placement of the patch label or nops before the futncion. */ +diff --git a/gcc/testsuite/gcc.target/aarch64/pr94201.c b/gcc/testsuite/gcc.target/aarch64/pr94201.c +index 69176169186..051c742e98e 100644 +--- a/gcc/testsuite/gcc.target/aarch64/pr94201.c ++++ b/gcc/testsuite/gcc.target/aarch64/pr94201.c +@@ -1,4 +1,5 @@ + /* { dg-do compile } */ ++/* { dg-require-effective-target arm_mabi_ilp32 } */ + /* { dg-options "-mcmodel=tiny -mabi=ilp32 -fPIC" } */ + + extern int bar (void *); +diff --git a/gcc/testsuite/gcc.target/aarch64/pr94577.c b/gcc/testsuite/gcc.target/aarch64/pr94577.c +index 6f2d3612c26..6a52e52dc39 100644 +--- a/gcc/testsuite/gcc.target/aarch64/pr94577.c ++++ b/gcc/testsuite/gcc.target/aarch64/pr94577.c +@@ -1,4 +1,5 @@ + /* { dg-do compile } */ ++/* { dg-require-effective-target arm_mabi_ilp32 } */ + /* { dg-options "-mcmodel=large -mabi=ilp32" } */ + + void +diff --git a/gcc/testsuite/gcc.target/aarch64/pr97535.c b/gcc/testsuite/gcc.target/aarch64/pr97535.c +index 7d4db485f1f..6f1ee8035eb 100644 +--- a/gcc/testsuite/gcc.target/aarch64/pr97535.c ++++ b/gcc/testsuite/gcc.target/aarch64/pr97535.c +@@ -13,4 +13,4 @@ void setRaw(const void *raw) + + /* At any optimization level this should be a function call + and not inlined. */ +-/* { dg-final { scan-assembler "bl\tmemcpy" } } */ ++/* { dg-final { scan-assembler "bl\t_*memcpy" } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-2.c b/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-2.c +index 8eec6824f37..193c65717ed 100644 +--- a/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-2.c ++++ b/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-2.c +@@ -1,5 +1,6 @@ + /* { dg-do compile } */ + /* { dg-options "-Ofast" } */ ++/* { dg-skip-if "no system variant_pcs support" *-*-darwin* } */ + + __attribute__ ((__simd__ ("notinbranch"))) + __attribute__ ((__nothrow__ , __leaf__ , __const__)) +@@ -12,5 +13,5 @@ void bar(double * f, int n) + f[i] = foo(f[i]); + } + +-/* { dg-final { scan-assembler-not {\.variant_pcs\tfoo} } } */ +-/* { dg-final { scan-assembler-times {\.variant_pcs\t_ZGVnN2v_foo} 1 } } */ ++/* { dg-final { scan-assembler-not {\.variant_pcs\t_?foo} } } */ ++/* { dg-final { scan-assembler-times {\.variant_pcs\t_?_ZGVnN2v_foo} 1 } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-3.c b/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-3.c +index 95f6a6803e8..6fd57735b3a 100644 +--- a/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-3.c ++++ b/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute-3.c +@@ -1,5 +1,6 @@ + /* { dg-do compile } */ + /* { dg-options "-Ofast" } */ ++/* { dg-skip-if "no system variant_pcs support" *-*-darwin* } */ + + __attribute__ ((__simd__)) + __attribute__ ((__nothrow__ , __leaf__ , __const__)) +@@ -17,8 +18,8 @@ double foo(double x) + return x * x / 3.0; + } + +-/* { dg-final { scan-assembler-not {\.variant_pcs\tfoo} } } */ +-/* { dg-final { scan-assembler-times {\.variant_pcs\t_ZGVnM1v_foo} 1 } } */ +-/* { dg-final { scan-assembler-times {\.variant_pcs\t_ZGVnM2v_foo} 1 } } */ +-/* { dg-final { scan-assembler-times {\.variant_pcs\t_ZGVnN1v_foo} 1 } } */ +-/* { dg-final { scan-assembler-times {\.variant_pcs\t_ZGVnN2v_foo} 1 } } */ ++/* { dg-final { scan-assembler-not {\.variant_pcs\t_?foo} } } */ ++/* { dg-final { scan-assembler-times {\.variant_pcs\t_?_ZGVnM1v_foo} 1 } } */ ++/* { dg-final { scan-assembler-times {\.variant_pcs\t_?_ZGVnM2v_foo} 1 } } */ ++/* { dg-final { scan-assembler-times {\.variant_pcs\t_?_ZGVnN1v_foo} 1 } } */ ++/* { dg-final { scan-assembler-times {\.variant_pcs\t_?_ZGVnN2v_foo} 1 } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute.c b/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute.c +index eddcef3597c..62ee482a892 100644 +--- a/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute.c ++++ b/gcc/testsuite/gcc.target/aarch64/simd_pcs_attribute.c +@@ -1,5 +1,6 @@ + /* { dg-do compile } */ + /* { dg-options "-Ofast" } */ ++/* { dg-skip-if "no system variant_pcs support" *-*-darwin* } */ + + __attribute__ ((__simd__ ("notinbranch"))) + __attribute__ ((__nothrow__ , __leaf__ , __const__)) +@@ -12,5 +13,5 @@ void foo(double *f, int n) + f[i] = log(f[i]); + } + +-/* { dg-final { scan-assembler-not {\.variant_pcs\tlog} } } */ +-/* { dg-final { scan-assembler-times {\.variant_pcs\t_ZGVnN2v_log} 1 } } */ ++/* { dg-final { scan-assembler-not {\.variant_pcs\t_?log} } } */ ++/* { dg-final { scan-assembler-times {\.variant_pcs\t_?_ZGVnN2v_log} 1 } } */ +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-1.c b/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-1.c +index 6885894a97e..ebba23c9d02 100644 +--- a/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-1.c ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-1.c +@@ -1,6 +1,7 @@ + /* { dg-do compile } */ + /* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16 -funwind-tables" } */ + /* { dg-require-effective-target supports_stack_clash_protection } */ ++/* { dg-skip-if "no cfi insn support yet" *-*-darwin* } */ + + #define SIZE 128*1024 + #include "stack-check-prologue.h" +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-2.c b/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-2.c +index 5796a53be06..e15fbd6196c 100644 +--- a/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-2.c ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-2.c +@@ -1,6 +1,7 @@ + /* { dg-do compile } */ + /* { dg-options "-O2 -fstack-clash-protection --param stack-clash-protection-guard-size=16 -funwind-tables" } */ + /* { dg-require-effective-target supports_stack_clash_protection } */ ++/* { dg-skip-if "no cfi insn support yet" *-*-darwin* } */ + + #define SIZE 1280*1024 + 512 + #include "stack-check-prologue.h" +diff --git a/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-3.c b/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-3.c +index c4b7bb601c4..ccaf2e6f8cf 100644 +--- a/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-3.c ++++ b/gcc/testsuite/gcc.target/aarch64/stack-check-cfa-3.c +@@ -1,6 +1,7 @@ + /* { dg-do compile } */ + /* { dg-options "-O3 -fopenmp-simd -march=armv8-a+sve -fstack-clash-protection --param stack-clash-protection-guard-size=16 -funwind-tables" } */ + /* { dg-require-effective-target supports_stack_clash_protection } */ ++/* { dg-skip-if "no cfi insn support yet" *-*-darwin* } */ + + #include "stack-check-prologue-16.c" + +diff --git a/gcc/testsuite/gcc.target/aarch64/sve/aarch64-sve.exp b/gcc/testsuite/gcc.target/aarch64/sve/aarch64-sve.exp +index 71dd6687c6b..7a62814edbb 100644 +--- a/gcc/testsuite/gcc.target/aarch64/sve/aarch64-sve.exp ++++ b/gcc/testsuite/gcc.target/aarch64/sve/aarch64-sve.exp +@@ -25,6 +25,11 @@ if {![istarget aarch64*-*-*] } then { + return + } + ++# Darwin doesn't support sve ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib gcc-dg.exp + +diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle-asm.exp b/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle-asm.exp +index a271f1793f4..2da5720d1f3 100644 +--- a/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle-asm.exp ++++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle-asm.exp +@@ -24,6 +24,11 @@ if {![istarget aarch64*-*-*] } { + return + } + ++# Darwin doesn't support sve ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib gcc-dg.exp + +diff --git a/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle.exp b/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle.exp +index ce71c9c1fd4..c7bd136f202 100644 +--- a/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle.exp ++++ b/gcc/testsuite/gcc.target/aarch64/sve/acle/aarch64-sve-acle.exp +@@ -25,6 +25,11 @@ if {![istarget aarch64*-*-*] } { + return + } + ++# Darwin doesn't support sve ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib gcc-dg.exp + +diff --git a/gcc/testsuite/gcc.target/aarch64/sve/pcs/aarch64-sve-pcs.exp b/gcc/testsuite/gcc.target/aarch64/sve/pcs/aarch64-sve-pcs.exp +index 83786733f35..9ab68902def 100644 +--- a/gcc/testsuite/gcc.target/aarch64/sve/pcs/aarch64-sve-pcs.exp ++++ b/gcc/testsuite/gcc.target/aarch64/sve/pcs/aarch64-sve-pcs.exp +@@ -25,6 +25,10 @@ if {![istarget aarch64*-*-*] } then { + return + } + ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib gcc-dg.exp + +diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/aarch64-sve2.exp b/gcc/testsuite/gcc.target/aarch64/sve2/aarch64-sve2.exp +index 60652dbf8fb..010e32132cb 100644 +--- a/gcc/testsuite/gcc.target/aarch64/sve2/aarch64-sve2.exp ++++ b/gcc/testsuite/gcc.target/aarch64/sve2/aarch64-sve2.exp +@@ -25,6 +25,11 @@ if {![istarget aarch64*-*-*] } then { + return + } + ++# Darwin doesn't support sve ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib gcc-dg.exp + +diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/acle/aarch64-sve2-acle-asm.exp b/gcc/testsuite/gcc.target/aarch64/sve2/acle/aarch64-sve2-acle-asm.exp +index e08cd612190..a7e5f364770 100644 +--- a/gcc/testsuite/gcc.target/aarch64/sve2/acle/aarch64-sve2-acle-asm.exp ++++ b/gcc/testsuite/gcc.target/aarch64/sve2/acle/aarch64-sve2-acle-asm.exp +@@ -24,6 +24,11 @@ if {![istarget aarch64*-*-*] } { + return + } + ++# Darwin doesn't support sve ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib gcc-dg.exp + +diff --git a/gcc/testsuite/gcc.target/aarch64/sve2/acle/aarch64-sve2-acle.exp b/gcc/testsuite/gcc.target/aarch64/sve2/acle/aarch64-sve2-acle.exp +index f0255967c9d..82092e337f6 100644 +--- a/gcc/testsuite/gcc.target/aarch64/sve2/acle/aarch64-sve2-acle.exp ++++ b/gcc/testsuite/gcc.target/aarch64/sve2/acle/aarch64-sve2-acle.exp +@@ -25,6 +25,11 @@ if {![istarget aarch64*-*-*] } { + return + } + ++# Darwin doesn't support sve ++if { [istarget *-*-darwin*] } then { ++ return ++} ++ + # Load support procs. + load_lib gcc-dg.exp + +diff --git a/gcc/testsuite/gcc.target/aarch64/symbol-range-tiny.c b/gcc/testsuite/gcc.target/aarch64/symbol-range-tiny.c +index fc6a4f3ec78..2d9e94bc625 100644 +--- a/gcc/testsuite/gcc.target/aarch64/symbol-range-tiny.c ++++ b/gcc/testsuite/gcc.target/aarch64/symbol-range-tiny.c +@@ -1,4 +1,5 @@ + /* { dg-do link } */ ++/* { dg-skip-if "no mcmodel tiny" *-*-darwin* } */ + /* { dg-options "-O3 -save-temps -mcmodel=tiny" } */ + + char fixed_regs[0x00080000]; +diff --git a/gcc/testsuite/gcc.target/aarch64/uaddw-3.c b/gcc/testsuite/gcc.target/aarch64/uaddw-3.c +index 39cbd6b6cc2..b4ed187bd2c 100644 +--- a/gcc/testsuite/gcc.target/aarch64/uaddw-3.c ++++ b/gcc/testsuite/gcc.target/aarch64/uaddw-3.c +@@ -1,10 +1,11 @@ + /* { dg-do compile } */ + /* { dg-options "-O3" } */ ++/* { dg-additional-options "-fno-signed-char" { target *-*-darwin* } } */ + + #pragma GCC target "+nosve" + + int +-t6(int len, void * dummy, char * __restrict x) ++t6(int len, void * dummy, unsigned char * __restrict x) + { + len = len & ~31; + unsigned short result = 0; +diff --git a/gcc/testsuite/gcc.target/aarch64/vect-cse-codegen.c b/gcc/testsuite/gcc.target/aarch64/vect-cse-codegen.c +index d025e989a1e..f218504c719 100644 +--- a/gcc/testsuite/gcc.target/aarch64/vect-cse-codegen.c ++++ b/gcc/testsuite/gcc.target/aarch64/vect-cse-codegen.c +@@ -6,8 +6,8 @@ + + /* + **test1: +-** adrp x[0-9]+, .LC[0-9]+ +-** ldr q[0-9]+, \[x[0-9]+, #:lo12:.LC[0-9]+\] ++** adrp x[0-9]+, (.LC[0-9]+|lC[0-9]+@PAGE) ++** ldr q[0-9]+, \[x[0-9]+, #(:lo12:.LC[0-9]+|lC[0-9]+@PAGEOFF)\] + ** add v[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d + ** str q[0-9]+, \[x[0-9]+\] + ** fmov x[0-9]+, d[0-9]+ +@@ -27,13 +27,14 @@ test1 (uint64_t a, uint64x2_t b, uint64x2_t* rt) + + /* + **test2: +-** adrp x[0-9]+, .LC[0-1]+ +-** ldr q[0-9]+, \[x[0-9]+, #:lo12:.LC[0-9]+\] ++** adrp x[0-9]+, (.LC[0-1]+|lC[0-1]+@PAGE) ++** ldr q[0-9]+, \[x[0-9]+, #(:lo12:.LC[0-9]+|lC[0-9]+@PAGEOFF)\] + ** add v[0-9]+.2d, v[0-9]+.2d, v[0-9]+.2d + ** str q[0-9]+, \[x[0-9]+\] + ** fmov x[0-9]+, d[0-9]+ + ** orr x[0-9]+, x[0-9]+, x[0-9]+ + ** ret ++ + */ + + uint64_t +@@ -48,8 +49,8 @@ test2 (uint64_t a, uint64x2_t b, uint64x2_t* rt) + + /* + **test3: +-** adrp x[0-9]+, .LC[0-9]+ +-** ldr q[0-9]+, \[x[0-9]+, #:lo12:.LC[0-9]+\] ++** adrp x[0-9]+, (.LC[0-9]+|lC[0-9]+@PAGE) ++** ldr q[0-9]+, \[x[0-9]+, #(:lo12:.LC[0-9]+|lC[0-9]+@PAGEOFF)\] + ** add v[0-9]+.4s, v[0-9]+.4s, v[0-9]+.4s + ** str q[0-9]+, \[x1\] + ** fmov w[0-9]+, s[0-9]+ +diff --git a/gcc/testsuite/gfortran.dg/coarray/caf.exp b/gcc/testsuite/gfortran.dg/coarray/caf.exp +index 8683a2ab435..e76cb69dcd9 100644 +--- a/gcc/testsuite/gfortran.dg/coarray/caf.exp ++++ b/gcc/testsuite/gfortran.dg/coarray/caf.exp +@@ -28,6 +28,7 @@ + + # Load procedures from common libraries. + load_lib gfortran-dg.exp ++load_lib atomic-dg.exp + + # If a testcase doesn't have special options, use these. + global DEFAULT_FFLAGS +@@ -47,6 +48,7 @@ global gfortran_test_path + global gfortran_aux_module_flags + set gfortran_test_path $srcdir/$subdir + set gfortran_aux_module_flags $DEFAULT_FFLAGS ++ + proc dg-compile-aux-modules { args } { + global gfortran_test_path + global gfortran_aux_module_flags +@@ -69,9 +71,21 @@ proc dg-compile-aux-modules { args } { + } + + # Add -latomic only where supported. Assume built-in support elsewhere. +-set maybe_atomic_lib "" + if [check_effective_target_libatomic_available] { +- set maybe_atomic_lib "-latomic" ++ #set maybe_atomic_lib "-latomic" ++ if ![is_remote host] { ++ if [info exists TOOL_OPTIONS] { ++ set maybe_atomic_lib "[atomic_link_flags [get_multilibs ${TOOL_OPTIONS}]]" ++ } else { ++ set maybe_atomic_lib "[atomic_link_flags [get_multilibs]]" ++ } ++ } else { ++ set maybe_atomic_lib "" ++ } ++ set t [get_multilibs] ++ puts "maybe al $maybe_atomic_lib ml $t" ++} else { ++ set maybe_atomic_lib "" + } + + # Main loop. +diff --git a/gcc/testsuite/gfortran.dg/dg.exp b/gcc/testsuite/gfortran.dg/dg.exp +index bd7ad95ad0d..36fc2972b2e 100644 +--- a/gcc/testsuite/gfortran.dg/dg.exp ++++ b/gcc/testsuite/gfortran.dg/dg.exp +@@ -18,6 +18,7 @@ + + # Load support procs. + load_lib gfortran-dg.exp ++load_lib atomic-dg.exp + + # If a testcase doesn't have special options, use these. + global DEFAULT_FFLAGS +@@ -53,12 +54,30 @@ proc dg-compile-aux-modules { args } { + } + } + ++# coarray tests might need libatomic. Assume that it is either not needed or ++# provided by builtins if it's not available. ++if [check_effective_target_libatomic_available] { ++ if ![is_remote host] { ++ if [info exists TOOL_OPTIONS] { ++ set maybe_atomic_lib "[atomic_link_flags [get_multilibs ${TOOL_OPTIONS}]]" ++ } else { ++ set maybe_atomic_lib "[atomic_link_flags [get_multilibs]]" ++ } ++ } else { ++ set maybe_atomic_lib "" ++ } ++ set t [get_multilibs] ++ puts "dg set al $maybe_atomic_lib ml $t" ++} ++ ++puts "DEFAULT_FFLAGS $DEFAULT_FFLAGS" ++ + # Main loop. + gfortran-dg-runtest [lsort \ +- [glob -nocomplain $srcdir/$subdir/*.\[fF\]{,90,95,03,08} ] ] "" $DEFAULT_FFLAGS ++ [glob -nocomplain $srcdir/$subdir/*.\[fF\]{,90,95,03,08} ] ] $maybe_atomic_lib $DEFAULT_FFLAGS + + gfortran-dg-runtest [lsort \ +- [glob -nocomplain $srcdir/$subdir/g77/*.\[fF\] ] ] "" $DEFAULT_FFLAGS ++ [glob -nocomplain $srcdir/$subdir/g77/*.\[fF\] ] ] $maybe_atomic_lib $DEFAULT_FFLAGS + + + # All done. +diff --git a/gcc/testsuite/gfortran.dg/pr95690.f90 b/gcc/testsuite/gfortran.dg/pr95690.f90 +index 47a5df9e894..1afa9d3c467 100644 +--- a/gcc/testsuite/gfortran.dg/pr95690.f90 ++++ b/gcc/testsuite/gfortran.dg/pr95690.f90 +@@ -2,8 +2,8 @@ + module m + contains + subroutine s +- print *, (erfc) ! { dg-error "not a floating constant" "" { target i?86-*-* x86_64-*-* sparc*-*-* cris-*-* } } +- end ! { dg-error "not a floating constant" "" { target { ! "i?86-*-* x86_64-*-* sparc*-*-* cris-*-*" } } } ++ print *, (erfc) ! { dg-error "not a floating constant" "" { target i?86-*-* x86_64-*-* sparc*-*-* cris-*-* aarch64-apple-darwin* } } ++ end ! { dg-error "not a floating constant" "" { target { ! "i?86-*-* x86_64-*-* sparc*-*-* cris-*-* aarch64-apple-darwin*" } } } + function erfc() + end + end +diff --git a/gcc/testsuite/lib/asan-dg.exp b/gcc/testsuite/lib/asan-dg.exp +index 7e0f85dc9b0..88c6ece8caa 100644 +--- a/gcc/testsuite/lib/asan-dg.exp ++++ b/gcc/testsuite/lib/asan-dg.exp +@@ -78,7 +78,7 @@ proc asan_link_flags_1 { paths lib } { + || [file exists "${gccpath}/libsanitizer/${lib}/.libs/lib${lib}.${shlib_ext}"] } { + append flags " -B${gccpath}/libsanitizer/ " + append flags " -B${gccpath}/libsanitizer/${lib}/ " +- append flags " -L${gccpath}/libsanitizer/${lib}/.libs " ++ append flags " -B${gccpath}/libsanitizer/${lib}/.libs " + append ld_library_path ":${gccpath}/libsanitizer/${lib}/.libs" + } + } else { +diff --git a/gcc/testsuite/lib/atomic-dg.exp b/gcc/testsuite/lib/atomic-dg.exp +index 86dcfa674ea..c9244fb6cac 100644 +--- a/gcc/testsuite/lib/atomic-dg.exp ++++ b/gcc/testsuite/lib/atomic-dg.exp +@@ -33,7 +33,7 @@ proc atomic_link_flags { paths } { + if { [file exists "${gccpath}/libatomic/.libs/libatomic.a"] + || [file exists "${gccpath}/libatomic/.libs/libatomic.${shlib_ext}"] } { + append flags " -B${gccpath}/libatomic/ " +- append flags " -L${gccpath}/libatomic/.libs" ++ append flags " -B${gccpath}/libatomic/.libs" + append ld_library_path ":${gccpath}/libatomic/.libs" + } + } else { +diff --git a/gcc/testsuite/lib/scanasm.exp b/gcc/testsuite/lib/scanasm.exp +index a80630bb2a8..195611f1f72 100644 +--- a/gcc/testsuite/lib/scanasm.exp ++++ b/gcc/testsuite/lib/scanasm.exp +@@ -763,7 +763,7 @@ proc scan-lto-assembler { args } { + # to function bodies in array RESULT. FILENAME has already been uploaded + # locally where necessary and is known to exist. + +-proc parse_function_bodies { filename result } { ++proc parse_ELF_function_bodies { filename result } { + upvar $result up_result + + # Regexp for the start of a function definition (name in \1). +@@ -793,6 +793,44 @@ proc parse_function_bodies { filename result } { + close $fd + } + ++proc parse_MACHO_function_bodies { filename result } { ++ upvar $result up_result ++ ++ # Regexp for the start of a function definition (name in \1). ++ set label {^(_[a-zA-Z_]\S+):$} ++ set start {^LFB[0-9]+} ++ ++ # Regexp for the end of a function definition. ++ set terminator {^LFE[0-9]+} ++ ++ # Regexp for lines that aren't interesting. ++ set fluff {^\s*(?:\.|//|@)} ++ set fluff3 {^L[0-9ACESV]} ++ ++ set fd [open $filename r] ++ set in_function 0 ++ while { [gets $fd line] >= 0 } { ++ if { !$in_function && [regexp $label $line dummy function_name] } { ++ set in_function 1 ++ set function_body "" ++ } elseif { $in_function == 1 } { ++ if { [regexp $start $line] } { ++ set in_function 2 ++ } else { ++ set in_function 0 ++ } ++ } elseif { $in_function == 2 } { ++ if { [regexp $terminator $line] } { ++ set up_result($function_name) $function_body ++ set in_function 0 ++ } elseif { ![regexp $fluff $line] && ![regexp $fluff3 $line] } { ++ append function_body $line "\n" ++ } ++ } ++ } ++ close $fd ++} ++ + # FUNCTIONS is an array that maps function names to function bodies. + # Return true if it contains a definition of function NAME and if + # that definition matches BODY_REGEXP. +@@ -820,6 +858,14 @@ proc check-function-bodies { args } { + error "too many arguments to check-function-bodies" + } + ++ set isELF 1 ++ # some targets have a __USER_LABEL_PREFIX__ ++ set needsULP 0 ++ if { [istarget *-*-darwin*] } { ++ set isELF 0 ++ set needsULP 1 ++ } ++ + if { [llength $args] >= 3 } { + set required_flags [lindex $args 2] + +@@ -876,7 +922,11 @@ proc check-function-bodies { args } { + remote_upload host "$filename" + } + if { [file exists $output_filename] } { +- parse_function_bodies $output_filename functions ++ if { $isELF } { ++ parse_ELF_function_bodies $output_filename functions ++ } else { ++ parse_MACHO_function_bodies $output_filename functions ++ } + set have_bodies 1 + } else { + verbose -log "$testcase: output file does not exist" +@@ -921,6 +971,9 @@ proc check-function-bodies { args } { + if { $xfail_all || [string equal $selector "F"] } { + setup_xfail "*-*-*" + } ++ if { $needsULP } { ++ set function_name "_$function_name" ++ } + set testname "$testcase check-function-bodies $function_name" + if { !$have_bodies } { + unresolved $testname +diff --git a/gcc/testsuite/lib/target-libpath.exp b/gcc/testsuite/lib/target-libpath.exp +index d09cd515d20..280ce390845 100644 +--- a/gcc/testsuite/lib/target-libpath.exp ++++ b/gcc/testsuite/lib/target-libpath.exp +@@ -67,6 +67,7 @@ proc set_ld_library_path_env_vars { } { + global orig_dyld_library_path + global orig_path + global orig_gcc_exec_prefix ++ global ENABLE_DARWIN_AT_RPATH + global env + + # Save the original GCC_EXEC_PREFIX. +@@ -133,6 +134,7 @@ proc set_ld_library_path_env_vars { } { + # + # Doing this is somewhat of a hack as ld_library_path gets repeated in + # SHLIB_PATH and LD_LIBRARY_PATH when unix_load sets these variables. ++ if { ![istarget *-*-darwin*] } { + if { $orig_ld_library_path_saved } { + setenv LD_LIBRARY_PATH "$ld_library_path:$orig_ld_library_path" + } else { +@@ -166,11 +168,23 @@ proc set_ld_library_path_env_vars { } { + } else { + setenv LD_LIBRARY_PATH_64 "$ld_library_path" + } +- if { $orig_dyld_library_path_saved } { +- setenv DYLD_LIBRARY_PATH "$ld_library_path:$orig_dyld_library_path" +- } else { +- setenv DYLD_LIBRARY_PATH "$ld_library_path" + } ++ if { [istarget *-*-darwin*] } { ++ if { [info exists ENABLE_DARWIN_AT_RPATH] || [istarget *-*-darwin1\[5-9\]*] ++ || [istarget *-*-darwin2*] } { ++ # Either we are not using DYLD_LIBRARY_PATH or we're on a version of the ++ # OS for which it is not passed through system exes. ++ if [info exists env(DYLD_LIBRARY_PATH)] { ++ unsetenv DYLD_LIBRARY_PATH ++ } ++ } else { ++ if { $orig_dyld_library_path_saved } { ++ setenv DYLD_LIBRARY_PATH "$ld_library_path:$orig_dyld_library_path" ++ } else { ++ setenv DYLD_LIBRARY_PATH "$ld_library_path" ++ } ++ } ++ } + if { [istarget *-*-cygwin*] || [istarget *-*-mingw*] } { + if { $orig_path_saved } { + setenv PATH "$ld_library_path:$orig_path" +@@ -179,6 +193,7 @@ proc set_ld_library_path_env_vars { } { + } + } + ++ verbose -log "set paths" + verbose -log "LD_LIBRARY_PATH=[getenv LD_LIBRARY_PATH]" + verbose -log "LD_RUN_PATH=[getenv LD_RUN_PATH]" + verbose -log "SHLIB_PATH=[getenv SHLIB_PATH]" +diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp +index 244fe2306f4..75581914d6c 100644 +--- a/gcc/testsuite/lib/target-supports.exp ++++ b/gcc/testsuite/lib/target-supports.exp +@@ -8485,7 +8485,7 @@ proc check_effective_target_section_anchors { } { + return [check_cached_effective_target section_anchors { + expr { [istarget powerpc*-*-*] + || [istarget arm*-*-*] +- || [istarget aarch64*-*-*] }}] ++ || ([istarget aarch64*-*-*] && ![istarget aarch64*-*-darwin*]) }}] + } + + # Return 1 if the target supports atomic operations on "int_128" values. +@@ -11526,6 +11526,15 @@ proc check_effective_target_arm_thumb2_ok_no_arm_v8_1_lob { } { + return 0 + } + ++# Return 1 if this is an ARM target where -mabi=ilp32 can be used. ++ ++proc check_effective_target_arm_mabi_ilp32 { } { ++ return [check_no_compiler_messages_nocache arm_mabi_ilp32 assembly { ++ int main() { return 0; } ++ } "-mabi=ilp32"] ++} ++ ++ + # Returns 1 if the target is using glibc, 0 otherwise. + + proc check_effective_target_glibc { } { +diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm +index 92852c3ecea..e0974539ecf 100644 +--- a/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm ++++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-class-meta.mm +@@ -19,6 +19,7 @@ this behavior may be defined or documented (for example, if class + + /* { dg-do run } */ + /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ ++/* { dg-skip-if "API unsupported" { arm64*-*-darwin* aarch64*-*-darwin* } { "-fnext-runtime" } { "" } } */ + /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + /* { dg-additional-options "-DOBJC_OLD_DISPATCH_PROTOTYPES" { target { *-*-darwin* } } } */ + // { dg-additional-options "-Wno-objc-root-class" } +diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm +index f6e3d8d22e0..a23968a89b5 100644 +--- a/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm ++++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm +@@ -6,6 +6,7 @@ + + /* { dg-do run } */ + /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ ++/* { dg-skip-if "API unsupported" { arm64*-*-darwin* aarch64*-*-darwin* } { "-fnext-runtime" } { "" } } */ + /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + /* { dg-additional-options "-DOBJC_OLD_DISPATCH_PROTOTYPES" { target { *-*-darwin* } } } */ + // { dg-additional-options "-Wno-objc-root-class" } +diff --git a/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-4.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-4.mm +index 1155db5f83f..e0dd8062373 100644 +--- a/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-4.mm ++++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-cfstring-4.mm +@@ -18,4 +18,4 @@ + + /* { dg-final { scan-assembler ".section __DATA, __cfstring" } } */ + /* { dg-final { scan-assembler ".long\t___CFConstantStringClassReference\n\t.long\t1992\n\t.long\t.*\n\t.long\t19\n" { target { *-*-darwin* && { ! lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t___CFConstantStringClassReference\n\t.long\t1992\n\t.space 4\n\t.quad\t.*\n\t.quad\t19\n" { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t___CFConstantStringClassReference\n\t.(long|word)\t1992\n\t.space 4\n\t.(quad|xword)\t.*\n\t.(quad|xword)\t19\n} { target { *-*-darwin* && { lp64 } } } } } */ +diff --git a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-10.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-10.mm +index e1dad124cd6..eb89710d890 100644 +--- a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-10.mm ++++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-10.mm +@@ -33,4 +33,4 @@ @interface NSConstantString : NSSimpleCString + /* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ + /* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ + /* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._NSConstantString\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t_OBJC_CLASS_._NSConstantString\n\t.(quad|xword)\t.*\n\t.(long|word)\t5\n\t.space} { target { *-*-darwin* && { lp64 } } } } } */ +diff --git a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-11.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-11.mm +index 30a9228a64e..c1b58dc6cb8 100644 +--- a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-11.mm ++++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-11.mm +@@ -33,4 +33,4 @@ @interface XStr : XString { + /* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ + /* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ + /* { dg-final { scan-assembler ".long\t__XStrClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._XStr\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t_OBJC_CLASS_._XStr\n\t.(quad|xword)\t.*\n\t.(long|word)\t5\n\t.space} { target { *-*-darwin* && { lp64 } } } } } */ +diff --git a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-9.mm b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-9.mm +index a1a14295e90..8457f46be53 100644 +--- a/gcc/testsuite/obj-c++.dg/torture/strings/const-str-9.mm ++++ b/gcc/testsuite/obj-c++.dg/torture/strings/const-str-9.mm +@@ -25,4 +25,4 @@ @interface NSConstantString: NSObject { + /* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ + /* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ + /* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._NSConstantString\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t_OBJC_CLASS_._NSConstantString\n\t.(quad|xword)\t.*\n\t.(long|word)\t5\n\t.space} { target { *-*-darwin* && { lp64 } } } } } */ +diff --git a/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m b/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m +index 6c1c76a87a3..41a48f9c685 100644 +--- a/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m ++++ b/gcc/testsuite/objc.dg/gnu-api-2-class-meta.m +@@ -19,6 +19,7 @@ this behavior may be defined or documented (for example, if class + + /* { dg-do run } */ + /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ ++/* { dg-skip-if "API unsupported" { arm64*-*-darwin* aarch64*-*-darwin* } { "-fnext-runtime" } { "" } } */ + /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + /* { dg-additional-options "-Wno-objc-root-class" } */ + /* { dg-additional-options "-DOBJC_OLD_DISPATCH_PROTOTYPES" { target { *-*-darwin* } } } */ +diff --git a/gcc/testsuite/objc.dg/gnu-api-2-class.m b/gcc/testsuite/objc.dg/gnu-api-2-class.m +index d11dae0e6dc..1386ebc2f99 100644 +--- a/gcc/testsuite/objc.dg/gnu-api-2-class.m ++++ b/gcc/testsuite/objc.dg/gnu-api-2-class.m +@@ -6,6 +6,7 @@ + + /* { dg-do run } */ + /* { dg-skip-if "No API#2 pre-Darwin9" { *-*-darwin[5-8]* } { "-fnext-runtime" } { "" } } */ ++/* { dg-skip-if "API unsupported" { arm64*-*-darwin* aarch64*-*-darwin* } { "-fnext-runtime" } { "" } } */ + /* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */ + /* { dg-additional-options "-Wno-objc-root-class" } */ + /* { dg-additional-options "-DOBJC_OLD_DISPATCH_PROTOTYPES" { target { *-*-darwin* } } } */ +diff --git a/gcc/testsuite/objc.dg/torture/strings/const-cfstring-4.m b/gcc/testsuite/objc.dg/torture/strings/const-cfstring-4.m +index 1155db5f83f..e0dd8062373 100644 +--- a/gcc/testsuite/objc.dg/torture/strings/const-cfstring-4.m ++++ b/gcc/testsuite/objc.dg/torture/strings/const-cfstring-4.m +@@ -18,4 +18,4 @@ + + /* { dg-final { scan-assembler ".section __DATA, __cfstring" } } */ + /* { dg-final { scan-assembler ".long\t___CFConstantStringClassReference\n\t.long\t1992\n\t.long\t.*\n\t.long\t19\n" { target { *-*-darwin* && { ! lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t___CFConstantStringClassReference\n\t.long\t1992\n\t.space 4\n\t.quad\t.*\n\t.quad\t19\n" { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t___CFConstantStringClassReference\n\t.(long|word)\t1992\n\t.space 4\n\t.(quad|xword)\t.*\n\t.(quad|xword)\t19\n} { target { *-*-darwin* && { lp64 } } } } } */ +diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-10.m b/gcc/testsuite/objc.dg/torture/strings/const-str-10.m +index 6565dc20007..81b0d326c56 100644 +--- a/gcc/testsuite/objc.dg/torture/strings/const-str-10.m ++++ b/gcc/testsuite/objc.dg/torture/strings/const-str-10.m +@@ -34,4 +34,4 @@ @interface NSConstantString : NSSimpleCString + /* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ + /* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ + /* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._NSConstantString\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t_OBJC_CLASS_._NSConstantString\n\t.(quad|xword)\t.*\n\t.(long|word)\t5\n\t.space} { target { *-*-darwin* && { lp64 } } } } } */ +diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-11.m b/gcc/testsuite/objc.dg/torture/strings/const-str-11.m +index 2bdb1531e1d..b044b0fd8c7 100644 +--- a/gcc/testsuite/objc.dg/torture/strings/const-str-11.m ++++ b/gcc/testsuite/objc.dg/torture/strings/const-str-11.m +@@ -33,4 +33,4 @@ @interface XStr : XString { + /* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ + /* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ + /* { dg-final { scan-assembler ".long\t__XStrClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._XStr\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t_OBJC_CLASS_._XStr\n\t.(quad|xword)\t.*\n\t.(long|word)\t5\n\t.space} { target { *-*-darwin* && { lp64 } } } } } */ +diff --git a/gcc/testsuite/objc.dg/torture/strings/const-str-9.m b/gcc/testsuite/objc.dg/torture/strings/const-str-9.m +index 966ea5e498d..d3d2916ed06 100644 +--- a/gcc/testsuite/objc.dg/torture/strings/const-str-9.m ++++ b/gcc/testsuite/objc.dg/torture/strings/const-str-9.m +@@ -25,4 +25,4 @@ @interface NSConstantString: NSObject { + /* { dg-final { scan-assembler ".section __OBJC, __cstring_object" { target { *-*-darwin* && { ! lp64 } } } } } */ + /* { dg-final { scan-assembler ".section __DATA, __objc_stringobj" { target { *-*-darwin* && { lp64 } } } } } */ + /* { dg-final { scan-assembler ".long\t__NSConstantStringClassReference\n\t.long\t.*\n\t.long\t5\n\t.data" { target { *-*-darwin* && { ! lp64 } } } } } */ +-/* { dg-final { scan-assembler ".quad\t_OBJC_CLASS_._NSConstantString\n\t.quad\t.*\n\t.long\t5\n\t.space" { target { *-*-darwin* && { lp64 } } } } } */ ++/* { dg-final { scan-assembler {.(quad|xword)\t_OBJC_CLASS_._NSConstantString\n\t.(quad|xword)\t.*\n\t.(long|word)\t5\n\t.space} { target { *-*-darwin* && { lp64 } } } } } */ +diff --git a/gcc/tree-nested.cc b/gcc/tree-nested.cc +index 078ceab3ca3..0308f558036 100644 +--- a/gcc/tree-nested.cc ++++ b/gcc/tree-nested.cc +@@ -611,6 +611,14 @@ get_trampoline_type (struct nesting_info *info) + if (trampoline_type) + return trampoline_type; + ++ /* When trampolines are created off-stack then the only thing we need in the ++ local frame is a single pointer. */ ++ if (flag_off_stack_trampolines) ++ { ++ trampoline_type = build_pointer_type (void_type_node); ++ return trampoline_type; ++ } ++ + align = TRAMPOLINE_ALIGNMENT; + size = TRAMPOLINE_SIZE; + +@@ -2786,17 +2794,27 @@ convert_tramp_reference_op (tree *tp, int *walk_subtrees, void *data) + + /* Compute the address of the field holding the trampoline. */ + x = get_frame_field (info, target_context, x, &wi->gsi); +- x = build_addr (x); +- x = gsi_gimplify_val (info, x, &wi->gsi); + +- /* Do machine-specific ugliness. Normally this will involve +- computing extra alignment, but it can really be anything. */ +- if (descr) +- builtin = builtin_decl_implicit (BUILT_IN_ADJUST_DESCRIPTOR); ++ /* APB: We don't need to do the adjustment calls when using off-stack ++ trampolines, any such adjustment will be done when the off-stack ++ trampoline is created. */ ++ if (!descr && flag_off_stack_trampolines) ++ x = gsi_gimplify_val (info, x, &wi->gsi); + else +- builtin = builtin_decl_implicit (BUILT_IN_ADJUST_TRAMPOLINE); +- call = gimple_build_call (builtin, 1, x); +- x = init_tmp_var_with_call (info, &wi->gsi, call); ++ { ++ x = build_addr (x); ++ ++ x = gsi_gimplify_val (info, x, &wi->gsi); ++ ++ /* Do machine-specific ugliness. Normally this will involve ++ computing extra alignment, but it can really be anything. */ ++ if (descr) ++ builtin = builtin_decl_implicit (BUILT_IN_ADJUST_DESCRIPTOR); ++ else ++ builtin = builtin_decl_implicit (BUILT_IN_ADJUST_TRAMPOLINE); ++ call = gimple_build_call (builtin, 1, x); ++ x = init_tmp_var_with_call (info, &wi->gsi, call); ++ } + + /* Cast back to the proper function type. */ + x = build1 (NOP_EXPR, TREE_TYPE (t), x); +@@ -3375,6 +3393,7 @@ build_init_call_stmt (struct nesting_info *info, tree decl, tree field, + static void + finalize_nesting_tree_1 (struct nesting_info *root) + { ++ gimple_seq cleanup_list = NULL; + gimple_seq stmt_list = NULL; + gimple *stmt; + tree context = root->context; +@@ -3506,9 +3525,48 @@ finalize_nesting_tree_1 (struct nesting_info *root) + if (!field) + continue; + +- x = builtin_decl_implicit (BUILT_IN_INIT_TRAMPOLINE); +- stmt = build_init_call_stmt (root, i->context, field, x); +- gimple_seq_add_stmt (&stmt_list, stmt); ++ if (flag_off_stack_trampolines) ++ { ++ /* We pass a whole bunch of arguments to the builtin function that ++ creates the off-stack trampoline, these are ++ 1. The nested function chain value (that must be passed to the ++ nested function so it can find the function arguments). ++ 2. A pointer to the nested function implementation, ++ 3. The address in the local stack frame where we should write ++ the address of the trampoline. ++ ++ When this code was originally written I just kind of threw ++ everything at the builtin, figuring I'd work out what was ++ actually needed later, I think, the stack pointer could ++ certainly be dropped, arguments #2 and #4 are based off the ++ stack pointer anyway, so #1 doesn't seem to add much value. */ ++ tree arg1, arg2, arg3; ++ ++ gcc_assert (DECL_STATIC_CHAIN (i->context)); ++ arg1 = build_addr (root->frame_decl); ++ arg2 = build_addr (i->context); ++ ++ x = build3 (COMPONENT_REF, TREE_TYPE (field), ++ root->frame_decl, field, NULL_TREE); ++ arg3 = build_addr (x); ++ ++ x = builtin_decl_implicit (BUILT_IN_NESTED_PTR_CREATED); ++ stmt = gimple_build_call (x, 3, arg1, arg2, arg3); ++ gimple_seq_add_stmt (&stmt_list, stmt); ++ ++ /* This call to delete the nested function trampoline is added to ++ the cleanup list, and called when we exit the current scope. */ ++ x = builtin_decl_implicit (BUILT_IN_NESTED_PTR_DELETED); ++ stmt = gimple_build_call (x, 0); ++ gimple_seq_add_stmt (&cleanup_list, stmt); ++ } ++ else ++ { ++ /* Original code to initialise the on stack trampoline. */ ++ x = builtin_decl_implicit (BUILT_IN_INIT_TRAMPOLINE); ++ stmt = build_init_call_stmt (root, i->context, field, x); ++ gimple_seq_add_stmt (&stmt_list, stmt); ++ } + } + } + +@@ -3533,11 +3591,40 @@ finalize_nesting_tree_1 (struct nesting_info *root) + /* If we created initialization statements, insert them. */ + if (stmt_list) + { +- gbind *bind; +- annotate_all_with_location (stmt_list, DECL_SOURCE_LOCATION (context)); +- bind = gimple_seq_first_stmt_as_a_bind (gimple_body (context)); +- gimple_seq_add_seq (&stmt_list, gimple_bind_body (bind)); +- gimple_bind_set_body (bind, stmt_list); ++ if (flag_off_stack_trampolines) ++ { ++ /* Handle the new, off stack trampolines. */ ++ gbind *bind; ++ annotate_all_with_location (stmt_list, DECL_SOURCE_LOCATION (context)); ++ annotate_all_with_location (cleanup_list, DECL_SOURCE_LOCATION (context)); ++ bind = gimple_seq_first_stmt_as_a_bind (gimple_body (context)); ++ gimple_seq_add_seq (&stmt_list, gimple_bind_body (bind)); ++ ++ gimple_seq xxx_list = NULL; ++ ++ if (cleanup_list != NULL) ++ { ++ /* We Maybe shouldn't be creating this try/finally if -fno-exceptions is ++ in use. If this is the case, then maybe we should, instead, be ++ inserting the cleanup code onto every path out of this function? Not ++ yet figured out how we would do this. */ ++ gtry *t = gimple_build_try (stmt_list, cleanup_list, GIMPLE_TRY_FINALLY); ++ gimple_seq_add_stmt (&xxx_list, t); ++ } ++ else ++ xxx_list = stmt_list; ++ ++ gimple_bind_set_body (bind, xxx_list); ++ } ++ else ++ { ++ /* The traditional, on stack trampolines. */ ++ gbind *bind; ++ annotate_all_with_location (stmt_list, DECL_SOURCE_LOCATION (context)); ++ bind = gimple_seq_first_stmt_as_a_bind (gimple_body (context)); ++ gimple_seq_add_seq (&stmt_list, gimple_bind_body (bind)); ++ gimple_bind_set_body (bind, stmt_list); ++ } + } + + /* If a chain_decl was created, then it needs to be registered with +diff --git a/gcc/tree.cc b/gcc/tree.cc +index 4cf3785270b..5cba2ab8171 100644 +--- a/gcc/tree.cc ++++ b/gcc/tree.cc +@@ -9766,6 +9766,23 @@ build_common_builtin_nodes (void) + "__builtin_nonlocal_goto", + ECF_NORETURN | ECF_NOTHROW); + ++ tree ptr_ptr_type_node = build_pointer_type (ptr_type_node); ++ ++ ftype = build_function_type_list (void_type_node, ++ ptr_type_node, // void *chain ++ ptr_type_node, // void *func ++ ptr_ptr_type_node, // void **dst ++ NULL_TREE); ++ local_define_builtin ("__builtin_nested_func_ptr_created", ftype, ++ BUILT_IN_NESTED_PTR_CREATED, ++ "__builtin_nested_func_ptr_created", ECF_NOTHROW); ++ ++ ftype = build_function_type_list (void_type_node, ++ NULL_TREE); ++ local_define_builtin ("__builtin_nested_func_ptr_deleted", ftype, ++ BUILT_IN_NESTED_PTR_DELETED, ++ "__builtin_nested_func_ptr_deleted", ECF_NOTHROW); ++ + ftype = build_function_type_list (void_type_node, + ptr_type_node, ptr_type_node, NULL_TREE); + local_define_builtin ("__builtin_setjmp_setup", ftype, +diff --git a/libada/configure b/libada/configure +index 162d9731f26..9c8b133d817 100755 +--- a/libada/configure ++++ b/libada/configure +@@ -3212,6 +3212,9 @@ case "${host}" in + # sets the default TLS model and affects inlining. + PICFLAG=-fPIC + ;; ++ loongarch*-*-*) ++ PICFLAG=-fpic ++ ;; + mips-sgi-irix6*) + # PIC is the default. + ;; +diff --git a/libatomic/Makefile.am b/libatomic/Makefile.am +index d88515e4a03..3c921f4a86d 100644 +--- a/libatomic/Makefile.am ++++ b/libatomic/Makefile.am +@@ -65,8 +65,13 @@ libatomic_version_script = + libatomic_version_dep = + endif + libatomic_version_info = -version-info $(libtool_VERSION) ++if ENABLE_DARWIN_AT_RPATH ++libatomic_darwin_rpath = -Wc,-nodefaultrpaths ++libatomic_darwin_rpath += -Wl,-rpath,@loader_path ++endif + +-libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script) $(lt_host_flags) ++libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script) \ ++ $(lt_host_flags) $(libatomic_darwin_rpath) + libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c \ + fenv.c fence.c flag.c + +diff --git a/libatomic/Makefile.in b/libatomic/Makefile.in +index 80d25653dc7..179f9217ad6 100644 +--- a/libatomic/Makefile.in ++++ b/libatomic/Makefile.in +@@ -403,7 +403,12 @@ noinst_LTLIBRARIES = libatomic_convenience.la + @LIBAT_BUILD_VERSIONED_SHLIB_GNU_TRUE@@LIBAT_BUILD_VERSIONED_SHLIB_TRUE@libatomic_version_dep = $(top_srcdir)/libatomic.map + @LIBAT_BUILD_VERSIONED_SHLIB_SUN_TRUE@@LIBAT_BUILD_VERSIONED_SHLIB_TRUE@libatomic_version_dep = libatomic.map-sun + libatomic_version_info = -version-info $(libtool_VERSION) +-libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script) $(lt_host_flags) ++@ENABLE_DARWIN_AT_RPATH_TRUE@libatomic_darwin_rpath = \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path ++libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script) \ ++ $(lt_host_flags) $(libatomic_darwin_rpath) ++ + libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c \ + fenv.c fence.c flag.c + +diff --git a/libatomic/configure b/libatomic/configure +index 92853dd8a45..935d5559aed 100755 +--- a/libatomic/configure ++++ b/libatomic/configure +@@ -658,6 +658,8 @@ OPT_LDFLAGS + SECTION_LDFLAGS + enable_aarch64_lse + libtool_VERSION ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + MAINT + MAINTAINER_MODE_FALSE + MAINTAINER_MODE_TRUE +@@ -803,6 +805,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_maintainer_mode + enable_symvers + enable_werror +@@ -1452,6 +1455,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer +@@ -9576,6 +9581,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -9593,10 +9639,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -11382,7 +11437,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11385 "configure" ++#line 11440 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11488,7 +11543,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11491 "configure" ++#line 11546 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11773,6 +11828,15 @@ fi + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ ++ + # For libtool versioning info, format is CURRENT:REVISION:AGE + libtool_VERSION=3:0:2 + +@@ -15900,6 +15964,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + + if test -z "${LIBAT_BUILD_VERSIONED_SHLIB_TRUE}" && test -z "${LIBAT_BUILD_VERSIONED_SHLIB_FALSE}"; then + as_fn_error $? "conditional \"LIBAT_BUILD_VERSIONED_SHLIB\" was never defined. +diff --git a/libatomic/configure.ac b/libatomic/configure.ac +index 5563551aaae..6b9d3085806 100644 +--- a/libatomic/configure.ac ++++ b/libatomic/configure.ac +@@ -156,6 +156,8 @@ AC_SUBST(enable_shared) + AC_SUBST(enable_static) + AM_MAINTAINER_MODE + ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) ++ + # For libtool versioning info, format is CURRENT:REVISION:AGE + libtool_VERSION=3:0:2 + AC_SUBST(libtool_VERSION) +diff --git a/libatomic/testsuite/Makefile.in b/libatomic/testsuite/Makefile.in +index 333980ec2c1..8bc70562e5b 100644 +--- a/libatomic/testsuite/Makefile.in ++++ b/libatomic/testsuite/Makefile.in +@@ -262,6 +262,7 @@ target_alias = @target_alias@ + target_cpu = @target_cpu@ + target_os = @target_os@ + target_vendor = @target_vendor@ ++tmake_file = @tmake_file@ + toolexecdir = @toolexecdir@ + toolexeclibdir = @toolexeclibdir@ + top_build_prefix = @top_build_prefix@ +diff --git a/libatomic/testsuite/lib/libatomic.exp b/libatomic/testsuite/lib/libatomic.exp +index 38f3e5673e2..300e5096f79 100644 +--- a/libatomic/testsuite/lib/libatomic.exp ++++ b/libatomic/testsuite/lib/libatomic.exp +@@ -152,6 +152,7 @@ proc libatomic_init { args } { + lappend ALWAYS_CFLAGS "additional_flags=-I${srcdir}/.." + + if [istarget *-*-darwin*] { ++ lappend ALWAYS_CFLAGS "additional_flags=-B${blddir}/.libs" + lappend ALWAYS_CFLAGS "additional_flags=-shared-libgcc" + } + +diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in +index 08cdd21fb40..8898251161d 100644 +--- a/libbacktrace/Makefile.in ++++ b/libbacktrace/Makefile.in +@@ -15,7 +15,7 @@ + @SET_MAKE@ + + # Makefile.am -- Backtrace Makefile. +-# Copyright (C) 2012-2021 Free Software Foundation, Inc. ++# Copyright (C) 2012-2022 Free Software Foundation, Inc. + + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are +diff --git a/libbacktrace/backtrace.c b/libbacktrace/backtrace.c +index d28575ec897..cf6491682a7 100644 +--- a/libbacktrace/backtrace.c ++++ b/libbacktrace/backtrace.c +@@ -70,6 +70,13 @@ unwind (struct _Unwind_Context *context, void *vdata) + uintptr_t pc; + int ip_before_insn = 0; + ++#ifdef __APPLE__ ++# undef HAVE_GETIPINFO ++# if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 ++# define HAVE_GETIPINFO 1 ++# endif ++#endif ++ + #ifdef HAVE_GETIPINFO + pc = _Unwind_GetIPInfo (context, &ip_before_insn); + #else +diff --git a/libbacktrace/configure b/libbacktrace/configure +index 17f470a4bec..957095aaf1b 100755 +--- a/libbacktrace/configure ++++ b/libbacktrace/configure +@@ -675,6 +675,8 @@ PIC_FLAG + WARN_FLAGS + EXTRA_FLAGS + BACKTRACE_FILE ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + OTOOL64 + OTOOL + LIPO +@@ -799,6 +801,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_largefile + enable_cet + enable_werror +@@ -1447,6 +1450,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --disable-largefile omit support for large files + --enable-cet enable Intel CET in target libraries [default=auto] + --disable-werror disable building with -Werror +@@ -9705,6 +9710,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -9722,10 +9768,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -11511,7 +11566,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11514 "configure" ++#line 11569 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11617,7 +11672,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11620 "configure" ++#line 11675 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11856,6 +11911,15 @@ CC="$lt_save_CC" + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ ++ + # Check whether --enable-largefile was given. + if test "${enable_largefile+set}" = set; then : + enableval=$enable_largefile; +@@ -14273,6 +14337,10 @@ if test -z "${HAVE_DWZ_TRUE}" && test -z "${HAVE_DWZ_FALSE}"; then + as_fn_error $? "conditional \"HAVE_DWZ\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${HAVE_ELF_TRUE}" && test -z "${HAVE_ELF_FALSE}"; then + as_fn_error $? "conditional \"HAVE_ELF\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac +index 597c9705db8..7f89bf33c6b 100644 +--- a/libbacktrace/configure.ac ++++ b/libbacktrace/configure.ac +@@ -84,6 +84,8 @@ AM_CONDITIONAL(HAVE_DWZ, test "$DWZ" != "") + LT_INIT + AM_PROG_LIBTOOL + ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) ++ + AC_SYS_LARGEFILE + + backtrace_supported=yes +diff --git a/libbacktrace/simple.c b/libbacktrace/simple.c +index 6a1a1c92a12..811255ab6b5 100644 +--- a/libbacktrace/simple.c ++++ b/libbacktrace/simple.c +@@ -65,6 +65,13 @@ simple_unwind (struct _Unwind_Context *context, void *vdata) + uintptr_t pc; + int ip_before_insn = 0; + ++#ifdef __APPLE__ ++# undef HAVE_GETIPINFO ++# if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 ++# define HAVE_GETIPINFO 1 ++# endif ++#endif ++ + #ifdef HAVE_GETIPINFO + pc = _Unwind_GetIPInfo (context, &ip_before_insn); + #else +diff --git a/libcc1/Makefile.am b/libcc1/Makefile.am +index 6e3a34ff7e2..44d282c7676 100644 +--- a/libcc1/Makefile.am ++++ b/libcc1/Makefile.am +@@ -55,6 +55,10 @@ marshall_c_source = marshall-c.hh + marshall_cxx_source = marshall-cp.hh + + libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym ++if ENABLE_DARWIN_AT_RPATH ++libcc1plugin_la_LDFLAGS += -Wc,-nodefaultrpaths ++libcc1plugin_la_LDFLAGS += -Wl,-rpath,@loader_path ++endif + libcc1plugin_la_SOURCES = libcc1plugin.cc context.cc context.hh \ + $(shared_source) $(marshall_c_source) + libcc1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_C) +@@ -65,6 +69,10 @@ libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@ + + libcp1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcp1plugin.sym ++if ENABLE_DARWIN_AT_RPATH ++libcp1plugin_la_LDFLAGS += -Wc,-nodefaultrpaths ++libcp1plugin_la_LDFLAGS += -Wl,-rpath,@loader_path ++endif + libcp1plugin_la_SOURCES = libcp1plugin.cc context.cc context.hh \ + $(shared_source) $(marshall_cxx_source) + libcp1plugin.lo_CPPFLAGS = $(CPPFLAGS_FOR_CXX) +@@ -76,6 +84,10 @@ libcp1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + + LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) + libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym ++if ENABLE_DARWIN_AT_RPATH ++libcc1_la_LDFLAGS += -Wc,-nodefaultrpaths ++libcc1_la_LDFLAGS += -Wl,-rpath,@loader_path ++endif + libcc1_la_SOURCES = findcomp.cc libcc1.cc libcp1.cc \ + compiler.cc compiler.hh names.cc names.hh $(shared_source) \ + $(marshall_c_source) $(marshall_cxx_source) +diff --git a/libcc1/Makefile.in b/libcc1/Makefile.in +index f8f590d71e9..440567a47d2 100644 +--- a/libcc1/Makefile.in ++++ b/libcc1/Makefile.in +@@ -90,6 +90,12 @@ build_triplet = @build@ + host_triplet = @host@ + target_triplet = @target@ + @DARWIN_DYNAMIC_LOOKUP_TRUE@am__append_1 = -Wl,-undefined,dynamic_lookup ++@ENABLE_DARWIN_AT_RPATH_TRUE@am__append_2 = -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path ++@ENABLE_DARWIN_AT_RPATH_TRUE@am__append_3 = -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path ++@ENABLE_DARWIN_AT_RPATH_TRUE@am__append_4 = -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path + subdir = . + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 + am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \ +@@ -405,7 +411,8 @@ shared_source = callbacks.cc callbacks.hh connection.cc connection.hh \ + + marshall_c_source = marshall-c.hh + marshall_cxx_source = marshall-cp.hh +-libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym ++libcc1plugin_la_LDFLAGS = -module -export-symbols \ ++ $(srcdir)/libcc1plugin.sym $(am__append_2) + libcc1plugin_la_SOURCES = libcc1plugin.cc context.cc context.hh \ + $(shared_source) $(marshall_c_source) + +@@ -416,7 +423,8 @@ libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@ + +-libcp1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcp1plugin.sym ++libcp1plugin_la_LDFLAGS = -module -export-symbols \ ++ $(srcdir)/libcp1plugin.sym $(am__append_3) + libcp1plugin_la_SOURCES = libcp1plugin.cc context.cc context.hh \ + $(shared_source) $(marshall_cxx_source) + +@@ -428,7 +436,8 @@ libcp1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(CXXFLAGS) $(libcp1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@ + + LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) +-libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym ++libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym \ ++ $(am__append_4) + libcc1_la_SOURCES = findcomp.cc libcc1.cc libcp1.cc \ + compiler.cc compiler.hh names.cc names.hh $(shared_source) \ + $(marshall_c_source) $(marshall_cxx_source) +diff --git a/libcc1/configure b/libcc1/configure +index 01cfb2806da..42fb85a4047 100755 +--- a/libcc1/configure ++++ b/libcc1/configure +@@ -646,6 +646,8 @@ gcc_version + get_gcc_base_ver + CET_HOST_FLAGS + visibility ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + CXXCPP + am__fastdepCXX_FALSE + am__fastdepCXX_TRUE +@@ -787,6 +789,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_cet + with_gcc_major_version_only + enable_werror_always +@@ -1439,6 +1442,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-cet enable Intel CET in host libraries [default=auto] + --enable-werror-always enable -Werror despite compiler version + --enable-plugin enable plugin support +@@ -8971,6 +8976,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -8988,10 +9034,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -10777,7 +10832,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 10780 "configure" ++#line 10835 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -10883,7 +10938,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 10886 "configure" ++#line 10941 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12165,6 +12220,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes +@@ -12182,12 +12278,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + if test "$lt_cv_apple_cc_single_mod" != "yes"; then +- archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring${_lt_dsymutil}" ++ else ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ fi + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + +@@ -14518,6 +14627,14 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ + ac_compiler_gnu=$ac_cv_c_compiler_gnu + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + visibility= + if test "$GXX" = yes; then +@@ -15369,6 +15486,10 @@ if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${DARWIN_DYNAMIC_LOOKUP_TRUE}" && test -z "${DARWIN_DYNAMIC_LOOKUP_FALSE}"; then + as_fn_error $? "conditional \"DARWIN_DYNAMIC_LOOKUP\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libcc1/configure.ac b/libcc1/configure.ac +index 36f5a7e09f1..e8d068e0ac4 100644 +--- a/libcc1/configure.ac ++++ b/libcc1/configure.ac +@@ -38,6 +38,7 @@ AM_MAINTAINER_MODE + LT_INIT([disable-static]) + AM_PROG_LIBTOOL + AC_PROG_CXX ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + + visibility= + if test "$GXX" = yes; then +diff --git a/libffi/Makefile.am b/libffi/Makefile.am +index c6d6f849c53..d2ae0c04c7b 100644 +--- a/libffi/Makefile.am ++++ b/libffi/Makefile.am +@@ -214,7 +214,12 @@ libffi.map: $(top_srcdir)/libffi.map.in + $(COMPILE) -D$(TARGET) -DGENERATE_LIBFFI_MAP \ + -E -x assembler-with-cpp -o $@ $(top_srcdir)/libffi.map.in + +-libffi_la_LDFLAGS = -no-undefined $(libffi_version_info) $(libffi_version_script) $(LTLDFLAGS) $(AM_LTLDFLAGS) ++if ENABLE_DARWIN_AT_RPATH ++libffi_darwin_rpath = -Wl,-rpath,@loader_path ++endif ++libffi_la_LDFLAGS = -no-undefined $(libffi_version_info) \ ++ $(libffi_version_script) $(LTLDFLAGS) $(AM_LTLDFLAGS) \ ++ $(libffi_darwin_rpath) + libffi_la_DEPENDENCIES = $(libffi_la_LIBADD) $(libffi_version_dep) + + AM_CPPFLAGS = -I. -I$(top_srcdir)/include -Iinclude -I$(top_srcdir)/src +diff --git a/libffi/Makefile.in b/libffi/Makefile.in +index 5524a6a571e..34e77a45d1a 100644 +--- a/libffi/Makefile.in ++++ b/libffi/Makefile.in +@@ -597,7 +597,11 @@ AM_CFLAGS = -Wall -g -fexceptions $(CET_FLAGS) $(am__append_2) + @LIBFFI_BUILD_VERSIONED_SHLIB_GNU_TRUE@@LIBFFI_BUILD_VERSIONED_SHLIB_TRUE@libffi_version_dep = libffi.map + @LIBFFI_BUILD_VERSIONED_SHLIB_SUN_TRUE@@LIBFFI_BUILD_VERSIONED_SHLIB_TRUE@libffi_version_dep = libffi.map-sun + libffi_version_info = -version-info `grep -v '^\#' $(srcdir)/libtool-version` +-libffi_la_LDFLAGS = -no-undefined $(libffi_version_info) $(libffi_version_script) $(LTLDFLAGS) $(AM_LTLDFLAGS) ++@ENABLE_DARWIN_AT_RPATH_TRUE@libffi_darwin_rpath = -Wl,-rpath,@loader_path ++libffi_la_LDFLAGS = -no-undefined $(libffi_version_info) \ ++ $(libffi_version_script) $(LTLDFLAGS) $(AM_LTLDFLAGS) \ ++ $(libffi_darwin_rpath) ++ + libffi_la_DEPENDENCIES = $(libffi_la_LIBADD) $(libffi_version_dep) + AM_CPPFLAGS = -I. -I$(top_srcdir)/include -Iinclude -I$(top_srcdir)/src + AM_CCASFLAGS = $(AM_CPPFLAGS) $(CET_FLAGS) +diff --git a/libffi/configure b/libffi/configure +index 575641cca1d..002320ca302 100755 +--- a/libffi/configure ++++ b/libffi/configure +@@ -667,6 +667,8 @@ MAINT + MAINTAINER_MODE_FALSE + MAINTAINER_MODE_TRUE + READELF ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + CXXCPP + CPP + OTOOL64 +@@ -810,6 +812,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_maintainer_mode + enable_pax_emutramp + enable_debug +@@ -1465,6 +1468,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer +@@ -9766,6 +9771,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -9783,10 +9829,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -11572,7 +11627,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11575 "configure" ++#line 11630 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11678,7 +11733,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11681 "configure" ++#line 11736 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12554,6 +12609,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes +@@ -12571,12 +12667,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + if test "$lt_cv_apple_cc_single_mod" != "yes"; then +- archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring${_lt_dsymutil}" ++ else ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ fi + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + +@@ -14926,6 +15035,14 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + # Only expand once: + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}readelf", so it can be a program name with args. +@@ -17071,6 +17188,10 @@ if test -z "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCCAS\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libffi/configure.ac b/libffi/configure.ac +index 014d89d0423..716f20ae313 100644 +--- a/libffi/configure.ac ++++ b/libffi/configure.ac +@@ -55,6 +55,7 @@ AC_SUBST(CET_FLAGS) + AM_PROG_AS + AM_PROG_CC_C_O + AC_PROG_LIBTOOL ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + + AC_CHECK_TOOL(READELF, readelf) + +diff --git a/libgcc/config.host b/libgcc/config.host +index 8c56fcae5d2..48eed32e195 100644 +--- a/libgcc/config.host ++++ b/libgcc/config.host +@@ -82,7 +82,7 @@ m32c*-*-*) + cpu_type=m32c + tmake_file=t-fdpbit + ;; +-aarch64*-*-*) ++aarch64*-*-* | arm64*-*-*) + cpu_type=aarch64 + ;; + alpha*-*-*) +@@ -241,7 +241,46 @@ case ${host} in + ;; + esac + tmake_file="$tmake_file t-slibgcc-darwin" +- extra_parts="crt3.o libd10-uwfef.a crttms.o crttme.o libemutls_w.a" ++ # We are not using libtool to build the libs here, so we need to replicate ++ # a little of the logic around setting Darwin rpaths. Setting an explicit ++ # yes or no is honoured, otherwise we choose a suitable default. ++ # Sadly, this has to be kept in line with the rules in libtool.m4. ++ # This make fragment will override the setting in t-slibgcc-darwin so it ++ # must appear after it. ++ if test "x$enable_darwin_at_rpath" = "x"; then ++ echo "enable_darwin_at_rpath is unset" 1>&2 ++ case ${host} in ++ *-darwin[45678]*) ;; ++ *-darwin9* | *-darwin1[01234]*) ;; # We might default these on later. ++ *-darwin*) ++ echo "but is needed after macOS 10.11 (setting it on)" 1>&2 ++ enable_darwin_at_rpath=yes ++ ;; ++ esac ++ else ++ echo "enable_darwin_at_rpath is '$enable_darwin_at_rpath'" 1>&2 ++ fi ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ tmake_file="$tmake_file t-darwin-rpath " ++ fi ++ case ${host} in ++ *-*-darwin2* | *-*-darwin1[89]* | aarch64*-*-darwin*) ++ tmake_file="t-darwin-min-8 $tmake_file" ++ ;; ++ *-*-darwin9* | *-*-darwin1[0-7]*) ++ tmake_file="t-darwin-min-5 $tmake_file" ++ ;; ++ *-*-darwin[4-8]*) ++ tmake_file="t-darwin-min-1 $tmake_file" ++ ;; ++ *) ++ # Fall back to configuring for the oldest system known to work with ++ # all archs and the current sources. ++ tmake_file="t-darwin-min-5 $tmake_file" ++ echo "Warning: libgcc configured to support macOS 10.5" 1>&2 ++ ;; ++ esac ++ extra_parts="crt3.o crttms.o crttme.o libemutls_w.a" + ;; + *-*-dragonfly*) + tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip" +@@ -384,6 +423,17 @@ aarch64*-*-elf | aarch64*-*-rtems*) + tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm" + md_unwind_header=aarch64/aarch64-unwind.h + ;; ++aarch64*-*-darwin*) ++ extra_parts="$extra_parts crtfastmath.o" ++ tmake_file="${tmake_file} ${cpu_type}/t-aarch64" ++ tmake_file="${tmake_file} ${cpu_type}/t-lse " ++ tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp " ++ tmake_file="${tmake_file} t-crtfm" ++ md_unwind_header=aarch64/aarch64-unwind.h ++ if test x$off_stack_trampolines = xyes; then ++ tmake_file="${tmake_file} ${cpu_type}/t-heap-trampoline" ++ fi ++ ;; + aarch64*-*-freebsd*) + extra_parts="$extra_parts crtfastmath.o" + tmake_file="${tmake_file} ${cpu_type}/t-aarch64" +@@ -408,6 +458,9 @@ aarch64*-*-linux*) + tmake_file="${tmake_file} ${cpu_type}/t-aarch64" + tmake_file="${tmake_file} ${cpu_type}/t-lse t-slibgcc-libgcc" + tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp t-crtfm" ++ if test x$off_stack_trampolines = xyes; then ++ tmake_file="${tmake_file} ${cpu_type}/t-heap-trampoline" ++ fi + ;; + aarch64*-*-vxworks7*) + extra_parts="$extra_parts crtfastmath.o" +@@ -701,12 +754,17 @@ hppa*-*-netbsd*) + i[34567]86-*-darwin*) + tmake_file="$tmake_file i386/t-crtpc t-crtfm i386/t-msabi" + tm_file="$tm_file i386/darwin-lib.h" ++ extra_parts="$extra_parts libd10-uwfef.a " + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" + ;; + x86_64-*-darwin*) + tmake_file="$tmake_file i386/t-crtpc t-crtfm i386/t-msabi" + tm_file="$tm_file i386/darwin-lib.h" ++ extra_parts="$extra_parts libd10-uwfef.a " + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" ++ if test x$off_stack_trampolines = xyes; then ++ tmake_file="${tmake_file} i386/t-heap-trampoline" ++ fi + ;; + i[34567]86-*-elfiamcu) + tmake_file="$tmake_file i386/t-crtstuff t-softfp-sfdftf i386/32/t-softfp i386/32/t-iamcu i386/t-softfp t-softfp t-dfprules" +@@ -773,6 +831,9 @@ x86_64-*-linux*) + tmake_file="${tmake_file} i386/t-crtpc t-crtfm i386/t-crtstuff t-dfprules" + tm_file="${tm_file} i386/elf-lib.h" + md_unwind_header=i386/linux-unwind.h ++ if test x$off_stack_trampolines = xyes; then ++ tmake_file="${tmake_file} i386/t-heap-trampoline" ++ fi + ;; + x86_64-*-kfreebsd*-gnu) + extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o crtfastmath.o" +@@ -1169,12 +1230,14 @@ powerpc-*-darwin*) + # We build the darwin10 EH shim for Rosetta (running on x86 machines). + tm_file="$tm_file i386/darwin-lib.h" + tmake_file="$tmake_file rs6000/t-ppc64-fp rs6000/t-ibm-ldouble" ++ extra_parts="$extra_parts libd10-uwfef.a " + extra_parts="$extra_parts crt2.o crt3_2.o libef_ppc.a dw_ppc.o" + ;; + powerpc64-*-darwin*) + # We build the darwin10 EH shim for Rosetta (running on x86 machines). + tm_file="$tm_file i386/darwin-lib.h" + tmake_file="$tmake_file rs6000/t-darwin64 rs6000/t-ibm-ldouble" ++ extra_parts="$extra_parts libd10-uwfef.a " + extra_parts="$extra_parts crt2.o crt3_2.o libef_ppc.a dw_ppc.o" + ;; + powerpc*-*-freebsd*) +diff --git a/libgcc/config/aarch64/heap-trampoline.c b/libgcc/config/aarch64/heap-trampoline.c +new file mode 100644 +index 00000000000..c8b83681ed7 +--- /dev/null ++++ b/libgcc/config/aarch64/heap-trampoline.c +@@ -0,0 +1,172 @@ ++/* Copyright The GNU Toolchain Authors. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if __APPLE__ ++/* For pthread_jit_write_protect_np */ ++#include ++#endif ++ ++void *allocate_trampoline_page (void); ++int get_trampolines_per_page (void); ++struct tramp_ctrl_data *allocate_tramp_ctrl (struct tramp_ctrl_data *parent); ++void *allocate_trampoline_page (void); ++ ++void __builtin_nested_func_ptr_created (void *chain, void *func, void **dst); ++void __builtin_nested_func_ptr_deleted (void); ++ ++#if defined(__gnu_linux__) ++static const uint32_t aarch64_trampoline_insns[] = { ++ 0xd503245f, /* hint 34 */ ++ 0x580000b1, /* ldr x17, .+20 */ ++ 0x580000d2, /* ldr x18, .+24 */ ++ 0xd61f0220, /* br x17 */ ++ 0xd5033f9f, /* dsb sy */ ++ 0xd5033fdf /* isb */ ++}; ++ ++#elif __APPLE__ ++static const uint32_t aarch64_trampoline_insns[] = { ++ 0xd503245f, /* hint 34 */ ++ 0x580000b1, /* ldr x17, .+20 */ ++ 0x580000d0, /* ldr x16, .+24 */ ++ 0xd61f0220, /* br x17 */ ++ 0xd5033f9f, /* dsb sy */ ++ 0xd5033fdf /* isb */ ++}; ++ ++#else ++#error "Unsupported AArch64 platform for heap trampolines" ++#endif ++ ++struct aarch64_trampoline { ++ uint32_t insns[6]; ++ void *func_ptr; ++ void *chain_ptr; ++}; ++ ++struct tramp_ctrl_data ++{ ++ struct tramp_ctrl_data *prev; ++ ++ int free_trampolines; ++ ++ /* This will be pointing to an executable mmap'ed page. */ ++ struct aarch64_trampoline *trampolines; ++}; ++ ++int ++get_trampolines_per_page (void) ++{ ++ return getpagesize() / sizeof(struct aarch64_trampoline); ++} ++ ++static _Thread_local struct tramp_ctrl_data *tramp_ctrl_curr = NULL; ++ ++void * ++allocate_trampoline_page (void) ++{ ++ void *page; ++ ++#if defined(__gnu_linux__) ++ page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC, ++ MAP_ANON | MAP_PRIVATE, 0, 0); ++#elif __APPLE__ ++ page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC, ++ MAP_ANON | MAP_PRIVATE | MAP_JIT, 0, 0); ++#else ++ page = MAP_FAILED; ++#endif ++ ++ return page; ++} ++ ++struct tramp_ctrl_data * ++allocate_tramp_ctrl (struct tramp_ctrl_data *parent) ++{ ++ struct tramp_ctrl_data *p = malloc (sizeof (struct tramp_ctrl_data)); ++ if (p == NULL) ++ return NULL; ++ ++ p->trampolines = allocate_trampoline_page (); ++ ++ if (p->trampolines == MAP_FAILED) ++ return NULL; ++ ++ p->prev = parent; ++ p->free_trampolines = get_trampolines_per_page(); ++ ++ return p; ++} ++ ++void ++__builtin_nested_func_ptr_created (void *chain, void *func, void **dst) ++{ ++ if (tramp_ctrl_curr == NULL) ++ { ++ tramp_ctrl_curr = allocate_tramp_ctrl (NULL); ++ if (tramp_ctrl_curr == NULL) ++ abort (); ++ } ++ ++ if (tramp_ctrl_curr->free_trampolines == 0) ++ { ++ void *tramp_ctrl = allocate_tramp_ctrl (tramp_ctrl_curr); ++ if (!tramp_ctrl) ++ abort (); ++ ++ tramp_ctrl_curr = tramp_ctrl; ++ } ++ ++ struct aarch64_trampoline *trampoline ++ = &tramp_ctrl_curr->trampolines[get_trampolines_per_page () ++ - tramp_ctrl_curr->free_trampolines]; ++ ++#if __APPLE__ ++ /* Disable write protection for the MAP_JIT regions in this thread (see ++ https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon) */ ++ pthread_jit_write_protect_np (0); ++#endif ++ ++ memcpy (trampoline->insns, aarch64_trampoline_insns, ++ sizeof(aarch64_trampoline_insns)); ++ trampoline->func_ptr = func; ++ trampoline->chain_ptr = chain; ++ ++#if __APPLE__ ++ /* Re-enable write protection. */ ++ pthread_jit_write_protect_np (1); ++#endif ++ ++ tramp_ctrl_curr->free_trampolines -= 1; ++ ++ __builtin___clear_cache ((void *)trampoline->insns, ++ ((void *)trampoline->insns + sizeof(trampoline->insns))); ++ ++ *dst = &trampoline->insns; ++} ++ ++void ++__builtin_nested_func_ptr_deleted (void) ++{ ++ if (tramp_ctrl_curr == NULL) ++ abort (); ++ ++ tramp_ctrl_curr->free_trampolines += 1; ++ ++ if (tramp_ctrl_curr->free_trampolines == get_trampolines_per_page ()) ++ { ++ if (tramp_ctrl_curr->prev == NULL) ++ return; ++ ++ munmap (tramp_ctrl_curr->trampolines, getpagesize()); ++ struct tramp_ctrl_data *prev = tramp_ctrl_curr->prev; ++ free (tramp_ctrl_curr); ++ tramp_ctrl_curr = prev; ++ } ++} +diff --git a/libgcc/config/aarch64/lse.S b/libgcc/config/aarch64/lse.S +index 9c29cf08b59..97b68c42cc1 100644 +--- a/libgcc/config/aarch64/lse.S ++++ b/libgcc/config/aarch64/lse.S +@@ -58,7 +58,11 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + #endif + + /* Declare the symbol gating the LSE implementations. */ ++#if __ELF__ + .hidden __aarch64_have_lse_atomics ++#else ++ .private_extern __aarch64_have_lse_atomics ++#endif + + /* Turn size and memory model defines into mnemonic fragments. */ + #if SIZE == 1 +@@ -164,6 +168,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + #define BTI_C hint 34 + + /* Start and end a function. */ ++#if __ELF__ + .macro STARTFN name + .text + .balign 16 +@@ -187,6 +192,29 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + cbz w(tmp0), \label + .endm + ++#else ++.macro STARTFN name ++ .text ++ .balign 16 ++ .private_extern _\name ++ .cfi_startproc ++_\name: ++ BTI_C ++.endm ++ ++.macro ENDFN name ++ .cfi_endproc ++.endm ++ ++/* Branch to LABEL if LSE is disabled. */ ++.macro JUMP_IF_NOT_LSE label ++ adrp x(tmp0), ___aarch64_have_lse_atomics@PAGE ++ ldrb w(tmp0), [x(tmp0), ___aarch64_have_lse_atomics@PAGEOFF] ++ cbz w(tmp0), \label ++.endm ++ ++#endif ++ + #ifdef L_cas + + STARTFN NAME(cas) +diff --git a/libgcc/config/aarch64/sfp-machine.h b/libgcc/config/aarch64/sfp-machine.h +index be9b42174c4..5dc1827ee3a 100644 +--- a/libgcc/config/aarch64/sfp-machine.h ++++ b/libgcc/config/aarch64/sfp-machine.h +@@ -122,6 +122,27 @@ void __sfp_handle_exceptions (int); + + + /* Define ALIASNAME as a strong alias for NAME. */ ++#if defined __APPLE__ ++/* Mach-O doesn't support aliasing, so we build a secondary function for ++ the alias - we need to do a bit of a dance to find out what the type of ++ the arguments is and then apply that to the secondary function. ++ If these functions ever return anything but CMPtype we need to revisit ++ this... */ ++typedef float alias_HFtype __attribute__ ((mode (HF))); ++typedef float alias_SFtype __attribute__ ((mode (SF))); ++typedef float alias_DFtype __attribute__ ((mode (DF))); ++typedef float alias_TFtype __attribute__ ((mode (TF))); ++#define ALIAS_SELECTOR \ ++ CMPtype (*) (alias_HFtype, alias_HFtype): (alias_HFtype) 0, \ ++ CMPtype (*) (alias_SFtype, alias_SFtype): (alias_SFtype) 0, \ ++ CMPtype (*) (alias_DFtype, alias_DFtype): (alias_DFtype) 0, \ ++ CMPtype (*) (alias_TFtype, alias_TFtype): (alias_TFtype) 0 ++#define strong_alias(name, aliasname) \ ++ CMPtype aliasname (__typeof (_Generic (name, ALIAS_SELECTOR)) a, \ ++ __typeof (_Generic (name, ALIAS_SELECTOR)) b) \ ++ { return name (a, b); } ++#else + # define strong_alias(name, aliasname) _strong_alias(name, aliasname) + # define _strong_alias(name, aliasname) \ + extern __typeof (name) aliasname __attribute__ ((alias (#name))); ++#endif +diff --git a/libgcc/config/aarch64/t-darwin b/libgcc/config/aarch64/t-darwin +new file mode 100644 +index 00000000000..f6ecda7b608 +--- /dev/null ++++ b/libgcc/config/aarch64/t-darwin +@@ -0,0 +1,7 @@ ++# Ensure we have a suitable minimum OS version. ++ ++HOST_LIBGCC2_CFLAGS += -mmacosx-version-min=11.0 ++ ++LIB2_SIDITI_CONV_FUNCS = yes ++ ++BUILD_LIBGCCS1 = +diff --git a/libgcc/config/aarch64/t-heap-trampoline b/libgcc/config/aarch64/t-heap-trampoline +new file mode 100644 +index 00000000000..3f70c2cd0c0 +--- /dev/null ++++ b/libgcc/config/aarch64/t-heap-trampoline +@@ -0,0 +1,20 @@ ++# Copyright The GNU Toolchain Authors. ++ ++# This file is part of GCC. ++# ++# GCC 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 3, or (at your option) ++# any later version. ++# ++# GCC is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GCC; see the file COPYING3. If not see ++# . ++ ++LIB2ADD += $(srcdir)/config/aarch64/heap-trampoline.c ++HOST_LIBGCC2_CFLAGS += -mmacosx-version-min=11.0 +diff --git a/libgcc/config/i386/heap-trampoline.c b/libgcc/config/i386/heap-trampoline.c +new file mode 100644 +index 00000000000..96e13bf828e +--- /dev/null ++++ b/libgcc/config/i386/heap-trampoline.c +@@ -0,0 +1,172 @@ ++/* Copyright The GNU Toolchain Authors. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400 ++/* For pthread_jit_write_protect_np */ ++#include ++#endif ++ ++void *allocate_trampoline_page (void); ++int get_trampolines_per_page (void); ++struct tramp_ctrl_data *allocate_tramp_ctrl (struct tramp_ctrl_data *parent); ++void *allocate_trampoline_page (void); ++ ++void __builtin_nested_func_ptr_created (void *chain, void *func, void **dst); ++void __builtin_nested_func_ptr_deleted (void); ++ ++static const uint8_t trampoline_insns[] = { ++ /* movabs $,%r11 */ ++ 0x49, 0xbb, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ ++ /* movabs $,%r10 */ ++ 0x49, 0xba, ++ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ++ ++ /* rex.WB jmpq *%r11 */ ++ 0x41, 0xff, 0xe3 ++}; ++ ++union ix86_trampoline { ++ uint8_t insns[sizeof(trampoline_insns)]; ++ ++ struct __attribute__((packed)) fields { ++ uint8_t insn_0[2]; ++ void *func_ptr; ++ uint8_t insn_1[2]; ++ void *chain_ptr; ++ uint8_t insn_2[3]; ++ } fields; ++}; ++ ++struct tramp_ctrl_data ++{ ++ struct tramp_ctrl_data *prev; ++ ++ int free_trampolines; ++ ++ /* This will be pointing to an executable mmap'ed page. */ ++ union ix86_trampoline *trampolines; ++}; ++ ++int ++get_trampolines_per_page (void) ++{ ++ return getpagesize() / sizeof(union ix86_trampoline); ++} ++ ++static _Thread_local struct tramp_ctrl_data *tramp_ctrl_curr = NULL; ++ ++void * ++allocate_trampoline_page (void) ++{ ++ void *page; ++ ++#if defined(__gnu_linux__) ++ page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC, ++ MAP_ANON | MAP_PRIVATE, 0, 0); ++#elif __APPLE__ ++# if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400 ++ page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC, ++ MAP_ANON | MAP_PRIVATE | MAP_JIT, 0, 0); ++# else ++ page = mmap (0, getpagesize (), PROT_WRITE | PROT_EXEC, ++ MAP_ANON | MAP_PRIVATE, 0, 0); ++# endif ++#else ++ page = MAP_FAILED; ++#endif ++ ++ return page; ++} ++ ++struct tramp_ctrl_data * ++allocate_tramp_ctrl (struct tramp_ctrl_data *parent) ++{ ++ struct tramp_ctrl_data *p = malloc (sizeof (struct tramp_ctrl_data)); ++ if (p == NULL) ++ return NULL; ++ ++ p->trampolines = allocate_trampoline_page (); ++ ++ if (p->trampolines == MAP_FAILED) ++ return NULL; ++ ++ p->prev = parent; ++ p->free_trampolines = get_trampolines_per_page(); ++ ++ return p; ++} ++ ++void ++__builtin_nested_func_ptr_created (void *chain, void *func, void **dst) ++{ ++ if (tramp_ctrl_curr == NULL) ++ { ++ tramp_ctrl_curr = allocate_tramp_ctrl (NULL); ++ if (tramp_ctrl_curr == NULL) ++ abort (); ++ } ++ ++ if (tramp_ctrl_curr->free_trampolines == 0) ++ { ++ void *tramp_ctrl = allocate_tramp_ctrl (tramp_ctrl_curr); ++ if (!tramp_ctrl) ++ abort (); ++ ++ tramp_ctrl_curr = tramp_ctrl; ++ } ++ ++ union ix86_trampoline *trampoline ++ = &tramp_ctrl_curr->trampolines[get_trampolines_per_page () ++ - tramp_ctrl_curr->free_trampolines]; ++ ++#if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400 ++ /* Disable write protection for the MAP_JIT regions in this thread (see ++ https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon) */ ++ pthread_jit_write_protect_np (0); ++#endif ++ ++ memcpy (trampoline->insns, trampoline_insns, ++ sizeof(trampoline_insns)); ++ trampoline->fields.func_ptr = func; ++ trampoline->fields.chain_ptr = chain; ++ ++#if __APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101400 ++ /* Re-enable write protection. */ ++ pthread_jit_write_protect_np (1); ++#endif ++ ++ tramp_ctrl_curr->free_trampolines -= 1; ++ ++ __builtin___clear_cache ((void *)trampoline->insns, ++ ((void *)trampoline->insns + sizeof(trampoline->insns))); ++ ++ *dst = &trampoline->insns; ++} ++ ++void ++__builtin_nested_func_ptr_deleted (void) ++{ ++ if (tramp_ctrl_curr == NULL) ++ abort (); ++ ++ tramp_ctrl_curr->free_trampolines += 1; ++ ++ if (tramp_ctrl_curr->free_trampolines == get_trampolines_per_page ()) ++ { ++ if (tramp_ctrl_curr->prev == NULL) ++ return; ++ ++ munmap (tramp_ctrl_curr->trampolines, getpagesize()); ++ struct tramp_ctrl_data *prev = tramp_ctrl_curr->prev; ++ free (tramp_ctrl_curr); ++ tramp_ctrl_curr = prev; ++ } ++} +diff --git a/libgcc/config/i386/t-heap-trampoline b/libgcc/config/i386/t-heap-trampoline +new file mode 100644 +index 00000000000..76f438d9529 +--- /dev/null ++++ b/libgcc/config/i386/t-heap-trampoline +@@ -0,0 +1,20 @@ ++# Copyright The GNU Toolchain Authors. ++ ++# This file is part of GCC. ++# ++# GCC 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 3, or (at your option) ++# any later version. ++# ++# GCC is distributed in the hope that it will be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++# General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with GCC; see the file COPYING3. If not see ++# . ++ ++LIB2ADD += $(srcdir)/config/i386/heap-trampoline.c ++HOST_LIBGCC2_CFLAGS += -mmacosx-version-min=10.8 +diff --git a/libgcc/config/t-darwin b/libgcc/config/t-darwin +index 299d26c2c96..a708583d965 100644 +--- a/libgcc/config/t-darwin ++++ b/libgcc/config/t-darwin +@@ -1,15 +1,15 @@ + # Set this as a minimum (unless overriden by arch t-files) since it's a + # reasonable lowest common denominator that works for all our archs. +-HOST_LIBGCC2_CFLAGS += -mmacosx-version-min=10.4 ++HOST_LIBGCC2_CFLAGS += $(DARWIN_MIN_LIB_VERSION) + + crt3.o: $(srcdir)/config/darwin-crt3.c +- $(crt_compile) -mmacosx-version-min=10.4 -c $< ++ $(crt_compile) $(DARWIN_MIN_CRT_VERSION) -c $< + + crttms.o: $(srcdir)/config/darwin-crt-tm.c +- $(crt_compile) -mmacosx-version-min=10.4 -DSTART -c $< ++ $(crt_compile) $(DARWIN_MIN_CRT_VERSION) -DSTART -c $< + + crttme.o: $(srcdir)/config/darwin-crt-tm.c +- $(crt_compile) -mmacosx-version-min=10.4 -DEND -c $< ++ $(crt_compile) $(DARWIN_MIN_CRT_VERSION) -DEND -c $< + + # Make emutls weak so that we can deal with -static-libgcc, override the + # hidden visibility when this is present in libgcc_eh. +@@ -24,7 +24,8 @@ libemutls_w.a: emutls_s.o + $(AR_CREATE_FOR_TARGET) $@ $< + $(RANLIB_FOR_TARGET) $@ + +-# Patch to __Unwind_Find_Enclosing_Function for Darwin10. ++# This has to be built for 10.6, even if the toolchain will not target that ++# version + d10-uwfef.o: $(srcdir)/config/darwin10-unwind-find-enc-func.c libgcc_tm.h + $(crt_compile) -mmacosx-version-min=10.6 -c $< + +diff --git a/libgcc/config/t-darwin-min-1 b/libgcc/config/t-darwin-min-1 +new file mode 100644 +index 00000000000..8c2cf8acd39 +--- /dev/null ++++ b/libgcc/config/t-darwin-min-1 +@@ -0,0 +1,3 @@ ++# Support building with -mmacosx-version-min back to 10.1. ++DARWIN_MIN_LIB_VERSION = -mmacosx-version-min=10.4 ++DARWIN_MIN_CRT_VERSION = -mmacosx-version-min=10.1 +diff --git a/libgcc/config/t-darwin-min-4 b/libgcc/config/t-darwin-min-4 +new file mode 100644 +index 00000000000..04e980de4d5 +--- /dev/null ++++ b/libgcc/config/t-darwin-min-4 +@@ -0,0 +1,3 @@ ++# Support building with -mmacosx-version-min back to 10.4. ++DARWIN_MIN_LIB_VERSION = -mmacosx-version-min=10.4 ++DARWIN_MIN_CRT_VERSION = -mmacosx-version-min=10.4 +diff --git a/libgcc/config/t-darwin-min-5 b/libgcc/config/t-darwin-min-5 +new file mode 100644 +index 00000000000..138193151e7 +--- /dev/null ++++ b/libgcc/config/t-darwin-min-5 +@@ -0,0 +1,3 @@ ++# Support building with -mmacosx-version-min back to 10.5. ++DARWIN_MIN_LIB_VERSION = -mmacosx-version-min=10.5 ++DARWIN_MIN_CRT_VERSION = -mmacosx-version-min=10.5 +diff --git a/libgcc/config/t-darwin-min-8 b/libgcc/config/t-darwin-min-8 +new file mode 100644 +index 00000000000..9efc9dc0257 +--- /dev/null ++++ b/libgcc/config/t-darwin-min-8 +@@ -0,0 +1,3 @@ ++# Support building with -mmacosx-version-min back to 10.8. ++DARWIN_MIN_LIB_VERSION = -mmacosx-version-min=10.8 ++DARWIN_MIN_CRT_VERSION = -mmacosx-version-min=10.8 +diff --git a/libgcc/config/t-darwin-rpath b/libgcc/config/t-darwin-rpath +new file mode 100644 +index 00000000000..951539de7aa +--- /dev/null ++++ b/libgcc/config/t-darwin-rpath +@@ -0,0 +1,5 @@ ++# Use @rpath and add a search path to exes and dylibs that depend on this. ++SHLIB_RPATH = @rpath ++ ++# Enable the libgcc_s.1.dylib compatibility lib to find the dependent 1.1.dylib. ++SHLIB_LOADER_PATH = -Wl,-rpath,@loader_path +diff --git a/libgcc/config/t-slibgcc-darwin b/libgcc/config/t-slibgcc-darwin +index a8f69666a82..ee449de32e6 100644 +--- a/libgcc/config/t-slibgcc-darwin ++++ b/libgcc/config/t-slibgcc-darwin +@@ -1,4 +1,4 @@ +-# Build a shared libgcc library with the darwin linker. ++# Build a shared libgcc library able to use embedded runpaths. + + SHLIB_SOVERSION = 1.1 + SHLIB_SO_MINVERSION = 1 +@@ -6,7 +6,6 @@ SHLIB_VERSTRING = -compatibility_version $(SHLIB_SO_MINVERSION) \ + -current_version $(SHLIB_SOVERSION) + SHLIB_EXT = .dylib + SHLIB_LC = -lSystem +-SHLIB_INSTALL_DIR = $(slibdir) + + SHLIB_MKMAP = $(srcdir)/mkmap-flat.awk + SHLIB_MKMAP_OPTS = -v leading_underscore=1 +@@ -23,11 +22,20 @@ SHLIB_SONAME = @shlib_base_name@$(SHLIB_EXT) + # subdir. The code under MULTIBUILDTOP combines these into a single FAT + # library, that is what we eventually install. + ++# When enable_darwin_at_rpath is true, use @rpath instead of $(slibdir) for ++# this and dylibs that depend on this. So this def must come first and be ++# overridden in a make fragment that depends on the rpath setting. ++SHLIB_RPATH = $(slibdir) ++ ++# Likewise, we only want to add an @loader_path to the shared libs when ++# we have enable_darwin_at_rpath. ++SHLIB_LOADER_PATH = ++ + SHLIB_LINK = $(CC) $(LIBGCC2_CFLAGS) $(LDFLAGS) -dynamiclib -nodefaultlibs \ +- -install_name $(SHLIB_INSTALL_DIR)/$(SHLIB_INSTALL_NAME) \ ++ -install_name $(SHLIB_RPATH)/$(SHLIB_INSTALL_NAME) \ + -single_module -o $(SHLIB_DIR)/$(SHLIB_SONAME) \ + -Wl,-exported_symbols_list,$(SHLIB_MAP) \ +- $(SHLIB_VERSTRING) \ ++ $(SHLIB_VERSTRING) -nodefaultrpaths \ + @multilib_flags@ @shlib_objs@ $(SHLIB_LC) + + # we do our own thing +@@ -63,9 +71,9 @@ EHS_INSTNAME = libgcc_ehs.$(SHLIB_SOVERSION)$(SHLIB_EXT) + libgcc_ehs$(SHLIB_EXT): $(LIBEHSOBJS) $(extra-parts) + mkdir -p $(MULTIDIR) + $(CC) $(LIBGCC2_CFLAGS) $(LDFLAGS) -dynamiclib -nodefaultlibs \ +- -install_name $(SHLIB_INSTALL_DIR)/$(EHS_INSTNAME) \ ++ -install_name $(SHLIB_RPATH)/$(EHS_INSTNAME) \ + -o $(MULTIDIR)/libgcc_ehs$(SHLIB_EXT) $(SHLIB_VERSTRING) \ +- $(LIBEHSOBJS) $(SHLIB_LC) ++ -nodefaultrpaths $(LIBEHSOBJS) $(SHLIB_LC) + + all: libgcc_ehs$(SHLIB_EXT) + +@@ -121,12 +129,13 @@ libgcc_s.1.dylib: all-multi libgcc_s.$(SHLIB_SOVERSION)$(SHLIB_EXT) \ + cp ../$${mlib}/libgcc/$${mlib}/libgcc_ehs$(SHLIB_EXT) \ + ./libgcc_ehs.$(SHLIB_SOVERSION)$(SHLIB_EXT)_T_$${mlib} || exit 1 ; \ + arch=`$(LIPO) -info libgcc_s.$(SHLIB_SOVERSION)$(SHLIB_EXT)_T_$${mlib} | sed -e 's/.*:\ //'` ; \ +- $(CC) -arch $${arch} -nodefaultlibs -dynamiclib \ ++ $(CC) -arch $${arch} -nodefaultlibs -dynamiclib -nodefaultrpaths \ ++ $(SHLIB_LOADER_PATH) \ + -o libgcc_s.1$(SHLIB_EXT)_T_$${mlib} \ + -Wl,-reexport_library,libgcc_s.$(SHLIB_SOVERSION)$(SHLIB_EXT)_T_$${mlib} \ + -Wl,-reexport_library,libgcc_ehs.$(SHLIB_SOVERSION)$(SHLIB_EXT)_T_$${mlib} \ +- -install_name $(SHLIB_INSTALL_DIR)/libgcc_s.1.dylib \ +- -compatibility_version 1 -current_version 1 ; \ ++ -install_name $(SHLIB_RPATH)/libgcc_s.1.dylib \ ++ -compatibility_version 1 -current_version 1.1 ; \ + done + $(LIPO) -output libgcc_s.1$(SHLIB_EXT) -create libgcc_s.1$(SHLIB_EXT)_T* + rm libgcc_s.$(SHLIB_SOVERSION)$(SHLIB_EXT)_T* +@@ -140,13 +149,14 @@ libgcc_s.1.dylib: all-multi libgcc_s.$(SHLIB_SOVERSION)$(SHLIB_EXT) + cp ../$${mlib}/libgcc/$${mlib}/libgcc_s$(SHLIB_EXT) \ + ./libgcc_s.$(SHLIB_SOVERSION)$(SHLIB_EXT)_T_$${mlib} || exit 1 ; \ + arch=`$(LIPO) -info libgcc_s.$(SHLIB_SOVERSION)$(SHLIB_EXT)_T_$${mlib} | sed -e 's/.*:\ //'` ; \ +- $(CC) -arch $${arch} -nodefaultlibs -dynamiclib \ ++ $(CC) -arch $${arch} -nodefaultlibs -dynamiclib -nodefaultrpaths \ ++ $(SHLIB_LOADER_PATH) \ + -o libgcc_s.1$(SHLIB_EXT)_T_$${mlib} \ + -Wl,-reexport_library,libgcc_s.$(SHLIB_SOVERSION)$(SHLIB_EXT)_T_$${mlib} \ + -lSystem \ + -Wl,-reexported_symbols_list,$(srcdir)/config/darwin-unwind.ver \ +- -install_name $(SHLIB_INSTALL_DIR)/libgcc_s.1.dylib \ +- -compatibility_version 1 -current_version 1 ; \ ++ -install_name $(SHLIB_RPATH)/libgcc_s.1.dylib \ ++ -compatibility_version 1 -current_version 1.1 ; \ + done + $(LIPO) -output libgcc_s.1$(SHLIB_EXT) -create libgcc_s.1$(SHLIB_EXT)_T* + rm libgcc_s.$(SHLIB_SOVERSION)$(SHLIB_EXT)_T* +diff --git a/libgcc/configure b/libgcc/configure +index 1f9b2ac578b..a5c228bc3a1 100755 +--- a/libgcc/configure ++++ b/libgcc/configure +@@ -630,7 +630,6 @@ LIPO + AR + toolexeclibdir + toolexecdir +-enable_gcov + target_subdir + host_subdir + build_subdir +@@ -654,6 +653,8 @@ build_cpu + build + with_aix_soname + enable_vtable_verify ++enable_gcov ++off_stack_trampolines + enable_shared + libgcc_topdir + target_alias +@@ -701,6 +702,8 @@ with_target_subdir + with_cross_host + with_ld + enable_shared ++enable_off_stack_trampolines ++enable_gcov + enable_vtable_verify + with_aix_soname + enable_version_specific_runtime_libs +@@ -708,7 +711,6 @@ with_toolexeclibdir + with_slibdir + enable_maintainer_mode + with_build_libsubdir +-enable_gcov + enable_largefile + enable_decimal_float + with_system_libunwind +@@ -1342,12 +1344,15 @@ Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-shared don't provide a shared libgcc ++ --enable-off-stack-trampolines ++ Specify whether to support generating off-stack trampolines ++ ++ --disable-gcov don't provide libgcov and related host tools + --enable-vtable-verify Enable vtable verification feature + --enable-version-specific-runtime-libs Specify that runtime libraries should be installed in a compiler-specific directory + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer +- --disable-gcov don't provide libgcov and related host tools + --disable-largefile omit support for large files + --enable-decimal-float={no,yes,bid,dpd} + enable decimal float extension to C. Selecting 'bid' +@@ -2252,6 +2257,48 @@ fi + + + ++# Check whether --enable-off-stack-trampolines was given. ++if test "${enable_off_stack_trampolines+set}" = set; then : ++ enableval=$enable_off_stack_trampolines; ++case "$target" in ++ x86_64-*-linux* | x86_64-*-darwin1[4-9]* | x86_64-*-darwin2*) ++ off_stack_trampolines=$enableval ++ ;; ++ aarch64*-*-linux* ) ++ off_stack_trampolines=$enableval ++ ;; ++ aarch64*-*darwin* ) ++ off_stack_trampolines=$enableval ++ ;; ++ *) ++ as_fn_error $? "Configure option --enable-off-stack-trampolines is not supported \ ++for this platform" "$LINENO" 5 ++ off_stack_trampolines=no ++ ;; ++esac ++else ++ ++case "$target" in ++ *-*-darwin2*) ++ off_stack_trampolines=yes ++ ;; ++ *) ++ off_stack_trampolines=no ++ ;; ++esac ++fi ++ ++ ++ ++# Check whether --enable-gcov was given. ++if test "${enable_gcov+set}" = set; then : ++ enableval=$enable_gcov; ++else ++ enable_gcov=yes ++fi ++ ++ ++ + # Check whether --enable-vtable-verify was given. + if test "${enable_vtable_verify+set}" = set; then : + enableval=$enable_vtable_verify; case "$enableval" in +diff --git a/libgcc/configure.ac b/libgcc/configure.ac +index 2fc9d5d7c93..7d11bf00142 100644 +--- a/libgcc/configure.ac ++++ b/libgcc/configure.ac +@@ -68,6 +68,40 @@ AC_ARG_ENABLE(shared, + ], [enable_shared=yes]) + AC_SUBST(enable_shared) + ++AC_ARG_ENABLE([off-stack-trampolines], ++ [AS_HELP_STRING([--enable-off-stack-trampolines] ++ [Specify whether to support generating off-stack trampolines])],[ ++case "$target" in ++ x86_64-*-linux* | x86_64-*-darwin1[[4-9]]* | x86_64-*-darwin2*) ++ off_stack_trampolines=$enableval ++ ;; ++ aarch64*-*-linux* ) ++ off_stack_trampolines=$enableval ++ ;; ++ aarch64*-*darwin* ) ++ off_stack_trampolines=$enableval ++ ;; ++ *) ++ AC_MSG_ERROR([Configure option --enable-off-stack-trampolines is not supported \ ++for this platform]) ++ off_stack_trampolines=no ++ ;; ++esac],[ ++case "$target" in ++ *-*-darwin2*) ++ off_stack_trampolines=yes ++ ;; ++ *) ++ off_stack_trampolines=no ++ ;; ++esac]) ++AC_SUBST(off_stack_trampolines) ++ ++AC_ARG_ENABLE(gcov, ++[ --disable-gcov don't provide libgcov and related host tools], ++[], [enable_gcov=yes]) ++AC_SUBST(enable_gcov) ++ + AC_ARG_ENABLE(vtable-verify, + [ --enable-vtable-verify Enable vtable verification feature ], + [case "$enableval" in +diff --git a/libgcc/libgcc-std.ver.in b/libgcc/libgcc-std.ver.in +index 513ddd0bd0d..fc0b4052a3b 100644 +--- a/libgcc/libgcc-std.ver.in ++++ b/libgcc/libgcc-std.ver.in +@@ -1943,4 +1943,7 @@ GCC_4.8.0 { + GCC_7.0.0 { + __PFX__divmoddi4 + __PFX__divmodti4 ++ ++ __builtin_nested_func_ptr_created ++ __builtin_nested_func_ptr_deleted + } +diff --git a/libgcc/libgcc2.h b/libgcc/libgcc2.h +index fc24ac34502..536e517b62f 100644 +--- a/libgcc/libgcc2.h ++++ b/libgcc/libgcc2.h +@@ -29,6 +29,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + #pragma GCC visibility push(default) + #endif + ++extern void __builtin_nested_func_ptr_created (void *, void *, void **); ++extern void __builtin_nested_func_ptr_deleted (void); ++ + extern int __gcc_bcmp (const unsigned char *, const unsigned char *, size_t); + extern void __clear_cache (void *, void *); + extern void __eprintf (const char *, const char *, unsigned int, const char *) +diff --git a/libgfortran/Makefile.am b/libgfortran/Makefile.am +index 5ce0cd7cd05..2073bf6c5ef 100644 +--- a/libgfortran/Makefile.am ++++ b/libgfortran/Makefile.am +@@ -37,6 +37,11 @@ else + version_arg = + version_dep = + endif ++extra_darwin_ldflags_libgfortran = @extra_ldflags_libgfortran@ ++if ENABLE_DARWIN_AT_RPATH ++extra_darwin_ldflags_libgfortran += -Wc,-nodefaultrpaths ++extra_darwin_ldflags_libgfortran += -Wl,-rpath,@loader_path ++endif + + gfor_c_HEADERS = ISO_Fortran_binding.h + gfor_cdir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include +@@ -50,7 +55,7 @@ libgfortran_la_LINK = $(LINK) $(libgfortran_la_LDFLAGS) + libgfortran_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ + $(LTLDFLAGS) $(LIBQUADLIB) ../libbacktrace/libbacktrace.la \ + $(HWCAP_LDFLAGS) \ +- $(LIBM) $(extra_ldflags_libgfortran) \ ++ $(LIBM) $(extra_darwin_ldflags_libgfortran) \ + $(version_arg) -Wc,-shared-libgcc + libgfortran_la_DEPENDENCIES = $(version_dep) libgfortran.spec $(LIBQUADLIB_DEP) + +diff --git a/libgfortran/Makefile.in b/libgfortran/Makefile.in +index 7ac6bfba657..52dd5f1819e 100644 +--- a/libgfortran/Makefile.in ++++ b/libgfortran/Makefile.in +@@ -91,8 +91,10 @@ POST_UNINSTALL = : + build_triplet = @build@ + host_triplet = @host@ + target_triplet = @target@ +-@LIBGFOR_MINIMAL_TRUE@am__append_1 = -DLIBGFOR_MINIMAL +-@LIBGFOR_MINIMAL_FALSE@am__append_2 = \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@am__append_1 = -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path ++@LIBGFOR_MINIMAL_TRUE@am__append_2 = -DLIBGFOR_MINIMAL ++@LIBGFOR_MINIMAL_FALSE@am__append_3 = \ + @LIBGFOR_MINIMAL_FALSE@io/close.c \ + @LIBGFOR_MINIMAL_FALSE@io/file_pos.c \ + @LIBGFOR_MINIMAL_FALSE@io/format.c \ +@@ -110,7 +112,7 @@ target_triplet = @target@ + @LIBGFOR_MINIMAL_FALSE@io/fbuf.c \ + @LIBGFOR_MINIMAL_FALSE@io/async.c + +-@LIBGFOR_MINIMAL_FALSE@am__append_3 = \ ++@LIBGFOR_MINIMAL_FALSE@am__append_4 = \ + @LIBGFOR_MINIMAL_FALSE@intrinsics/access.c \ + @LIBGFOR_MINIMAL_FALSE@intrinsics/c99_functions.c \ + @LIBGFOR_MINIMAL_FALSE@intrinsics/chdir.c \ +@@ -143,9 +145,9 @@ target_triplet = @target@ + @LIBGFOR_MINIMAL_FALSE@intrinsics/umask.c \ + @LIBGFOR_MINIMAL_FALSE@intrinsics/unlink.c + +-@IEEE_SUPPORT_TRUE@am__append_4 = ieee/ieee_helper.c +-@LIBGFOR_MINIMAL_TRUE@am__append_5 = runtime/minimal.c +-@LIBGFOR_MINIMAL_FALSE@am__append_6 = \ ++@IEEE_SUPPORT_TRUE@am__append_5 = ieee/ieee_helper.c ++@LIBGFOR_MINIMAL_TRUE@am__append_6 = runtime/minimal.c ++@LIBGFOR_MINIMAL_FALSE@am__append_7 = \ + @LIBGFOR_MINIMAL_FALSE@runtime/backtrace.c \ + @LIBGFOR_MINIMAL_FALSE@runtime/convert_char.c \ + @LIBGFOR_MINIMAL_FALSE@runtime/environ.c \ +@@ -157,7 +159,7 @@ target_triplet = @target@ + + + # dummy sources for libtool +-@onestep_TRUE@am__append_7 = libgfortran_c.c libgfortran_f.f90 ++@onestep_TRUE@am__append_8 = libgfortran_c.c libgfortran_f.f90 + subdir = . + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 + am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \ +@@ -589,7 +591,7 @@ AMTAR = @AMTAR@ + + # Some targets require additional compiler options for IEEE compatibility. + AM_CFLAGS = @AM_CFLAGS@ -fcx-fortran-rules $(SECTION_FLAGS) \ +- $(IEEE_FLAGS) $(am__append_1) ++ $(IEEE_FLAGS) $(am__append_2) + AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ + AM_FCFLAGS = @AM_FCFLAGS@ $(IEEE_FLAGS) + AR = @AR@ +@@ -748,6 +750,8 @@ gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER) + @LIBGFOR_USE_SYMVER_FALSE@version_dep = + @LIBGFOR_USE_SYMVER_GNU_TRUE@@LIBGFOR_USE_SYMVER_TRUE@version_dep = gfortran.ver + @LIBGFOR_USE_SYMVER_SUN_TRUE@@LIBGFOR_USE_SYMVER_TRUE@version_dep = gfortran.ver-sun gfortran.ver ++extra_darwin_ldflags_libgfortran = @extra_ldflags_libgfortran@ \ ++ $(am__append_1) + gfor_c_HEADERS = ISO_Fortran_binding.h + gfor_cdir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include + LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS)) \ +@@ -759,7 +763,7 @@ libgfortran_la_LINK = $(LINK) $(libgfortran_la_LDFLAGS) + libgfortran_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ + $(LTLDFLAGS) $(LIBQUADLIB) ../libbacktrace/libbacktrace.la \ + $(HWCAP_LDFLAGS) \ +- $(LIBM) $(extra_ldflags_libgfortran) \ ++ $(LIBM) $(extra_darwin_ldflags_libgfortran) \ + $(version_arg) -Wc,-shared-libgcc + + libgfortran_la_DEPENDENCIES = $(version_dep) libgfortran.spec $(LIBQUADLIB_DEP) +@@ -780,7 +784,7 @@ AM_CPPFLAGS = -iquote$(srcdir)/io -I$(srcdir)/$(MULTISRCTOP)../gcc \ + -I$(MULTIBUILDTOP)../libbacktrace \ + -I../libbacktrace + +-gfor_io_src = io/size_from_kind.c $(am__append_2) ++gfor_io_src = io/size_from_kind.c $(am__append_3) + gfor_io_headers = \ + io/io.h \ + io/fbuf.h \ +@@ -802,7 +806,7 @@ gfor_helper_src = intrinsics/associated.c intrinsics/abort.c \ + intrinsics/selected_int_kind.f90 \ + intrinsics/selected_real_kind.f90 intrinsics/trigd.c \ + intrinsics/unpack_generic.c runtime/in_pack_generic.c \ +- runtime/in_unpack_generic.c $(am__append_3) $(am__append_4) ++ runtime/in_unpack_generic.c $(am__append_4) $(am__append_5) + @IEEE_SUPPORT_TRUE@gfor_ieee_helper_src = ieee/ieee_helper.c + @IEEE_SUPPORT_FALSE@gfor_ieee_src = + @IEEE_SUPPORT_TRUE@gfor_ieee_src = \ +@@ -811,8 +815,8 @@ gfor_helper_src = intrinsics/associated.c intrinsics/abort.c \ + @IEEE_SUPPORT_TRUE@ieee/ieee_features.F90 + + gfor_src = runtime/bounds.c runtime/compile_options.c runtime/memory.c \ +- runtime/string.c runtime/select.c $(am__append_5) \ +- $(am__append_6) ++ runtime/string.c runtime/select.c $(am__append_6) \ ++ $(am__append_7) + i_all_c = \ + $(srcdir)/generated/all_l1.c \ + $(srcdir)/generated/all_l2.c \ +@@ -1652,7 +1656,7 @@ intrinsics/random_init.f90 + + BUILT_SOURCES = $(gfor_built_src) $(gfor_built_specific_src) \ + $(gfor_built_specific2_src) $(gfor_misc_specifics) \ +- $(am__append_7) ++ $(am__append_8) + prereq_SRC = $(gfor_src) $(gfor_built_src) $(gfor_io_src) \ + $(gfor_helper_src) $(gfor_ieee_src) $(gfor_io_headers) $(gfor_specific_src) + +diff --git a/libgfortran/configure b/libgfortran/configure +index ae64dca3114..f288af81ff5 100755 +--- a/libgfortran/configure ++++ b/libgfortran/configure +@@ -655,6 +655,8 @@ extra_ldflags_libgfortran + ac_ct_FC + FCFLAGS + FC ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_static + enable_shared + lt_host_flags +@@ -824,6 +826,7 @@ enable_static + with_pic + enable_fast_install + enable_libtool_lock ++enable_darwin_at_rpath + enable_largefile + enable_libquadmath_support + with_gcc_major_version_only +@@ -1479,6 +1482,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --disable-largefile omit support for large files + --disable-libquadmath-support + disable libquadmath support for Fortran +@@ -10939,6 +10944,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -10956,10 +11002,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -12766,7 +12821,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12769 "configure" ++#line 12824 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12872,7 +12927,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12875 "configure" ++#line 12930 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -13274,6 +13329,14 @@ esac + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + #AC_MSG_NOTICE([====== Finished libtool configuration]) ; sleep 10 + + # We need gfortran to compile parts of the library +@@ -14917,6 +14980,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_FC=no + hardcode_direct_FC=no + hardcode_automatic_FC=yes +@@ -14934,10 +15038,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_FC="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_FC="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_FC="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_FC="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_FC="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_FC="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_FC="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_FC="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_FC="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_FC="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_FC="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_FC="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs_FC=no +@@ -16190,9 +16303,10 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + # extra LD Flags which are required for targets ++extra_ldflags_libgfortran= + case "${host}" in +- *-darwin*) +- # Darwin needs -single_module when linking libgfortran ++ *-*-darwin[4567]*) ++ # Earlier Darwin needs -single_module when linking libgfortran + extra_ldflags_libgfortran=-Wl,-single_module + ;; + esac +@@ -28519,6 +28633,10 @@ if test -z "${HAVE_HWCAP_TRUE}" && test -z "${HAVE_HWCAP_FALSE}"; then + as_fn_error $? "conditional \"HAVE_HWCAP\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${LIBGFOR_BUILD_QUAD_TRUE}" && test -z "${LIBGFOR_BUILD_QUAD_FALSE}"; then + as_fn_error $? "conditional \"LIBGFOR_BUILD_QUAD\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac +index 97cc490cb5e..a21f56648a2 100644 +--- a/libgfortran/configure.ac ++++ b/libgfortran/configure.ac +@@ -282,6 +282,7 @@ LT_LIB_M + ACX_LT_HOST_FLAGS + AC_SUBST(enable_shared) + AC_SUBST(enable_static) ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + #AC_MSG_NOTICE([====== Finished libtool configuration]) ; sleep 10 + + # We need gfortran to compile parts of the library +@@ -290,9 +291,10 @@ FC="$GFORTRAN" + AC_PROG_FC(gfortran) + + # extra LD Flags which are required for targets ++extra_ldflags_libgfortran= + case "${host}" in +- *-darwin*) +- # Darwin needs -single_module when linking libgfortran ++ *-*-darwin[[4567]]*) ++ # Earlier Darwin needs -single_module when linking libgfortran + extra_ldflags_libgfortran=-Wl,-single_module + ;; + esac +diff --git a/libgo/configure b/libgo/configure +index ffe17c9be55..de5c1ac9b3d 100755 +--- a/libgo/configure ++++ b/libgo/configure +@@ -708,6 +708,8 @@ glibgo_toolexecdir + WERROR + WARN_FLAGS + CC_FOR_BUILD ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_static + enable_shared + CPP +@@ -11544,7 +11546,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11547 "configure" ++#line 11549 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11650,7 +11652,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11653 "configure" ++#line 11655 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -13779,6 +13781,14 @@ CC="$lt_save_CC" + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + CC_FOR_BUILD=${CC_FOR_BUILD:-gcc} + +@@ -16321,6 +16331,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${USE_LIBFFI_TRUE}" && test -z "${USE_LIBFFI_FALSE}"; then + as_fn_error $? "conditional \"USE_LIBFFI\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libgo/configure.ac b/libgo/configure.ac +index 7e2b98ba67c..7b0222bb620 100644 +--- a/libgo/configure.ac ++++ b/libgo/configure.ac +@@ -53,6 +53,7 @@ AC_LIBTOOL_DLOPEN + AM_PROG_LIBTOOL + AC_SUBST(enable_shared) + AC_SUBST(enable_static) ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + + CC_FOR_BUILD=${CC_FOR_BUILD:-gcc} + AC_SUBST(CC_FOR_BUILD) +diff --git a/libgomp/Makefile.am b/libgomp/Makefile.am +index f8b2a06d63e..81ba6c634fa 100644 +--- a/libgomp/Makefile.am ++++ b/libgomp/Makefile.am +@@ -53,9 +53,14 @@ else + libgomp_version_script = + libgomp_version_dep = + endif ++ + libgomp_version_info = -version-info $(libtool_VERSION) ++if ENABLE_DARWIN_AT_RPATH ++libgomp_darwin_rpath = -Wc,-nodefaultrpaths ++libgomp_darwin_rpath += -Wl,-rpath,@loader_path ++endif + libgomp_la_LDFLAGS = $(libgomp_version_info) $(libgomp_version_script) \ +- $(lt_host_flags) ++ $(lt_host_flags) $(libgomp_darwin_rpath) + libgomp_la_DEPENDENCIES = $(libgomp_version_dep) + libgomp_la_LINK = $(LINK) $(libgomp_la_LDFLAGS) + +diff --git a/libgomp/Makefile.in b/libgomp/Makefile.in +index 6f0cb716135..5cfb149c2ba 100644 +--- a/libgomp/Makefile.in ++++ b/libgomp/Makefile.in +@@ -546,8 +546,11 @@ nodist_toolexeclib_HEADERS = libgomp.spec + @LIBGOMP_BUILD_VERSIONED_SHLIB_GNU_TRUE@@LIBGOMP_BUILD_VERSIONED_SHLIB_TRUE@libgomp_version_dep = libgomp.ver + @LIBGOMP_BUILD_VERSIONED_SHLIB_SUN_TRUE@@LIBGOMP_BUILD_VERSIONED_SHLIB_TRUE@libgomp_version_dep = libgomp.ver-sun + libgomp_version_info = -version-info $(libtool_VERSION) ++@ENABLE_DARWIN_AT_RPATH_TRUE@libgomp_darwin_rpath = \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path + libgomp_la_LDFLAGS = $(libgomp_version_info) $(libgomp_version_script) \ +- $(lt_host_flags) ++ $(lt_host_flags) $(libgomp_darwin_rpath) + + libgomp_la_DEPENDENCIES = $(libgomp_version_dep) + libgomp_la_LINK = $(LINK) $(libgomp_la_LDFLAGS) +diff --git a/libgomp/configure b/libgomp/configure +index 85fdb4d3f48..71b5987dc9a 100755 +--- a/libgomp/configure ++++ b/libgomp/configure +@@ -692,6 +692,8 @@ FC + MAINT + MAINTAINER_MODE_FALSE + MAINTAINER_MODE_TRUE ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_static + enable_shared + lt_host_flags +@@ -832,6 +834,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_maintainer_mode + with_cuda_driver + with_cuda_driver_include +@@ -1493,6 +1496,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer +@@ -9625,6 +9630,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -9642,10 +9688,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -11431,7 +11486,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11434 "configure" ++#line 11489 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11537,7 +11592,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11540 "configure" ++#line 11595 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11798,6 +11853,14 @@ esac + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +@@ -13473,6 +13536,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_FC=no + hardcode_direct_FC=no + hardcode_automatic_FC=yes +@@ -13490,10 +13594,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_FC="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_FC="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_FC="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_FC="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_FC="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_FC="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_FC="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_FC="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_FC="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_FC="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_FC="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_FC="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs_FC=no +@@ -17213,6 +17326,10 @@ if test -z "${BUILD_INFO_TRUE}" && test -z "${BUILD_INFO_FALSE}"; then + as_fn_error $? "conditional \"BUILD_INFO\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libgomp/configure.ac b/libgomp/configure.ac +index a9b1f3973f7..654fca1f445 100644 +--- a/libgomp/configure.ac ++++ b/libgomp/configure.ac +@@ -149,6 +149,7 @@ AM_PROG_LIBTOOL + ACX_LT_HOST_FLAGS + AC_SUBST(enable_shared) + AC_SUBST(enable_static) ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + + AM_MAINTAINER_MODE + +diff --git a/libiberty/aclocal.m4 b/libiberty/aclocal.m4 +index 3378316dced..1a00b771fe1 100644 +--- a/libiberty/aclocal.m4 ++++ b/libiberty/aclocal.m4 +@@ -12,10 +12,61 @@ + # PARTICULAR PURPOSE. + + m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) ++# AM_CONDITIONAL -*- Autoconf -*- ++ ++# Copyright (C) 1997-2017 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# AM_CONDITIONAL(NAME, SHELL-CONDITION) ++# ------------------------------------- ++# Define a conditional. ++AC_DEFUN([AM_CONDITIONAL], ++[AC_PREREQ([2.52])dnl ++ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], ++ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl ++AC_SUBST([$1_TRUE])dnl ++AC_SUBST([$1_FALSE])dnl ++_AM_SUBST_NOTMAKE([$1_TRUE])dnl ++_AM_SUBST_NOTMAKE([$1_FALSE])dnl ++m4_define([_AM_COND_VALUE_$1], [$2])dnl ++if $2; then ++ $1_TRUE= ++ $1_FALSE='#' ++else ++ $1_TRUE='#' ++ $1_FALSE= ++fi ++AC_CONFIG_COMMANDS_PRE( ++[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then ++ AC_MSG_ERROR([[conditional "$1" was never defined. ++Usually this means the macro was only invoked conditionally.]]) ++fi])]) ++ ++# Copyright (C) 2006-2017 Free Software Foundation, Inc. ++# ++# This file is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# _AM_SUBST_NOTMAKE(VARIABLE) ++# --------------------------- ++# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. ++# This macro is traced by Automake. ++AC_DEFUN([_AM_SUBST_NOTMAKE]) ++ ++# AM_SUBST_NOTMAKE(VARIABLE) ++# -------------------------- ++# Public sister of _AM_SUBST_NOTMAKE. ++AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) ++ + m4_include([../config/acx.m4]) + m4_include([../config/cet.m4]) + m4_include([../config/enable.m4]) + m4_include([../config/no-executables.m4]) ++m4_include([../config/override.m4]) + m4_include([../config/picflag.m4]) + m4_include([../config/warnings.m4]) + m4_include([acinclude.m4]) +diff --git a/libiberty/configure b/libiberty/configure +index 0a797255c70..a346be40cc2 100755 +--- a/libiberty/configure ++++ b/libiberty/configure +@@ -632,6 +632,8 @@ PICFLAG + INSTALL_DATA + INSTALL_SCRIPT + INSTALL_PROGRAM ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + OUTPUT_OPTION + NO_MINUS_C_MINUS_O + ac_libiberty_warn_cflags +@@ -2459,6 +2461,9 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + ++ ++ ++ + # This works around the fact that libtool configuration may change LD + # for this particular configuration, but some shells, instead of + # keeping the changes in LD private, export them just because LD is +@@ -5046,6 +5051,15 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ ++ + ac_config_headers="$ac_config_headers config.h:config.in" + + +@@ -5208,6 +5222,9 @@ case "${host}" in + # sets the default TLS model and affects inlining. + PICFLAG=-fPIC + ;; ++ loongarch*-*-*) ++ PICFLAG=-fpic ++ ;; + mips-sgi-irix6*) + # PIC is the default. + ;; +@@ -7837,6 +7854,10 @@ LTLIBOBJS=$ac_ltlibobjs + + + ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + + : "${CONFIG_STATUS=./config.status}" + ac_write_fail=0 +diff --git a/libiberty/configure.ac b/libiberty/configure.ac +index 84a7b378fad..4dad84ea77a 100644 +--- a/libiberty/configure.ac ++++ b/libiberty/configure.ac +@@ -190,6 +190,8 @@ dnl AM_DISABLE_SHARED + dnl When we start using libtool: + dnl AM_PROG_LIBTOOL + ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) ++ + dnl When we start using automake: + dnl AM_CONFIG_HEADER(config.h:config.in) + AC_CONFIG_HEADER(config.h:config.in) +diff --git a/libitm/Makefile.am b/libitm/Makefile.am +index 3f31ad30556..a25317b07fe 100644 +--- a/libitm/Makefile.am ++++ b/libitm/Makefile.am +@@ -54,7 +54,12 @@ libitm_version_info = -version-info $(libtool_VERSION) + # want or need libstdc++. + libitm_la_DEPENDENCIES = $(libitm_version_dep) + libitm_la_LINK = $(LINK) $(libitm_la_LDFLAGS) +-libitm_la_LDFLAGS = $(libitm_version_info) $(libitm_version_script) ++if ENABLE_DARWIN_AT_RPATH ++libitm_darwin_rpath = -Wc,-nodefaultrpaths ++libitm_darwin_rpath += -Wl,-rpath,@loader_path ++endif ++libitm_la_LDFLAGS = $(libitm_version_info) $(libitm_version_script) \ ++ $(libitm_darwin_rpath) + + libitm_la_SOURCES = \ + aatree.cc alloc.cc alloc_c.cc alloc_cpp.cc barrier.cc beginend.cc \ +diff --git a/libitm/Makefile.in b/libitm/Makefile.in +index 7f53ea9b9db..ed28db45057 100644 +--- a/libitm/Makefile.in ++++ b/libitm/Makefile.in +@@ -481,7 +481,12 @@ libitm_version_info = -version-info $(libtool_VERSION) + # want or need libstdc++. + libitm_la_DEPENDENCIES = $(libitm_version_dep) + libitm_la_LINK = $(LINK) $(libitm_la_LDFLAGS) +-libitm_la_LDFLAGS = $(libitm_version_info) $(libitm_version_script) ++@ENABLE_DARWIN_AT_RPATH_TRUE@libitm_darwin_rpath = \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path ++libitm_la_LDFLAGS = $(libitm_version_info) $(libitm_version_script) \ ++ $(libitm_darwin_rpath) ++ + libitm_la_SOURCES = aatree.cc alloc.cc alloc_c.cc alloc_cpp.cc \ + barrier.cc beginend.cc clone.cc eh_cpp.cc local.cc query.cc \ + retry.cc rwlock.cc useraction.cc util.cc sjlj.S tls.cc \ +diff --git a/libitm/config/aarch64/sjlj.S b/libitm/config/aarch64/sjlj.S +index 296cb683a9f..941e886143e 100644 +--- a/libitm/config/aarch64/sjlj.S ++++ b/libitm/config/aarch64/sjlj.S +@@ -57,10 +57,19 @@ + + .text + .align 2 ++#if __ELF__ + .global _ITM_beginTransaction + .type _ITM_beginTransaction, %function + + _ITM_beginTransaction: ++ ++#elif __MACH__ ++ .global __ITM_beginTransaction ++ ++__ITM_beginTransaction: ++ ++#endif ++ + cfi_startproc + CFI_PAC_KEY + PAC_AND_BTI +@@ -84,8 +93,13 @@ _ITM_beginTransaction: + + /* Invoke GTM_begin_transaction with the struct we just built. */ + mov x1, sp ++#if __ELF__ + bl GTM_begin_transaction +- ++#elif __MACH__ ++ bl _GTM_begin_transaction ++#else ++#error "unexpected object format" ++#endif + /* Return; we don't need to restore any of the call-saved regs. */ + ldp x29, x30, [sp], 11*16 + cfi_adjust_cfa_offset(-11*16) +@@ -95,14 +109,23 @@ _ITM_beginTransaction: + CFI_PAC_TOGGLE + ret + cfi_endproc ++#if __ELF__ + .size _ITM_beginTransaction, . - _ITM_beginTransaction ++#endif + + .align 2 ++#if __ELF__ + .global GTM_longjmp + .hidden GTM_longjmp + .type GTM_longjmp, %function + + GTM_longjmp: ++ ++#elif __MACH__ ++ .private_extern _GTM_longjmp ++ ++_GTM_longjmp: ++#endif + /* The first parameter becomes the return value (x0). + The third parameter is ignored for now. */ + cfi_startproc +@@ -126,7 +149,9 @@ GTM_longjmp: + CFI_PAC_TOGGLE + br x30 + cfi_endproc ++#if __ELF__ + .size GTM_longjmp, . - GTM_longjmp ++#endif + + /* GNU_PROPERTY_AARCH64_* macros from elf.h for use in asm code. */ + #define FEATURE_1_AND 0xc0000000 +diff --git a/libitm/configure b/libitm/configure +index 18fc2d3a10a..5beb48a6b99 100755 +--- a/libitm/configure ++++ b/libitm/configure +@@ -660,6 +660,8 @@ libtool_VERSION + MAINT + MAINTAINER_MODE_FALSE + MAINTAINER_MODE_TRUE ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_static + enable_shared + CXXCPP +@@ -810,6 +812,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_maintainer_mode + enable_linux_futex + enable_tls +@@ -1462,6 +1465,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer +@@ -10252,6 +10257,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -10269,10 +10315,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -12058,7 +12113,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12061 "configure" ++#line 12116 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12164,7 +12219,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12167 "configure" ++#line 12222 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -13040,6 +13095,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes +@@ -13057,12 +13153,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + if test "$lt_cv_apple_cc_single_mod" != "yes"; then +- archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring${_lt_dsymutil}" ++ else ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ fi + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + +@@ -15414,6 +15523,14 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +@@ -18172,6 +18289,10 @@ if test -z "${BUILD_INFO_TRUE}" && test -z "${BUILD_INFO_FALSE}"; then + as_fn_error $? "conditional \"BUILD_INFO\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libitm/configure.ac b/libitm/configure.ac +index 78a682376d9..209a025a90e 100644 +--- a/libitm/configure.ac ++++ b/libitm/configure.ac +@@ -157,6 +157,7 @@ AM_CONDITIONAL(BUILD_INFO, test $gcc_cv_prog_makeinfo_modern = "yes") + AM_PROG_LIBTOOL + AC_SUBST(enable_shared) + AC_SUBST(enable_static) ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + + AM_MAINTAINER_MODE + +diff --git a/libitm/configure.tgt b/libitm/configure.tgt +index 06e90973ef3..acaf4f85712 100644 +--- a/libitm/configure.tgt ++++ b/libitm/configure.tgt +@@ -50,7 +50,7 @@ fi + # Map the target cpu to an ARCH sub-directory. At the same time, + # work out any special compilation flags as necessary. + case "${target_cpu}" in +- aarch64*) ARCH=aarch64 ;; ++ aarch64* | arm64*) ARCH=aarch64 ;; + alpha*) ARCH=alpha ;; + rs6000 | powerpc*) + XCFLAGS="${XCFLAGS} -mhtm" +diff --git a/libitm/testsuite/lib/libitm.exp b/libitm/testsuite/lib/libitm.exp +index 6d8e3e71310..906534022eb 100644 +--- a/libitm/testsuite/lib/libitm.exp ++++ b/libitm/testsuite/lib/libitm.exp +@@ -158,6 +158,7 @@ proc libitm_init { args } { + } + + if [istarget *-*-darwin*] { ++ lappend ALWAYS_CFLAGS "additional_flags=-B${blddir}/.libs" + lappend ALWAYS_CFLAGS "additional_flags=-shared-libgcc" + } + +diff --git a/libitm/testsuite/libitm.c++/c++.exp b/libitm/testsuite/libitm.c++/c++.exp +index f92aa096104..295c5bd4703 100644 +--- a/libitm/testsuite/libitm.c++/c++.exp ++++ b/libitm/testsuite/libitm.c++/c++.exp +@@ -56,8 +56,10 @@ if { $lang_test_file_found } { + # Gather a list of all tests. + set tests [lsort [glob -nocomplain $srcdir/$subdir/*.C]] + ++ set stdcxxadder "" + if { $blddir != "" } { + set ld_library_path "$always_ld_library_path:${blddir}/${lang_library_path}" ++ set stdcxxadder "-B ${blddir}/${lang_library_path}" + } else { + set ld_library_path "$always_ld_library_path" + } +@@ -72,7 +74,7 @@ if { $lang_test_file_found } { + } + + # Main loop. +- dg-runtest $tests "" $libstdcxx_includes ++ dg-runtest $tests $stdcxxadder $libstdcxx_includes + } + + # All done. +diff --git a/libobjc/configure b/libobjc/configure +index 5d1b424a66d..21ac18723c3 100755 +--- a/libobjc/configure ++++ b/libobjc/configure +@@ -636,6 +636,9 @@ OBJC_BOEHM_GC_LIBS + OBJC_BOEHM_GC_INCLUDES + OBJC_BOEHM_GC + OBJC_GCFLAGS ++extra_ldflags_libobjc ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + SET_MAKE + CPP + OTOOL64 +@@ -667,7 +670,6 @@ RANLIB + AR + AS + XCFLAGS +-extra_ldflags_libobjc + lt_host_flags + OBJEXT + EXEEXT +@@ -755,6 +757,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_tls + enable_objc_gc + with_target_bdw_gc +@@ -1392,6 +1395,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-tls Use thread-local storage [default=yes] + --enable-objc-gc enable use of Boehm's garbage collector with the GNU + Objective-C runtime +@@ -3430,17 +3435,6 @@ esac + + + +-case "${host}" in +- *-darwin*) +- # Darwin needs -single_module when linking libobjc +- extra_ldflags_libobjc='$(lt_host_flags) -Wl,-single_module' +- ;; +- *-cygwin*|*-mingw*) +- # Tell libtool to build DLLs on Windows +- extra_ldflags_libobjc='$(lt_host_flags)' +- ;; +-esac +- + + # Add CET specific flags if CET is enabled + +@@ -3466,7 +3460,7 @@ case "$host" in + case "$enable_cet" in + auto) + # Check if target supports multi-byte NOPs +- # and if assembler supports CET insn. ++ # and if compiler and assembler support CET insn. + cet_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fcf-protection" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -8944,6 +8938,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -8961,10 +8996,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -10771,7 +10815,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 10784 "configure" ++#line 10818 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -10877,7 +10921,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 10890 "configure" ++#line 10924 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11149,6 +11193,38 @@ $as_echo "no" >&6; } + fi + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ ++ ++# Must come after libtool is initialized. ++case "${host}" in ++ *-darwin[4567]*) ++ # Earlier Darwin versions need -single_module when linking libobjc; they ++ # do not support @rpath. ++ extra_ldflags_libobjc='$(lt_host_flags) -Wl,-single_module' ++ ;; ++ *-darwin*) ++ # Otherwise, single_module is the default and multi-module is ignored and ++ # obsolete. ++ extra_ldflags_libobjc='$(lt_host_flags)' ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ extra_ldflags_libobjc="${extra_ldflags_libobjc} -Wc,-nodefaultrpaths" ++ extra_ldflags_libobjc="${extra_ldflags_libobjc} -Wl,-rpath,@loader_path" ++ fi ++ ;; ++ *-cygwin*|*-mingw*) ++ # Tell libtool to build DLLs on Windows ++ extra_ldflags_libobjc='$(lt_host_flags)' ++ ;; ++esac ++ ++ + # ------- + # Headers + # ------- +@@ -11890,6 +11966,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + + : "${CONFIG_STATUS=./config.status}" + ac_write_fail=0 +diff --git a/libobjc/configure.ac b/libobjc/configure.ac +index f8f577cfbef..2a9bf1fed4c 100644 +--- a/libobjc/configure.ac ++++ b/libobjc/configure.ac +@@ -147,17 +147,6 @@ m4_rename_force([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) + + # extra LD Flags which are required for targets + ACX_LT_HOST_FLAGS +-case "${host}" in +- *-darwin*) +- # Darwin needs -single_module when linking libobjc +- extra_ldflags_libobjc='$(lt_host_flags) -Wl,-single_module' +- ;; +- *-cygwin*|*-mingw*) +- # Tell libtool to build DLLs on Windows +- extra_ldflags_libobjc='$(lt_host_flags)' +- ;; +-esac +-AC_SUBST(extra_ldflags_libobjc) + + # Add CET specific flags if CET is enabled + GCC_CET_FLAGS(CET_FLAGS) +@@ -182,6 +171,31 @@ AM_PROG_CC_C_O + + AC_PROG_MAKE_SET + ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) ++ ++# Must come after libtool is initialized. ++case "${host}" in ++ *-darwin[[4567]]*) ++ # Earlier Darwin versions need -single_module when linking libobjc; they ++ # do not support @rpath. ++ extra_ldflags_libobjc='$(lt_host_flags) -Wl,-single_module' ++ ;; ++ *-darwin*) ++ # Otherwise, single_module is the default and multi-module is ignored and ++ # obsolete. ++ extra_ldflags_libobjc='$(lt_host_flags)' ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ extra_ldflags_libobjc="${extra_ldflags_libobjc} -Wc,-nodefaultrpaths" ++ extra_ldflags_libobjc="${extra_ldflags_libobjc} -Wl,-rpath,@loader_path" ++ fi ++ ;; ++ *-cygwin*|*-mingw*) ++ # Tell libtool to build DLLs on Windows ++ extra_ldflags_libobjc='$(lt_host_flags)' ++ ;; ++esac ++AC_SUBST(extra_ldflags_libobjc) ++ + # ------- + # Headers + # ------- +diff --git a/liboffloadmic/configure b/liboffloadmic/configure +index dfa8287fd75..84447cbb7eb 100755 +--- a/liboffloadmic/configure ++++ b/liboffloadmic/configure +@@ -639,6 +639,8 @@ link_offloadmic_host + lt_cv_dlopen_libs + toolexeclibdir + toolexecdir ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + CXXCPP + OTOOL64 + OTOOL +@@ -782,6 +784,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + with_gcc_major_version_only + ' + ac_precious_vars='build_alias +@@ -1434,6 +1437,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + + Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] +@@ -7900,23 +7905,25 @@ _LT_EOF + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 + $as_echo "$lt_cv_ld_force_load" >&6; } +- case $host_os in +- rhapsody* | darwin1.[012]) ++ # Allow for Darwin 4-7 (macOS 10.0-10.3) although these are not expect to ++ # build without first building modern cctools / linker. ++ case $host_cpu-$host_os in ++ *-rhapsody* | *-darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; +- darwin1.*) ++ *-darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; +- darwin*) # darwin 5.x on +- # if running on 10.5 or later, the deployment target defaults +- # to the OS version, if on x86, and 10.4, the deployment +- # target defaults to 10.4. Don't you love it? +- case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in +- 10.0,*86*-darwin8*|10.0,*-darwin[91]*) +- _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; ++ *-darwin*) ++ # darwin 5.x (macOS 10.1) onwards we only need to adjust when the ++ # deployment target is forced to an earlier version. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host in ++ UNSET,*-darwin[89]*|UNSET,*-darwin[12][0123456789]*) ++ ;; + 10.[012][,.]*) +- _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; +- 10.*) +- _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; +- esac ++ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ++ ;; ++ *) ++ ;; ++ esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then +@@ -9614,6 +9621,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -9631,10 +9679,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -11420,7 +11477,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11433 "configure" ++#line 11480 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11526,7 +11583,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11539 "configure" ++#line 11586 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12402,6 +12459,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes +@@ -12419,12 +12517,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + if test "$lt_cv_apple_cc_single_mod" != "yes"; then +- archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring${_lt_dsymutil}" ++ else ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ fi + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + +@@ -14265,16 +14376,6 @@ freebsd* | dragonfly*) + esac + ;; + +-gnu*) +- version_type=linux +- need_lib_prefix=no +- need_version=no +- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' +- soname_spec='${libname}${release}${shared_ext}$major' +- shlibpath_var=LD_LIBRARY_PATH +- hardcode_into_libs=yes +- ;; +- + haiku*) + version_type=linux + need_lib_prefix=no +@@ -14396,7 +14497,7 @@ linux*oldld* | linux*aout* | linux*coff*) + # project, but have not yet been accepted: they are GCC-local changes + # for the time being. (See + # https://lists.gnu.org/archive/html/libtool-patches/2018-05/msg00000.html) +-linux* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) ++linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu* | uclinuxfdpiceabi) + version_type=linux + need_lib_prefix=no + need_version=no +@@ -14784,6 +14885,15 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + # Only expand once: + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ ++ + # Forbid libtool to hardcode RPATH, because we want to be able to specify + # library search directory using LD_LIBRARY_PATH + hardcode_into_libs=no +@@ -14999,6 +15109,10 @@ if test -z "${LIBOFFLOADMIC_HOST_TRUE}" && test -z "${LIBOFFLOADMIC_HOST_FALSE}" + as_fn_error $? "conditional \"LIBOFFLOADMIC_HOST\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + + : "${CONFIG_STATUS=./config.status}" + ac_write_fail=0 +diff --git a/liboffloadmic/configure.ac b/liboffloadmic/configure.ac +index f64f182e8ef..b96e7eaf9e3 100644 +--- a/liboffloadmic/configure.ac ++++ b/liboffloadmic/configure.ac +@@ -118,6 +118,8 @@ esac + + AC_LIBTOOL_DLOPEN + AM_PROG_LIBTOOL ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) ++ + # Forbid libtool to hardcode RPATH, because we want to be able to specify + # library search directory using LD_LIBRARY_PATH + hardcode_into_libs=no +diff --git a/liboffloadmic/plugin/Makefile.in b/liboffloadmic/plugin/Makefile.in +index 8d5ad0025c2..c53f2d32b3b 100644 +--- a/liboffloadmic/plugin/Makefile.in ++++ b/liboffloadmic/plugin/Makefile.in +@@ -123,10 +123,10 @@ subdir = . + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 + am__aclocal_m4_deps = $(top_srcdir)/../../config/acx.m4 \ + $(top_srcdir)/../../config/depstand.m4 \ +- $(top_srcdir)/../../config/toolexeclibdir.m4 \ + $(top_srcdir)/../../config/lead-dot.m4 \ + $(top_srcdir)/../../config/multi.m4 \ + $(top_srcdir)/../../config/override.m4 \ ++ $(top_srcdir)/../../config/toolexeclibdir.m4 \ + $(top_srcdir)/../../libtool.m4 \ + $(top_srcdir)/../../ltoptions.m4 \ + $(top_srcdir)/../../ltsugar.m4 \ +diff --git a/liboffloadmic/plugin/aclocal.m4 b/liboffloadmic/plugin/aclocal.m4 +index 9fa1d1216c1..1bb91402f66 100644 +--- a/liboffloadmic/plugin/aclocal.m4 ++++ b/liboffloadmic/plugin/aclocal.m4 +@@ -1169,10 +1169,10 @@ AC_SUBST([am__untar]) + + m4_include([../../config/acx.m4]) + m4_include([../../config/depstand.m4]) +-m4_include([../../config/toolexeclibdir.m4]) + m4_include([../../config/lead-dot.m4]) + m4_include([../../config/multi.m4]) + m4_include([../../config/override.m4]) ++m4_include([../../config/toolexeclibdir.m4]) + m4_include([../../libtool.m4]) + m4_include([../../ltoptions.m4]) + m4_include([../../ltsugar.m4]) +diff --git a/liboffloadmic/plugin/configure b/liboffloadmic/plugin/configure +index 0b21d7d4eed..a9416401a65 100755 +--- a/liboffloadmic/plugin/configure ++++ b/liboffloadmic/plugin/configure +@@ -635,6 +635,8 @@ LIBOBJS + get_gcc_base_ver + toolexeclibdir + toolexecdir ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + CXXCPP + CPP + OTOOL64 +@@ -778,6 +780,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + with_gcc_major_version_only + ' + ac_precious_vars='build_alias +@@ -1431,6 +1434,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + + Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] +@@ -7280,23 +7285,25 @@ _LT_EOF + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 + $as_echo "$lt_cv_ld_force_load" >&6; } +- case $host_os in +- rhapsody* | darwin1.[012]) ++ # Allow for Darwin 4-7 (macOS 10.0-10.3) although these are not expect to ++ # build without first building modern cctools / linker. ++ case $host_cpu-$host_os in ++ *-rhapsody* | *-darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; +- darwin1.*) ++ *-darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; +- darwin*) # darwin 5.x on +- # if running on 10.5 or later, the deployment target defaults +- # to the OS version, if on x86, and 10.4, the deployment +- # target defaults to 10.4. Don't you love it? +- case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in +- 10.0,*86*-darwin8*|10.0,*-darwin[91]*) +- _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; ++ *-darwin*) ++ # darwin 5.x (macOS 10.1) onwards we only need to adjust when the ++ # deployment target is forced to an earlier version. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host in ++ UNSET,*-darwin[89]*|UNSET,*-darwin[12][0123456789]*) ++ ;; + 10.[012][,.]*) +- _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; +- 10.*) +- _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; +- esac ++ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ++ ;; ++ *) ++ ;; ++ esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then +@@ -9261,6 +9268,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -9278,10 +9326,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -11067,7 +11124,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11080 "configure" ++#line 11127 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11173,7 +11230,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11186 "configure" ++#line 11233 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12049,6 +12106,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes +@@ -12066,12 +12164,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + if test "$lt_cv_apple_cc_single_mod" != "yes"; then +- archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring${_lt_dsymutil}" ++ else ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ fi + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + +@@ -13912,16 +14023,6 @@ freebsd* | dragonfly*) + esac + ;; + +-gnu*) +- version_type=linux +- need_lib_prefix=no +- need_version=no +- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' +- soname_spec='${libname}${release}${shared_ext}$major' +- shlibpath_var=LD_LIBRARY_PATH +- hardcode_into_libs=yes +- ;; +- + haiku*) + version_type=linux + need_lib_prefix=no +@@ -14043,7 +14144,7 @@ linux*oldld* | linux*aout* | linux*coff*) + # project, but have not yet been accepted: they are GCC-local changes + # for the time being. (See + # https://lists.gnu.org/archive/html/libtool-patches/2018-05/msg00000.html) +-linux* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) ++linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu* | uclinuxfdpiceabi) + version_type=linux + need_lib_prefix=no + need_version=no +@@ -14431,6 +14532,15 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu + # Only expand once: + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ ++ + # Forbid libtool to hardcode RPATH, because we want to be able to specify + # library search directory using LD_LIBRARY_PATH + hardcode_into_libs=no +@@ -14634,6 +14744,10 @@ if test -z "${PLUGIN_HOST_TRUE}" && test -z "${PLUGIN_HOST_FALSE}"; then + as_fn_error $? "conditional \"PLUGIN_HOST\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + + : "${CONFIG_STATUS=./config.status}" + ac_write_fail=0 +diff --git a/liboffloadmic/plugin/configure.ac b/liboffloadmic/plugin/configure.ac +index cbcd0130d05..3329b03638d 100644 +--- a/liboffloadmic/plugin/configure.ac ++++ b/liboffloadmic/plugin/configure.ac +@@ -134,6 +134,8 @@ esac + + AC_LIBTOOL_DLOPEN + AM_PROG_LIBTOOL ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) ++ + # Forbid libtool to hardcode RPATH, because we want to be able to specify + # library search directory using LD_LIBRARY_PATH + hardcode_into_libs=no +diff --git a/libphobos/configure b/libphobos/configure +index 9da06f087d0..9fbb3c91e93 100755 +--- a/libphobos/configure ++++ b/libphobos/configure +@@ -707,6 +707,8 @@ get_gcc_base_ver + phobos_compiler_shared_flag + phobos_compiler_pic_flag + phobos_lt_pic_flag ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_static + enable_shared + OTOOL64 +@@ -838,6 +840,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + with_gcc_major_version_only + enable_werror + with_libatomic +@@ -1490,6 +1493,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-werror turns on -Werror [default=no] + --enable-version-specific-runtime-libs + Specify that runtime libraries should be installed +@@ -9944,6 +9949,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -9961,10 +10007,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -11750,7 +11805,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11753 "configure" ++#line 11808 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11856,7 +11911,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11859 "configure" ++#line 11914 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -13381,6 +13436,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_D=no + hardcode_direct_D=no + hardcode_automatic_D=yes +@@ -13398,10 +13494,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_D="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_D="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_D="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_D="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_D="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_D="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_D="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_D="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_D="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_D="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_D="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_D="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs_D=no +@@ -14002,6 +14107,14 @@ CFLAGS=$lt_save_CFLAGS + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + # libtool variables for Phobos shared and position-independent compiles. + # +@@ -15726,6 +15839,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${DRUNTIME_CPU_AARCH64_TRUE}" && test -z "${DRUNTIME_CPU_AARCH64_FALSE}"; then + as_fn_error $? "conditional \"DRUNTIME_CPU_AARCH64\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libphobos/configure.ac b/libphobos/configure.ac +index 31209ba2920..cc372587939 100644 +--- a/libphobos/configure.ac ++++ b/libphobos/configure.ac +@@ -93,6 +93,7 @@ AM_PROG_LIBTOOL + WITH_LOCAL_DRUNTIME([LT_LANG([D])], []) + AC_SUBST(enable_shared) + AC_SUBST(enable_static) ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + + # libtool variables for Phobos shared and position-independent compiles. + # +diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am +index 6ca4012b713..861ec0ebc03 100644 +--- a/libphobos/libdruntime/Makefile.am ++++ b/libphobos/libdruntime/Makefile.am +@@ -128,8 +128,11 @@ ALL_DRUNTIME_SOURCES = $(DRUNTIME_DSOURCES) $(DRUNTIME_CSOURCES) \ + toolexeclib_LTLIBRARIES = libgdruntime.la + libgdruntime_la_SOURCES = $(ALL_DRUNTIME_SOURCES) + libgdruntime_la_LIBTOOLFLAGS = ++if ENABLE_DARWIN_AT_RPATH ++libgdruntime_darwin_rpath = -Wl,-rpath,@loader_path ++endif + libgdruntime_la_LDFLAGS = -Wc,-nophoboslib,-dstartfiles,-B../src,-Bgcc \ +- -version-info $(libtool_VERSION) ++ -version-info $(libtool_VERSION) $(libgdruntime_darwin_rpath) + libgdruntime_la_LIBADD = $(LIBATOMIC) $(LIBBACKTRACE) + libgdruntime_la_DEPENDENCIES = $(DRTSTUFF) + # Also override library link commands: This is not strictly +diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in +index f7f78d71ff7..9f3361c7702 100644 +--- a/libphobos/libdruntime/Makefile.in ++++ b/libphobos/libdruntime/Makefile.in +@@ -805,8 +805,9 @@ ALL_DRUNTIME_SOURCES = $(DRUNTIME_DSOURCES) $(DRUNTIME_CSOURCES) \ + toolexeclib_LTLIBRARIES = libgdruntime.la + libgdruntime_la_SOURCES = $(ALL_DRUNTIME_SOURCES) + libgdruntime_la_LIBTOOLFLAGS = ++@ENABLE_DARWIN_AT_RPATH_TRUE@libgdruntime_darwin_rpath = -Wl,-rpath,@loader_path + libgdruntime_la_LDFLAGS = -Wc,-nophoboslib,-dstartfiles,-B../src,-Bgcc \ +- -version-info $(libtool_VERSION) ++ -version-info $(libtool_VERSION) $(libgdruntime_darwin_rpath) + + libgdruntime_la_LIBADD = $(LIBATOMIC) $(LIBBACKTRACE) + libgdruntime_la_DEPENDENCIES = $(DRTSTUFF) +diff --git a/libphobos/src/Makefile.am b/libphobos/src/Makefile.am +index da7a2004ff8..a47d985c5b7 100644 +--- a/libphobos/src/Makefile.am ++++ b/libphobos/src/Makefile.am +@@ -44,8 +44,11 @@ toolexeclib_DATA = libgphobos.spec + toolexeclib_LTLIBRARIES = libgphobos.la + libgphobos_la_SOURCES = $(ALL_PHOBOS_SOURCES) + libgphobos_la_LIBTOOLFLAGS = ++if ENABLE_DARWIN_AT_RPATH ++libgphobos_darwin_rpath = -Wl,-rpath,@loader_path ++endif + libgphobos_la_LDFLAGS = -Wc,-nophoboslib,-dstartfiles,-B../libdruntime/gcc \ +- -version-info $(libtool_VERSION) ++ -version-info $(libtool_VERSION) $(libgphobos_darwin_rpath) + if ENABLE_LIBDRUNTIME_ONLY + libgphobos_la_LIBADD = ../libdruntime/libgdruntime_convenience.la + else +diff --git a/libphobos/src/Makefile.in b/libphobos/src/Makefile.in +index 6f58fee01ac..212ea2469f2 100644 +--- a/libphobos/src/Makefile.in ++++ b/libphobos/src/Makefile.in +@@ -528,8 +528,9 @@ toolexeclib_DATA = libgphobos.spec + toolexeclib_LTLIBRARIES = libgphobos.la + libgphobos_la_SOURCES = $(ALL_PHOBOS_SOURCES) + libgphobos_la_LIBTOOLFLAGS = ++@ENABLE_DARWIN_AT_RPATH_TRUE@libgphobos_darwin_rpath = -Wl,-rpath,@loader_path + libgphobos_la_LDFLAGS = -Wc,-nophoboslib,-dstartfiles,-B../libdruntime/gcc \ +- -version-info $(libtool_VERSION) ++ -version-info $(libtool_VERSION) $(libgphobos_darwin_rpath) + + @ENABLE_LIBDRUNTIME_ONLY_FALSE@libgphobos_la_LIBADD = \ + @ENABLE_LIBDRUNTIME_ONLY_FALSE@ ../libdruntime/libgdruntime_convenience.la $(LIBZ) +diff --git a/libquadmath/Makefile.am b/libquadmath/Makefile.am +index 35dffb46f6e..4bf4bf6eebc 100644 +--- a/libquadmath/Makefile.am ++++ b/libquadmath/Makefile.am +@@ -36,8 +36,13 @@ endif + + toolexeclib_LTLIBRARIES = libquadmath.la + libquadmath_la_LIBADD = ++ ++if ENABLE_DARWIN_AT_RPATH ++libquadmath_darwin_rpath = -Wc,-nodefaultrpaths ++libquadmath_darwin_rpath += -Wl,-rpath,@loader_path ++endif + libquadmath_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ +- $(version_arg) $(lt_host_flags) -lm ++ $(version_arg) $(lt_host_flags) $(LIBM) $(libquadmath_darwin_rpath) + libquadmath_la_DEPENDENCIES = $(version_dep) $(libquadmath_la_LIBADD) + + nodist_libsubinclude_HEADERS = quadmath.h quadmath_weak.h +diff --git a/libquadmath/Makefile.in b/libquadmath/Makefile.in +index 8c011212258..b59aac7f1ac 100644 +--- a/libquadmath/Makefile.in ++++ b/libquadmath/Makefile.in +@@ -355,6 +355,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ + INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ + LD = @LD@ + LDFLAGS = @LDFLAGS@ ++LIBM = @LIBM@ + LIBOBJS = @LIBOBJS@ + LIBS = @LIBS@ + LIBTOOL = @LIBTOOL@ +@@ -463,8 +464,10 @@ AUTOMAKE_OPTIONS = foreign info-in-builddir + @BUILD_LIBQUADMATH_TRUE@@LIBQUAD_USE_SYMVER_SUN_TRUE@@LIBQUAD_USE_SYMVER_TRUE@version_dep = quadmath.map-sun + @BUILD_LIBQUADMATH_TRUE@toolexeclib_LTLIBRARIES = libquadmath.la + @BUILD_LIBQUADMATH_TRUE@libquadmath_la_LIBADD = ++@BUILD_LIBQUADMATH_TRUE@@ENABLE_DARWIN_AT_RPATH_TRUE@libquadmath_darwin_rpath = -Wc,-nodefaultrpaths \ ++@BUILD_LIBQUADMATH_TRUE@@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path + @BUILD_LIBQUADMATH_TRUE@libquadmath_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ +-@BUILD_LIBQUADMATH_TRUE@ $(version_arg) $(lt_host_flags) -lm ++@BUILD_LIBQUADMATH_TRUE@ $(version_arg) $(lt_host_flags) $(LIBM) $(libquadmath_darwin_rpath) + + @BUILD_LIBQUADMATH_TRUE@libquadmath_la_DEPENDENCIES = $(version_dep) $(libquadmath_la_LIBADD) + @BUILD_LIBQUADMATH_TRUE@nodist_libsubinclude_HEADERS = quadmath.h quadmath_weak.h +diff --git a/libquadmath/configure b/libquadmath/configure +index b3ee64f9c7d..23a99be108f 100755 +--- a/libquadmath/configure ++++ b/libquadmath/configure +@@ -644,11 +644,14 @@ LIBQUAD_USE_SYMVER_GNU_FALSE + LIBQUAD_USE_SYMVER_GNU_TRUE + LIBQUAD_USE_SYMVER_FALSE + LIBQUAD_USE_SYMVER_TRUE ++LIBM + toolexeclibdir + toolexecdir + MAINT + MAINTAINER_MODE_FALSE + MAINTAINER_MODE_TRUE ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_static + enable_shared + lt_host_flags +@@ -785,6 +788,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_maintainer_mode + with_toolexeclibdir + enable_symvers +@@ -1435,6 +1439,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-maintainer-mode + enable make rules and dependencies not useful (and + sometimes confusing) to the casual installer +@@ -8979,6 +8985,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -8996,10 +9043,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -10806,7 +10862,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 10819 "configure" ++#line 10865 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -10912,7 +10968,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 10925 "configure" ++#line 10971 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11173,6 +11229,14 @@ esac + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +@@ -12137,6 +12201,148 @@ esac + + + ++LIBM= ++case $host in ++*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) ++ # These system don't have libm, or don't need it ++ ;; ++*-ncr-sysv4.3*) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _mwvalidcheckl in -lmw" >&5 ++$as_echo_n "checking for _mwvalidcheckl in -lmw... " >&6; } ++if ${ac_cv_lib_mw__mwvalidcheckl+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lmw $LIBS" ++if test x$gcc_no_link = xyes; then ++ as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 ++fi ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char _mwvalidcheckl (); ++int ++main () ++{ ++return _mwvalidcheckl (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_mw__mwvalidcheckl=yes ++else ++ ac_cv_lib_mw__mwvalidcheckl=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mw__mwvalidcheckl" >&5 ++$as_echo "$ac_cv_lib_mw__mwvalidcheckl" >&6; } ++if test "x$ac_cv_lib_mw__mwvalidcheckl" = xyes; then : ++ LIBM="-lmw" ++fi ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5 ++$as_echo_n "checking for cos in -lm... " >&6; } ++if ${ac_cv_lib_m_cos+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lm $LIBS" ++if test x$gcc_no_link = xyes; then ++ as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 ++fi ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char cos (); ++int ++main () ++{ ++return cos (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_m_cos=yes ++else ++ ac_cv_lib_m_cos=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_cos" >&5 ++$as_echo "$ac_cv_lib_m_cos" >&6; } ++if test "x$ac_cv_lib_m_cos" = xyes; then : ++ LIBM="$LIBM -lm" ++fi ++ ++ ;; ++*) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cos in -lm" >&5 ++$as_echo_n "checking for cos in -lm... " >&6; } ++if ${ac_cv_lib_m_cos+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_check_lib_save_LIBS=$LIBS ++LIBS="-lm $LIBS" ++if test x$gcc_no_link = xyes; then ++ as_fn_error $? "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 ++fi ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char cos (); ++int ++main () ++{ ++return cos (); ++ ; ++ return 0; ++} ++_ACEOF ++if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_lib_m_cos=yes ++else ++ ac_cv_lib_m_cos=no ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext conftest.$ac_ext ++LIBS=$ac_check_lib_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_cos" >&5 ++$as_echo "$ac_cv_lib_m_cos" >&6; } ++if test "x$ac_cv_lib_m_cos" = xyes; then : ++ LIBM="-lm" ++fi ++ ++ ;; ++esac ++ ++ ++ + for ac_header in fenv.h langinfo.h locale.h wchar.h wctype.h limits.h ctype.h printf.h errno.h + do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +@@ -13031,7 +13237,7 @@ case "$host" in + case "$enable_cet" in + auto) + # Check if target supports multi-byte NOPs +- # and if assembler supports CET insn. ++ # and if compiler and assembler support CET insn. + cet_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fcf-protection" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -13397,6 +13603,10 @@ if test -z "${BUILD_INFO_TRUE}" && test -z "${BUILD_INFO_FALSE}"; then + as_fn_error $? "conditional \"BUILD_INFO\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libquadmath/configure.ac b/libquadmath/configure.ac +index eec4084a45f..94a3f2179e9 100644 +--- a/libquadmath/configure.ac ++++ b/libquadmath/configure.ac +@@ -59,6 +59,7 @@ AM_PROG_LIBTOOL + ACX_LT_HOST_FLAGS + AC_SUBST(enable_shared) + AC_SUBST(enable_static) ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + + AM_MAINTAINER_MODE + +@@ -121,6 +122,8 @@ esac + AC_SUBST(toolexecdir) + AC_SUBST(toolexeclibdir) + ++AC_CHECK_LIBM ++ + AC_CHECK_HEADERS(fenv.h langinfo.h locale.h wchar.h wctype.h limits.h ctype.h printf.h errno.h) + LIBQUAD_CHECK_MATH_H_SIGNGAM + +diff --git a/libsanitizer/Makefile.in b/libsanitizer/Makefile.in +index aab88deb6e8..65e7f2e9553 100644 +--- a/libsanitizer/Makefile.in ++++ b/libsanitizer/Makefile.in +@@ -345,7 +345,6 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ +-runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +diff --git a/libsanitizer/asan/Makefile.am b/libsanitizer/asan/Makefile.am +index 4f802f723d6..223d3e07816 100644 +--- a/libsanitizer/asan/Makefile.am ++++ b/libsanitizer/asan/Makefile.am +@@ -60,7 +60,12 @@ libasan_la_LIBADD += $(top_builddir)/libbacktrace/libsanitizer_libbacktrace.la + endif + libasan_la_LIBADD += $(LIBSTDCXX_RAW_CXX_LDFLAGS) + +-libasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libasan) ++if ENABLE_DARWIN_AT_RPATH ++libasan_darwin_rpath = -Wc,-nodefaultrpaths ++libasan_darwin_rpath += -Wl,-rpath,@loader_path ++endif ++libasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(link_libasan) $(libasan_darwin_rpath) + + libasan_preinit.o: asan_preinit.o + cp $< $@ +diff --git a/libsanitizer/asan/Makefile.in b/libsanitizer/asan/Makefile.in +index 2476fbc5a26..e88e5e0b0a7 100644 +--- a/libsanitizer/asan/Makefile.in ++++ b/libsanitizer/asan/Makefile.in +@@ -399,7 +399,6 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ +-runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +@@ -466,7 +465,12 @@ libasan_la_LIBADD = \ + $(top_builddir)/sanitizer_common/libsanitizer_common.la \ + $(top_builddir)/lsan/libsanitizer_lsan.la $(am__append_2) \ + $(am__append_3) $(LIBSTDCXX_RAW_CXX_LDFLAGS) +-libasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libasan) ++@ENABLE_DARWIN_AT_RPATH_TRUE@libasan_darwin_rpath = \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path ++libasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(link_libasan) $(libasan_darwin_rpath) ++ + + # Work around what appears to be a GNU make bug handling MAKEFLAGS + # values defined in terms of make variables, as is the case for CC and +diff --git a/libsanitizer/configure b/libsanitizer/configure +index 771b135573a..dfd99e34288 100755 +--- a/libsanitizer/configure ++++ b/libsanitizer/configure +@@ -666,6 +666,8 @@ LSAN_SUPPORTED_FALSE + LSAN_SUPPORTED_TRUE + TSAN_SUPPORTED_FALSE + TSAN_SUPPORTED_TRUE ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_static + enable_shared + CXXCPP +@@ -817,6 +819,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_werror + with_gcc_major_version_only + enable_cet +@@ -1471,6 +1474,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --disable-werror disable building with -Werror + --enable-cet enable Intel CET in target libraries [default=auto] + +@@ -10553,6 +10558,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -10570,10 +10616,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -12359,7 +12414,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12362 "configure" ++#line 12417 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12465,7 +12520,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12468 "configure" ++#line 12523 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -13341,6 +13396,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes +@@ -13358,12 +13454,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + if test "$lt_cv_apple_cc_single_mod" != "yes"; then +- archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring${_lt_dsymutil}" ++ else ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ fi + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + +@@ -15763,6 +15872,15 @@ esac + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ ++ + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +@@ -17152,6 +17270,10 @@ if test -z "${am__fastdepCCAS_TRUE}" && test -z "${am__fastdepCCAS_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCCAS\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${TSAN_SUPPORTED_TRUE}" && test -z "${TSAN_SUPPORTED_FALSE}"; then + as_fn_error $? "conditional \"TSAN_SUPPORTED\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libsanitizer/configure.ac b/libsanitizer/configure.ac +index 7f1ef3979c4..3549b904c62 100644 +--- a/libsanitizer/configure.ac ++++ b/libsanitizer/configure.ac +@@ -85,6 +85,8 @@ esac + AC_SUBST(enable_shared) + AC_SUBST(enable_static) + ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) ++ + AC_CHECK_SIZEOF([void *]) + + if test "${multilib}" = "yes"; then +diff --git a/libsanitizer/hwasan/Makefile.am b/libsanitizer/hwasan/Makefile.am +index e12c0a0ce71..4061078c734 100644 +--- a/libsanitizer/hwasan/Makefile.am ++++ b/libsanitizer/hwasan/Makefile.am +@@ -46,7 +46,11 @@ libhwasan_la_LIBADD += $(top_builddir)/libbacktrace/libsanitizer_libbacktrace.la + endif + libhwasan_la_LIBADD += $(LIBSTDCXX_RAW_CXX_LDFLAGS) + +-libhwasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libhwasan) ++if ENABLE_DARWIN_AT_RPATH ++libhwasan_darwin_rpath = -nodefaultrpaths -Wl,-rpath,@loader_path/ ++endif ++libhwasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(link_libhwasan) $(libhwasan_darwin_rpath) + + # Work around what appears to be a GNU make bug handling MAKEFLAGS + # values defined in terms of make variables, as is the case for CC and +diff --git a/libsanitizer/hwasan/Makefile.in b/libsanitizer/hwasan/Makefile.in +index 67553f3979d..d20f2dc6eef 100644 +--- a/libsanitizer/hwasan/Makefile.in ++++ b/libsanitizer/hwasan/Makefile.in +@@ -387,7 +387,6 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ +-runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +@@ -442,7 +441,10 @@ libhwasan_la_SOURCES = $(hwasan_files) + libhwasan_la_LIBADD = \ + $(top_builddir)/sanitizer_common/libsanitizer_common.la \ + $(am__append_1) $(am__append_2) $(LIBSTDCXX_RAW_CXX_LDFLAGS) +-libhwasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libhwasan) ++@ENABLE_DARWIN_AT_RPATH_TRUE@libhwasan_darwin_rpath = -nodefaultrpaths -Wl,-rpath,@loader_path/ ++libhwasan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(link_libhwasan) $(libhwasan_darwin_rpath) ++ + + # Work around what appears to be a GNU make bug handling MAKEFLAGS + # values defined in terms of make variables, as is the case for CC and +diff --git a/libsanitizer/interception/Makefile.in b/libsanitizer/interception/Makefile.in +index bce788aeea7..85dd386de47 100644 +--- a/libsanitizer/interception/Makefile.in ++++ b/libsanitizer/interception/Makefile.in +@@ -317,7 +317,6 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ +-runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +diff --git a/libsanitizer/libbacktrace/Makefile.in b/libsanitizer/libbacktrace/Makefile.in +index ece4f11a855..c0243fa4aab 100644 +--- a/libsanitizer/libbacktrace/Makefile.in ++++ b/libsanitizer/libbacktrace/Makefile.in +@@ -367,7 +367,6 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ +-runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +diff --git a/libsanitizer/lsan/Makefile.am b/libsanitizer/lsan/Makefile.am +index 6ff28ff5eea..7701b0e18cf 100644 +--- a/libsanitizer/lsan/Makefile.am ++++ b/libsanitizer/lsan/Makefile.am +@@ -41,8 +41,12 @@ if LIBBACKTRACE_SUPPORTED + liblsan_la_LIBADD += $(top_builddir)/libbacktrace/libsanitizer_libbacktrace.la + endif + liblsan_la_LIBADD += $(LIBSTDCXX_RAW_CXX_LDFLAGS) +-liblsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_liblsan) +- ++if ENABLE_DARWIN_AT_RPATH ++liblsan_darwin_rpath = -Wc,-nodefaultrpaths ++liblsan_darwin_rpath += -Wl,-rpath,@loader_path ++endif ++liblsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(link_liblsan) $(liblsan_darwin_rpath) + liblsan_preinit.o: lsan_preinit.o + cp $< $@ + +diff --git a/libsanitizer/lsan/Makefile.in b/libsanitizer/lsan/Makefile.in +index 857f244cd86..078edf01fda 100644 +--- a/libsanitizer/lsan/Makefile.in ++++ b/libsanitizer/lsan/Makefile.in +@@ -362,7 +362,6 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ +-runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +@@ -414,7 +413,12 @@ liblsan_la_LIBADD = \ + $(top_builddir)/sanitizer_common/libsanitizer_common.la \ + $(top_builddir)/interception/libinterception.la \ + $(am__append_1) $(LIBSTDCXX_RAW_CXX_LDFLAGS) +-liblsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_liblsan) ++@ENABLE_DARWIN_AT_RPATH_TRUE@liblsan_darwin_rpath = \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path ++liblsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(link_liblsan) $(liblsan_darwin_rpath) ++ + + # Work around what appears to be a GNU make bug handling MAKEFLAGS + # values defined in terms of make variables, as is the case for CC and +@@ -789,7 +793,6 @@ uninstall-am: uninstall-nodist_toolexeclibHEADERS \ + + .PRECIOUS: Makefile + +- + liblsan_preinit.o: lsan_preinit.o + cp $< $@ + +diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in +index c4b009fed83..e5e1c1d51fe 100644 +--- a/libsanitizer/sanitizer_common/Makefile.in ++++ b/libsanitizer/sanitizer_common/Makefile.in +@@ -354,7 +354,6 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ +-runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +diff --git a/libsanitizer/tsan/Makefile.am b/libsanitizer/tsan/Makefile.am +index ae588a67df6..47ee50bee1a 100644 +--- a/libsanitizer/tsan/Makefile.am ++++ b/libsanitizer/tsan/Makefile.am +@@ -58,7 +58,11 @@ libtsan_la_LIBADD += $(top_builddir)/libbacktrace/libsanitizer_libbacktrace.la + libtsan_la_DEPENDENCIES +=$(top_builddir)/libbacktrace/libsanitizer_libbacktrace.la + endif + libtsan_la_LIBADD += $(LIBSTDCXX_RAW_CXX_LDFLAGS) +-libtsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libtsan) ++if ENABLE_DARWIN_AT_RPATH ++libtsan_darwin_rpath = -nodefaultrpaths -Wl,-rpath,@loader_path/ ++endif ++libtsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(link_libtsan) $(libtsan_darwin_rpath) + + libtsan_preinit.o: tsan_preinit.o + cp $< $@ +diff --git a/libsanitizer/tsan/Makefile.in b/libsanitizer/tsan/Makefile.in +index 538d2e8eb68..d6efff71e2f 100644 +--- a/libsanitizer/tsan/Makefile.in ++++ b/libsanitizer/tsan/Makefile.in +@@ -391,7 +391,6 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ +-runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +@@ -466,7 +465,10 @@ libtsan_la_DEPENDENCIES = \ + $(top_builddir)/sanitizer_common/libsanitizer_common.la \ + $(top_builddir)/interception/libinterception.la \ + $(TSAN_TARGET_DEPENDENT_OBJECTS) $(am__append_2) +-libtsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libtsan) ++@ENABLE_DARWIN_AT_RPATH_TRUE@libtsan_darwin_rpath = -nodefaultrpaths -Wl,-rpath,@loader_path/ ++libtsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(link_libtsan) $(libtsan_darwin_rpath) ++ + + # Work around what appears to be a GNU make bug handling MAKEFLAGS + # values defined in terms of make variables, as is the case for CC and +diff --git a/libsanitizer/ubsan/Makefile.am b/libsanitizer/ubsan/Makefile.am +index d480f26adc0..7769b3437e4 100644 +--- a/libsanitizer/ubsan/Makefile.am ++++ b/libsanitizer/ubsan/Makefile.am +@@ -36,7 +36,12 @@ if LIBBACKTRACE_SUPPORTED + libubsan_la_LIBADD += $(top_builddir)/libbacktrace/libsanitizer_libbacktrace.la + endif + libubsan_la_LIBADD += $(LIBSTDCXX_RAW_CXX_LDFLAGS) +-libubsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libubsan) ++if ENABLE_DARWIN_AT_RPATH ++libubsan_darwin_rpath = -Wc,-nodefaultrpaths ++libubsan_darwin_rpath += -Wl,-rpath,@loader_path ++endif ++libubsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(link_libubsan) $(libubsan_darwin_rpath) + + # Use special rules for files that require RTTI support. + ubsan_handlers_cxx.% ubsan_type_hash.% ubsan_type_hash_itanium.% : AM_CXXFLAGS += -frtti +diff --git a/libsanitizer/ubsan/Makefile.in b/libsanitizer/ubsan/Makefile.in +index 497e0338696..7e51480e970 100644 +--- a/libsanitizer/ubsan/Makefile.in ++++ b/libsanitizer/ubsan/Makefile.in +@@ -356,7 +356,6 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ +-runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +@@ -401,7 +400,12 @@ libubsan_la_SOURCES = $(ubsan_files) + libubsan_la_LIBADD = \ + $(top_builddir)/sanitizer_common/libsanitizer_common.la \ + $(am__append_1) $(am__append_2) $(LIBSTDCXX_RAW_CXX_LDFLAGS) +-libubsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_libubsan) ++@ENABLE_DARWIN_AT_RPATH_TRUE@libubsan_darwin_rpath = \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path ++libubsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ ++ $(link_libubsan) $(libubsan_darwin_rpath) ++ + + # Work around what appears to be a GNU make bug handling MAKEFLAGS + # values defined in terms of make variables, as is the case for CC and +diff --git a/libssp/Makefile.am b/libssp/Makefile.am +index 945dc3c8336..d2a92b3aed1 100644 +--- a/libssp/Makefile.am ++++ b/libssp/Makefile.am +@@ -49,8 +49,12 @@ libssp_la_SOURCES = \ + vsnprintf-chk.c vsprintf-chk.c + libssp_la_LIBADD = + libssp_la_DEPENDENCIES = $(version_dep) $(libssp_la_LIBADD) ++if ENABLE_DARWIN_AT_RPATH ++libssp_darwin_rpath = -Wc,-nodefaultrpaths ++libssp_darwin_rpath += -Wl,-rpath,@loader_path ++endif + libssp_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ +- $(version_arg) $(lt_host_flags) ++ $(version_arg) $(lt_host_flags) $(libssp_darwin_rpath) + + libssp_nonshared_la_SOURCES = \ + ssp-local.c +diff --git a/libssp/Makefile.in b/libssp/Makefile.in +index bc8a0dc2b28..1cf86361b96 100644 +--- a/libssp/Makefile.in ++++ b/libssp/Makefile.in +@@ -376,8 +376,11 @@ libssp_la_SOURCES = \ + + libssp_la_LIBADD = + libssp_la_DEPENDENCIES = $(version_dep) $(libssp_la_LIBADD) ++@ENABLE_DARWIN_AT_RPATH_TRUE@libssp_darwin_rpath = \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path + libssp_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` \ +- $(version_arg) $(lt_host_flags) ++ $(version_arg) $(lt_host_flags) $(libssp_darwin_rpath) + + libssp_nonshared_la_SOURCES = \ + ssp-local.c +diff --git a/libssp/configure b/libssp/configure +index 10ba209bde8..5d62fef54a1 100755 +--- a/libssp/configure ++++ b/libssp/configure +@@ -636,6 +636,8 @@ LIBOBJS + get_gcc_base_ver + toolexeclibdir + toolexecdir ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_static + enable_shared + lt_host_flags +@@ -781,6 +783,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + with_toolexeclibdir + with_gcc_major_version_only + ' +@@ -1426,6 +1429,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + + Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] +@@ -4338,7 +4343,7 @@ case "$host" in + case "$enable_cet" in + auto) + # Check if target supports multi-byte NOPs +- # and if assembler supports CET insn. ++ # and if compiler and assembler support CET insn. + cet_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fcf-protection" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -9165,6 +9170,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -9182,10 +9228,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -10992,7 +11047,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11005 "configure" ++#line 11050 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11098,7 +11153,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 11111 "configure" ++#line 11156 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11376,6 +11431,15 @@ fi + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ ++ + # Calculate toolexeclibdir + # Also toolexecdir, though it's only used in toolexeclibdir + case ${version_specific_libs} in +@@ -11585,6 +11649,10 @@ if test -z "${LIBSSP_USE_SYMVER_SUN_TRUE}" && test -z "${LIBSSP_USE_SYMVER_SUN_F + as_fn_error $? "conditional \"LIBSSP_USE_SYMVER_SUN\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + + : "${CONFIG_STATUS=./config.status}" + ac_write_fail=0 +diff --git a/libssp/configure.ac b/libssp/configure.ac +index f30f81c54f6..90778e2355d 100644 +--- a/libssp/configure.ac ++++ b/libssp/configure.ac +@@ -165,6 +165,8 @@ AC_SUBST(enable_static) + + GCC_WITH_TOOLEXECLIBDIR + ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) ++ + # Calculate toolexeclibdir + # Also toolexecdir, though it's only used in toolexeclibdir + case ${version_specific_libs} in +diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure +index eac60392121..bdaa160dac6 100755 +--- a/libstdc++-v3/configure ++++ b/libstdc++-v3/configure +@@ -786,6 +786,8 @@ GLIBCXX_HOSTED_TRUE + glibcxx_compiler_shared_flag + glibcxx_compiler_pic_flag + glibcxx_lt_pic_flag ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_static + enable_shared + lt_host_flags +@@ -921,6 +923,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_hosted_libstdcxx + enable_libstdcxx_verbose + enable_libstdcxx_pch +@@ -1608,6 +1611,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --disable-hosted-libstdcxx + only build freestanding C++ runtime support + --disable-libstdcxx-verbose +@@ -10364,6 +10369,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -10381,10 +10427,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -12191,7 +12246,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12194 "configure" ++#line 12249 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12297,7 +12352,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12300 "configure" ++#line 12355 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -13179,6 +13234,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes +@@ -13196,12 +13292,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + if test "$lt_cv_apple_cc_single_mod" != "yes"; then +- archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring${_lt_dsymutil}" ++ else ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ fi + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + +@@ -15578,6 +15687,14 @@ esac + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + if test "$enable_vtable_verify" = yes; then + predep_objects_CXX="${predep_objects_CXX} ${glibcxx_builddir}/../libgcc/vtv_start.o" +@@ -15981,7 +16098,7 @@ $as_echo "$glibcxx_cv_atomic_long_long" >&6; } + # Fake what AC_TRY_COMPILE does. + + cat > conftest.$ac_ext << EOF +-#line 15984 "configure" ++#line 16101 "configure" + int main() + { + typedef bool atomic_type; +@@ -16016,7 +16133,7 @@ $as_echo "$glibcxx_cv_atomic_bool" >&6; } + rm -f conftest* + + cat > conftest.$ac_ext << EOF +-#line 16019 "configure" ++#line 16136 "configure" + int main() + { + typedef short atomic_type; +@@ -16051,7 +16168,7 @@ $as_echo "$glibcxx_cv_atomic_short" >&6; } + rm -f conftest* + + cat > conftest.$ac_ext << EOF +-#line 16054 "configure" ++#line 16171 "configure" + int main() + { + // NB: _Atomic_word not necessarily int. +@@ -16087,7 +16204,7 @@ $as_echo "$glibcxx_cv_atomic_int" >&6; } + rm -f conftest* + + cat > conftest.$ac_ext << EOF +-#line 16090 "configure" ++#line 16207 "configure" + int main() + { + typedef long long atomic_type; +@@ -16243,7 +16360,7 @@ $as_echo "mutex" >&6; } + # unnecessary for this test. + + cat > conftest.$ac_ext << EOF +-#line 16246 "configure" ++#line 16363 "configure" + int main() + { + _Decimal32 d1; +@@ -16285,7 +16402,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + # unnecessary for this test. + + cat > conftest.$ac_ext << EOF +-#line 16288 "configure" ++#line 16405 "configure" + template + struct same + { typedef T2 type; }; +@@ -79038,6 +79155,10 @@ if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${GLIBCXX_HOSTED_TRUE}" && test -z "${GLIBCXX_HOSTED_FALSE}"; then + as_fn_error $? "conditional \"GLIBCXX_HOSTED\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac +index e59bcdb2944..f3dda5a4ff9 100644 +--- a/libstdc++-v3/configure.ac ++++ b/libstdc++-v3/configure.ac +@@ -99,6 +99,7 @@ AM_PROG_LIBTOOL + ACX_LT_HOST_FLAGS + AC_SUBST(enable_shared) + AC_SUBST(enable_static) ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + + if test "$enable_vtable_verify" = yes; then + predep_objects_CXX="${predep_objects_CXX} ${glibcxx_builddir}/../libgcc/vtv_start.o" +diff --git a/libstdc++-v3/configure.host b/libstdc++-v3/configure.host +index ec32980aa0d..da5b1578d91 100644 +--- a/libstdc++-v3/configure.host ++++ b/libstdc++-v3/configure.host +@@ -234,11 +234,6 @@ case "${host_os}" in + darwin8 | darwin8.* ) + # For 8+ compatibility is better if not -flat_namespace. + OPT_LDFLAGS="${OPT_LDFLAGS} -Wl,-single_module" +- case "${host_cpu}" in +- i[34567]86 | x86_64) +- OPTIMIZE_CXXFLAGS="${OPTIMIZE_CXXFLAGS} -fvisibility-inlines-hidden" +- ;; +- esac + os_include_dir="os/bsd/darwin" + ;; + darwin*) +diff --git a/libstdc++-v3/src/Makefile.am b/libstdc++-v3/src/Makefile.am +index 9c3f4aca655..016d68ecd5f 100644 +--- a/libstdc++-v3/src/Makefile.am ++++ b/libstdc++-v3/src/Makefile.am +@@ -133,8 +133,13 @@ libstdc___la_DEPENDENCIES = \ + $(top_builddir)/src/c++17/libc++17convenience.la \ + $(top_builddir)/src/c++20/libc++20convenience.la + ++if ENABLE_DARWIN_AT_RPATH ++libstdc___darwin_rpath = -Wc,-nodefaultrpaths ++libstdc___darwin_rpath += -Wl,-rpath,@loader_path ++endif ++ + libstdc___la_LDFLAGS = \ +- -version-info $(libtool_VERSION) ${version_arg} -lm ++ -version-info $(libtool_VERSION) ${version_arg} -lm $(libstdc___darwin_rpath) + + libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS) $(lt_host_flags) + +diff --git a/libstdc++-v3/src/Makefile.in b/libstdc++-v3/src/Makefile.in +index 4a06f6cfec1..0dc6c9650fc 100644 +--- a/libstdc++-v3/src/Makefile.in ++++ b/libstdc++-v3/src/Makefile.in +@@ -546,8 +546,11 @@ libstdc___la_DEPENDENCIES = \ + $(top_builddir)/src/c++17/libc++17convenience.la \ + $(top_builddir)/src/c++20/libc++20convenience.la + ++@ENABLE_DARWIN_AT_RPATH_TRUE@libstdc___darwin_rpath = \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wc,-nodefaultrpaths \ ++@ENABLE_DARWIN_AT_RPATH_TRUE@ -Wl,-rpath,@loader_path + libstdc___la_LDFLAGS = \ +- -version-info $(libtool_VERSION) ${version_arg} -lm ++ -version-info $(libtool_VERSION) ${version_arg} -lm $(libstdc___darwin_rpath) + + libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS) $(lt_host_flags) + @GLIBCXX_LDBL_ALT128_COMPAT_FALSE@@GLIBCXX_LDBL_COMPAT_TRUE@LTCXXCOMPILE64 = $(LTCXXCOMPILE) +diff --git a/libtool.m4 b/libtool.m4 +index 17f8e5f3074..5452de03793 100644 +--- a/libtool.m4 ++++ b/libtool.m4 +@@ -1039,6 +1039,45 @@ _LT_EOF + m4_defun([_LT_DARWIN_LINKER_FEATURES], + [ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ AC_ARG_ENABLE([darwin-at-rpath], ++ AS_HELP_STRING([--enable-darwin-at-path], ++ [install libraries with @rpath/library-name, requires rpaths to be added to executables]), ++ [if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[[45678]]*|UNSET,rhapsody*|10.[[01234]][[,.]]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&AS_MESSAGE_LOG_FD ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi], ++ [case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[[45678]]*|UNSET,rhapsody*|10.[[01234]][[,.]]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[[56789]]*|UNSET,darwin2*|10.1[[123456789]][[,.]]*|1[[123456789]].*[[,.]]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&AS_MESSAGE_LOG_FD ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ]) ++ + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes +@@ -1056,13 +1095,26 @@ m4_defun([_LT_DARWIN_LINKER_FEATURES], + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&AS_MESSAGE_LOG_FD ++ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&AS_MESSAGE_LOG_FD ++ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + m4_if([$1], [CXX], + [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then +- _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring${_lt_dsymutil}" ++ else ++ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ fi + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + ],[]) +@@ -4203,6 +4255,7 @@ _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) + ])# _LT_COMPILER_PIC + ++_LT_TAGVAR(enable_darwin_at_rpath, $1)=no + + # _LT_LINKER_SHLIBS([TAGNAME]) + # ---------------------------- +@@ -6441,7 +6494,6 @@ fi # test "$_lt_caught_CXX_error" != yes + AC_LANG_POP + ])# _LT_LANG_CXX_CONFIG + +- + # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) + # --------------------------------- + # Figure out "hidden" library dependencies from verbose +diff --git a/libvtv/configure b/libvtv/configure +index d64b4af5c6b..4280e3b20a9 100755 +--- a/libvtv/configure ++++ b/libvtv/configure +@@ -640,6 +640,8 @@ VTV_CYGMIN_FALSE + VTV_CYGMIN_TRUE + XCFLAGS + libtool_VERSION ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + enable_static + enable_shared + lt_host_flags +@@ -797,6 +799,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + enable_cet + with_gcc_major_version_only + ' +@@ -1446,6 +1449,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-cet enable Intel CET in target libraries [default=auto] + + Optional Packages: +@@ -10448,6 +10453,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -10465,10 +10511,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -12254,7 +12309,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12267 "configure" ++#line 12312 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12360,7 +12415,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12373 "configure" ++#line 12418 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -13236,6 +13291,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes +@@ -13253,12 +13349,25 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + if test "$lt_cv_apple_cc_single_mod" != "yes"; then +- archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring${_lt_dsymutil}" ++ else ++ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" ++ fi + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + +@@ -15099,16 +15208,6 @@ freebsd* | dragonfly*) + esac + ;; + +-gnu*) +- version_type=linux +- need_lib_prefix=no +- need_version=no +- library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' +- soname_spec='${libname}${release}${shared_ext}$major' +- shlibpath_var=LD_LIBRARY_PATH +- hardcode_into_libs=yes +- ;; +- + haiku*) + version_type=linux + need_lib_prefix=no +@@ -15230,7 +15329,7 @@ linux*oldld* | linux*aout* | linux*coff*) + # project, but have not yet been accepted: they are GCC-local changes + # for the time being. (See + # https://lists.gnu.org/archive/html/libtool-patches/2018-05/msg00000.html) +-linux* | k*bsd*-gnu | kopensolaris*-gnu | uclinuxfdpiceabi) ++linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu* | uclinuxfdpiceabi) + version_type=linux + need_lib_prefix=no + need_version=no +@@ -15642,6 +15741,14 @@ esac + + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + # For libtool versioning info, format is CURRENT:REVISION:AGE + libtool_VERSION=1:0:0 +@@ -15672,7 +15779,7 @@ case "$host" in + case "$enable_cet" in + auto) + # Check if target supports multi-byte NOPs +- # and if assembler supports CET insn. ++ # and if compiler and assembler support CET insn. + cet_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fcf-protection" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -15987,6 +16094,10 @@ if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${VTV_CYGMIN_TRUE}" && test -z "${VTV_CYGMIN_FALSE}"; then + as_fn_error $? "conditional \"VTV_CYGMIN\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/libvtv/configure.ac b/libvtv/configure.ac +index f3b937e4b10..50aaadbb3a3 100644 +--- a/libvtv/configure.ac ++++ b/libvtv/configure.ac +@@ -153,6 +153,7 @@ AM_PROG_LIBTOOL + ACX_LT_HOST_FLAGS + AC_SUBST(enable_shared) + AC_SUBST(enable_static) ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + + # For libtool versioning info, format is CURRENT:REVISION:AGE + libtool_VERSION=1:0:0 +diff --git a/lto-plugin/configure b/lto-plugin/configure +index b820accfd65..8faa13c4a8b 100755 +--- a/lto-plugin/configure ++++ b/lto-plugin/configure +@@ -634,6 +634,8 @@ LTLIBOBJS + LIBOBJS + target_noncanonical + lt_host_flags ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + OTOOL64 + OTOOL + LIPO +@@ -785,6 +787,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + ' + ac_precious_vars='build_alias + host_alias +@@ -1430,6 +1433,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + + Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] +@@ -10275,6 +10280,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -10292,10 +10338,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -12081,7 +12136,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12084 "configure" ++#line 12139 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12187,7 +12242,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 12190 "configure" ++#line 12245 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -12424,6 +12479,14 @@ CC="$lt_save_CC" + # Only expand once: + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + + +@@ -12670,6 +12733,10 @@ if test -z "${LTO_PLUGIN_USE_SYMVER_SUN_TRUE}" && test -z "${LTO_PLUGIN_USE_SYMV + as_fn_error $? "conditional \"LTO_PLUGIN_USE_SYMVER_SUN\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + + : "${CONFIG_STATUS=./config.status}" + ac_write_fail=0 +diff --git a/lto-plugin/configure.ac b/lto-plugin/configure.ac +index bc5b618a495..317596288b2 100644 +--- a/lto-plugin/configure.ac ++++ b/lto-plugin/configure.ac +@@ -88,6 +88,7 @@ AM_CONDITIONAL(LTO_PLUGIN_USE_SYMVER_GNU, [test "x$lto_plugin_use_symver" = xgnu + AM_CONDITIONAL(LTO_PLUGIN_USE_SYMVER_SUN, [test "x$lto_plugin_use_symver" = xsun]) + + AM_PROG_LIBTOOL ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + ACX_LT_HOST_FLAGS + AC_SUBST(target_noncanonical) + AC_TYPE_INT64_T +diff --git a/zlib/configure b/zlib/configure +index f489f31bc70..f7adce0db2c 100755 +--- a/zlib/configure ++++ b/zlib/configure +@@ -639,6 +639,8 @@ TARGET_LIBRARY_FALSE + TARGET_LIBRARY_TRUE + toolexeclibdir + toolexecdir ++ENABLE_DARWIN_AT_RPATH_FALSE ++ENABLE_DARWIN_AT_RPATH_TRUE + CPP + OTOOL64 + OTOOL +@@ -776,6 +778,7 @@ with_pic + enable_fast_install + with_gnu_ld + enable_libtool_lock ++enable_darwin_at_rpath + with_toolexeclibdir + enable_host_shared + ' +@@ -1419,6 +1422,8 @@ Optional Features: + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) ++ --enable-darwin-at-path install libraries with @rpath/library-name, requires ++ rpaths to be added to executables + --enable-host-shared build host code as shared libraries + + Optional Packages: +@@ -4169,7 +4174,7 @@ case "$host" in + case "$enable_cet" in + auto) + # Check if target supports multi-byte NOPs +- # and if assembler supports CET insn. ++ # and if compiler and assembler support CET insn. + cet_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fcf-protection" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +@@ -8908,6 +8913,47 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + darwin* | rhapsody*) + + ++ ++ # Publish an arg to allow the user to select that Darwin host (and target) ++ # libraries should be given install-names like @rpath/libfoo.dylib. This ++ # requires that the user of the library then adds an 'rpath' to the DSO that ++ # needs access. ++ # NOTE: there are defaults below, for systems that support rpaths. The person ++ # configuring can override the defaults for any system version that supports ++ # them - they are, however, forced off for system versions without support. ++ # Check whether --enable-darwin-at-rpath was given. ++if test "${enable_darwin_at_rpath+set}" = set; then : ++ enableval=$enable_darwin_at_rpath; if test "x$enable_darwin_at_rpath" = "xyes"; then ++ # This is not supported before macOS 10.5 / Darwin9. ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ echo "WARNING: Darwin @rpath library names are incompatible with macOS versions earlier than 10.5 (rpaths disabled)" 1>&5 ++ enable_darwin_at_rpath=no ++ ;; ++ esac ++ fi ++else ++ case ${MACOSX_DEPLOYMENT_TARGET-UNSET},$host_os in ++ # As above, before 10.5 / Darwin9 this does not work. ++ UNSET,darwin[45678]*|UNSET,rhapsody*|10.[01234][,.]*) ++ enable_darwin_at_rpath=no ++ ;; ++ ++ # We cannot build and test reliably on macOS 10.11+ (Darwin15+) without use ++ # of rpaths, since runpaths set via DYLD_LIBRARY_PATH are elided by key ++ # system executables (e.g. /bin/sh). Force rpaths on for these systems. ++ UNSET,darwin1[56789]*|UNSET,darwin2*|10.1[123456789][,.]*|1[123456789].*[,.]* ) ++ echo "@rpath library names are needed on macOS versions later than 10.11 (rpaths enabled)" 1>&5 ++ enable_darwin_at_rpath=yes ++ ;; ++ # NOTE: we are not (yet) doing anything for 10.5 .. 10.10, since they can ++ # work with either DYLD_LIBRARY_PATH or embedded rpaths. ++ ++ esac ++ ++fi ++ ++ + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes +@@ -8925,10 +8971,19 @@ if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all +- archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" +- module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" +- archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" +- module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ if test "x$enable_darwin_at_rpath" = "xyes"; then ++ echo "using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name @rpath/\$soname \$verstring ${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ else ++ echo "NOT using Darwin @rpath" 1>&5 ++ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" ++ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" ++ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" ++ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" ++ fi + + else + ld_shlibs=no +@@ -10735,7 +10790,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 10748 "configure" ++#line 10793 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -10841,7 +10896,7 @@ else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +-#line 10854 "configure" ++#line 10899 "configure" + #include "confdefs.h" + + #if HAVE_DLFCN_H +@@ -11078,6 +11133,14 @@ CC="$lt_save_CC" + # Only expand once: + + ++ if test x$enable_darwin_at_rpath = xyes; then ++ ENABLE_DARWIN_AT_RPATH_TRUE= ++ ENABLE_DARWIN_AT_RPATH_FALSE='#' ++else ++ ENABLE_DARWIN_AT_RPATH_TRUE='#' ++ ENABLE_DARWIN_AT_RPATH_FALSE= ++fi ++ + + # Find CPP now so that any conditional tests below won't do it and + # thereby make the resulting definitions conditional. +@@ -11708,6 +11771,10 @@ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 + fi ++if test -z "${ENABLE_DARWIN_AT_RPATH_TRUE}" && test -z "${ENABLE_DARWIN_AT_RPATH_FALSE}"; then ++ as_fn_error $? "conditional \"ENABLE_DARWIN_AT_RPATH\" was never defined. ++Usually this means the macro was only invoked conditionally." "$LINENO" 5 ++fi + if test -z "${TARGET_LIBRARY_TRUE}" && test -z "${TARGET_LIBRARY_FALSE}"; then + as_fn_error $? "conditional \"TARGET_LIBRARY\" was never defined. + Usually this means the macro was only invoked conditionally." "$LINENO" 5 +diff --git a/zlib/configure.ac b/zlib/configure.ac +index be1cfe29651..2327d003a05 100644 +--- a/zlib/configure.ac ++++ b/zlib/configure.ac +@@ -64,6 +64,7 @@ GCC_CET_FLAGS(CET_FLAGS) + AC_SUBST(CET_FLAGS) + + AC_PROG_LIBTOOL ++AM_CONDITIONAL([ENABLE_DARWIN_AT_RPATH], [test x$enable_darwin_at_rpath = xyes]) + + # Find CPP now so that any conditional tests below won't do it and + # thereby make the resulting definitions conditional. diff --git a/build/pkgs/gcc/spkg-build.in b/build/pkgs/gcc/spkg-build.in index 2c07c4ea988..215201207d6 100644 --- a/build/pkgs/gcc/spkg-build.in +++ b/build/pkgs/gcc/spkg-build.in @@ -1,41 +1,6 @@ # Exit on error set -e -# The ld (linker) on old Darwin systems doesn't understand -# -compatibility_version, it needs -dylib_compatibility_version. -# Similarly for a few more options. We create an ld wrapper to fix -# these command line options. -if { uname -sr | grep 'Darwin [0-9]\.' ;} &>/dev/null; then - mkdir -p bin/ - LD=`which "${LD:-ld}"` - - echo '#!/bin/bash' >>"bin/ld" - echo '# ld wrapper generated by the GCC spkg' >>"bin/ld" - echo >>"bin/ld" - # Hardcode the path to the "real" ld. - echo "LD=$LD" >>"bin/ld" - -cat >>"bin/ld" <<'EOF' - -for arg in "$@"; do - arg=`echo "$arg" | sed \ - -e 's/^-\(compatibility_version\)/-dylib_\1/' \ - -e 's/^-\(current_version\)/-dylib_\1/' \ - -e 's/^-\(install_name\)/-dylib_\1/' \ - ` - argv=("${argv[@]}" "$arg") -done - -exec "$LD" "${argv[@]}" -EOF - - chmod +x "bin/ld" - - # Make GCC use this ld wrapper (found in the $PATH) - export LD=ld - export PATH="$(pwd)/bin:$PATH" -fi - # On OS X 10.9, g++ and the cdefs.h header are currently incompatible # Temporary workaround posted at http://trac.macports.org/ticket/41033 if { uname -sr | grep 'Darwin 13\.' ;} &>/dev/null; then 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/gfortran/spkg-build.in b/build/pkgs/gfortran/spkg-build.in index ac74c12ad5c..bf4ce381cfe 100644 --- a/build/pkgs/gfortran/spkg-build.in +++ b/build/pkgs/gfortran/spkg-build.in @@ -8,4 +8,4 @@ case $(uname -m),"$ARCH" in ;; esac -./build-gcc --disable-bootstrap --enable-languages=fortran $EXTRA_GCC_CONFIGURE +./build-gcc --disable-bootstrap --enable-languages=fortran --disable-darwin-at-rpath $EXTRA_GCC_CONFIGURE diff --git a/build/pkgs/github_cli/SPKG.rst b/build/pkgs/github_cli/SPKG.rst new file mode 100644 index 00000000000..5ab5b6bfbdc --- /dev/null +++ b/build/pkgs/github_cli/SPKG.rst @@ -0,0 +1,19 @@ +github_cli: Command-line interface for GitHub +============================================= + +Description +----------- + +``gh`` is GitHub on the command line. It brings pull requests, issues, and +other GitHub concepts to the terminal next to where you are already +working with ``git`` and your code. + +License +------- + +MIT + +Upstream Contact +---------------- + +https://github.com/cli/cli diff --git a/build/pkgs/github_cli/distros/alpine.txt b/build/pkgs/github_cli/distros/alpine.txt new file mode 100644 index 00000000000..5b249a1e859 --- /dev/null +++ b/build/pkgs/github_cli/distros/alpine.txt @@ -0,0 +1 @@ +github-cli diff --git a/build/pkgs/github_cli/distros/arch.txt b/build/pkgs/github_cli/distros/arch.txt new file mode 100644 index 00000000000..5b249a1e859 --- /dev/null +++ b/build/pkgs/github_cli/distros/arch.txt @@ -0,0 +1 @@ +github-cli diff --git a/build/pkgs/github_cli/distros/conda.txt b/build/pkgs/github_cli/distros/conda.txt new file mode 100644 index 00000000000..7f8d49f4704 --- /dev/null +++ b/build/pkgs/github_cli/distros/conda.txt @@ -0,0 +1 @@ +gh diff --git a/build/pkgs/github_cli/distros/debian.txt b/build/pkgs/github_cli/distros/debian.txt new file mode 100644 index 00000000000..7f8d49f4704 --- /dev/null +++ b/build/pkgs/github_cli/distros/debian.txt @@ -0,0 +1 @@ +gh diff --git a/build/pkgs/github_cli/distros/fedora.txt b/build/pkgs/github_cli/distros/fedora.txt new file mode 100644 index 00000000000..7f8d49f4704 --- /dev/null +++ b/build/pkgs/github_cli/distros/fedora.txt @@ -0,0 +1 @@ +gh diff --git a/build/pkgs/github_cli/distros/freebsd.txt b/build/pkgs/github_cli/distros/freebsd.txt new file mode 100644 index 00000000000..7362ba57a11 --- /dev/null +++ b/build/pkgs/github_cli/distros/freebsd.txt @@ -0,0 +1 @@ +devel/gh diff --git a/build/pkgs/github_cli/distros/gentoo.txt b/build/pkgs/github_cli/distros/gentoo.txt new file mode 100644 index 00000000000..660aea3ced4 --- /dev/null +++ b/build/pkgs/github_cli/distros/gentoo.txt @@ -0,0 +1 @@ +dev-util/github-cli diff --git a/build/pkgs/github_cli/distros/homebrew.txt b/build/pkgs/github_cli/distros/homebrew.txt new file mode 100644 index 00000000000..7f8d49f4704 --- /dev/null +++ b/build/pkgs/github_cli/distros/homebrew.txt @@ -0,0 +1 @@ +gh diff --git a/build/pkgs/github_cli/distros/macports.txt b/build/pkgs/github_cli/distros/macports.txt new file mode 100644 index 00000000000..7f8d49f4704 --- /dev/null +++ b/build/pkgs/github_cli/distros/macports.txt @@ -0,0 +1 @@ +gh diff --git a/build/pkgs/github_cli/distros/nix.txt b/build/pkgs/github_cli/distros/nix.txt new file mode 100644 index 00000000000..7f8d49f4704 --- /dev/null +++ b/build/pkgs/github_cli/distros/nix.txt @@ -0,0 +1 @@ +gh diff --git a/build/pkgs/github_cli/distros/opensuse.txt b/build/pkgs/github_cli/distros/opensuse.txt new file mode 100644 index 00000000000..7f8d49f4704 --- /dev/null +++ b/build/pkgs/github_cli/distros/opensuse.txt @@ -0,0 +1 @@ +gh diff --git a/build/pkgs/github_cli/distros/repology.txt b/build/pkgs/github_cli/distros/repology.txt new file mode 100644 index 00000000000..5b249a1e859 --- /dev/null +++ b/build/pkgs/github_cli/distros/repology.txt @@ -0,0 +1 @@ +github-cli diff --git a/build/pkgs/github_cli/distros/void.txt b/build/pkgs/github_cli/distros/void.txt new file mode 100644 index 00000000000..5b249a1e859 --- /dev/null +++ b/build/pkgs/github_cli/distros/void.txt @@ -0,0 +1 @@ +github-cli diff --git a/build/pkgs/github_cli/type b/build/pkgs/github_cli/type new file mode 100644 index 00000000000..134d9bc32d5 --- /dev/null +++ b/build/pkgs/github_cli/type @@ -0,0 +1 @@ +optional diff --git a/build/pkgs/gsl/checksums.ini b/build/pkgs/gsl/checksums.ini index affe99b550f..8bef7d5f43c 100644 --- a/build/pkgs/gsl/checksums.ini +++ b/build/pkgs/gsl/checksums.ini @@ -1,5 +1,5 @@ tarball=gsl-VERSION.tar.gz -sha1=29179db0d746f422bb0ceca2cbda4de107a2c651 -md5=9e47e81caaebcd92b7aca27a5348df74 -cksum=2494121348 +sha1=549e1105cd1198537be9707257161531e109bd94 +md5=36aee97e67f64dbdab7afae197e3483b +cksum=171022903 upstream_url=https://ftp.gnu.org/gnu/gsl/gsl-VERSION.tar.gz diff --git a/build/pkgs/gsl/package-version.txt b/build/pkgs/gsl/package-version.txt index 1effb003408..860487ca19c 100644 --- a/build/pkgs/gsl/package-version.txt +++ b/build/pkgs/gsl/package-version.txt @@ -1 +1 @@ -2.7 +2.7.1 diff --git a/build/pkgs/gsl/patches/configure-big_sur.patch b/build/pkgs/gsl/patches/configure-big_sur.patch new file mode 100644 index 00000000000..aba05df4d8a --- /dev/null +++ b/build/pkgs/gsl/patches/configure-big_sur.patch @@ -0,0 +1,23 @@ +--- a/configure.orig 2021-10-01 08:15:08.000000000 -0700 ++++ b/configure 2021-10-20 12:44:47.000000000 -0700 +@@ -8733,16 +8733,11 @@ + _lt_dar_allow_undefined='$wl-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; +- darwin*) # darwin 5.x on +- # if running on 10.5 or later, the deployment target defaults +- # to the OS version, if on x86, and 10.4, the deployment +- # target defaults to 10.4. Don't you love it? +- case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in +- 10.0,*86*-darwin8*|10.0,*-darwin[91]*) +- _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; +- 10.[012][,.]*) ++ darwin*) ++ case ${MACOSX_DEPLOYMENT_TARGET},$host in ++ 10.[012],*|,*powerpc*) + _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;; +- 10.*) ++ *) + _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;; + esac + ;; 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/igraph/checksums.ini b/build/pkgs/igraph/checksums.ini index 9da572238e5..f7d3336bda8 100644 --- a/build/pkgs/igraph/checksums.ini +++ b/build/pkgs/igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=igraph-VERSION.tar.gz -sha1=74abe82bdebdefc295a4f04b54170880dcb265e8 -md5=4e61e5e86ebe4fe478df415b7407e87e -cksum=2574937983 +sha1=20587332f0f36d6d7eb3cca248e2dab76e1e58ad +md5=af41eb9c614946c4a92a51834e9cab4a +cksum=4011381306 upstream_url=https://github.com/igraph/igraph/releases/download/VERSION/igraph-VERSION.tar.gz diff --git a/build/pkgs/igraph/package-version.txt b/build/pkgs/igraph/package-version.txt index 571215736a6..5eef0f10e8c 100644 --- a/build/pkgs/igraph/package-version.txt +++ b/build/pkgs/igraph/package-version.txt @@ -1 +1 @@ -0.10.1 +0.10.2 diff --git a/build/pkgs/imagesize/checksums.ini b/build/pkgs/imagesize/checksums.ini index 6a49dac52c4..8e0bef1a816 100644 --- a/build/pkgs/imagesize/checksums.ini +++ b/build/pkgs/imagesize/checksums.ini @@ -1,5 +1,5 @@ tarball=imagesize-VERSION.tar.gz -sha1=b88a92cabe93b5a53faacb1cff4e50f8a2d9427a -md5=3a1e124594183778a8f87e4bcdb6dca9 -cksum=2804705518 +sha1=89627e703f80c3ad2a77cc8168d85d119e71dcbe +md5=5a40586a25c07e1a8f16f6267252c321 +cksum=3711184129 upstream_url=https://pypi.io/packages/source/i/imagesize/imagesize-VERSION.tar.gz diff --git a/build/pkgs/imagesize/package-version.txt b/build/pkgs/imagesize/package-version.txt index 26aaba0e866..347f5833ee6 100644 --- a/build/pkgs/imagesize/package-version.txt +++ b/build/pkgs/imagesize/package-version.txt @@ -1 +1 @@ -1.2.0 +1.4.1 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/ipywidgets/checksums.ini b/build/pkgs/ipywidgets/checksums.ini index e250f8111d0..63a890dcf81 100644 --- a/build/pkgs/ipywidgets/checksums.ini +++ b/build/pkgs/ipywidgets/checksums.ini @@ -1,5 +1,5 @@ tarball=ipywidgets-VERSION.tar.gz -sha1=db842df5008a1786ab6434875c2d56b974c5109a -md5=61deb9024c3de1848812b97c2560d0cf -cksum=3129459111 +sha1=b2c8adf4fefc012adfb61e03a2e957bddbbb7597 +md5=c976de164b782eac9e5dfc933e8da295 +cksum=305610881 upstream_url=https://pypi.io/packages/source/i/ipywidgets/ipywidgets-VERSION.tar.gz diff --git a/build/pkgs/ipywidgets/dependencies b/build/pkgs/ipywidgets/dependencies index e6cc2ed95d5..64f5151c754 100644 --- a/build/pkgs/ipywidgets/dependencies +++ b/build/pkgs/ipywidgets/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) widgetsnbextension | $(PYTHON_TOOLCHAIN) ipykernel ipython traitlets +$(PYTHON) widgetsnbextension jupyterlab_widgets | $(PYTHON_TOOLCHAIN) ipykernel ipython traitlets ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/ipywidgets/package-version.txt b/build/pkgs/ipywidgets/package-version.txt index 1985849fb58..8b22a322d0f 100644 --- a/build/pkgs/ipywidgets/package-version.txt +++ b/build/pkgs/ipywidgets/package-version.txt @@ -1 +1 @@ -7.7.0 +8.0.2 diff --git a/build/pkgs/ipywidgets/patches/0001-setup.py-Remove-install-requires-of-jupyterlab_widge.patch b/build/pkgs/ipywidgets/patches/0001-setup.py-Remove-install-requires-of-jupyterlab_widge.patch deleted file mode 100644 index fed30e5445e..00000000000 --- a/build/pkgs/ipywidgets/patches/0001-setup.py-Remove-install-requires-of-jupyterlab_widge.patch +++ /dev/null @@ -1,35 +0,0 @@ -From e64096431a7099f8db46748ef7d1021939f1a624 Mon Sep 17 00:00:00 2001 -From: Matthias Koeppe -Date: Wed, 24 Mar 2021 12:59:13 -0700 -Subject: [PATCH] setup.py: Remove install-requires of jupyterlab_widgets, - nbformat - ---- - setup.py | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/setup.py b/setup.py -index e544267a..bff154af 100644 ---- a/setup.py -+++ b/setup.py -@@ -112,9 +112,6 @@ setuptools_args = {} - install_requires = setuptools_args['install_requires'] = [ - 'ipykernel>=4.5.1', - 'traitlets>=4.3.1', -- # Requiring nbformat to specify bugfix version which is not required by -- # notebook. -- 'nbformat>=4.2.0', - # TODO: Dynamically add this dependency - # only if notebook 4.x is installed in this - # interpreter, to allow ipywidgets to be -@@ -125,7 +122,6 @@ install_requires = setuptools_args['install_requires'] = [ - extras_require = setuptools_args['extras_require'] = { - ':python_version<"3.3"' : ['ipython>=4.0.0,<6.0.0'], - ':python_version>="3.3"': ['ipython>=4.0.0'], -- ':python_version>="3.6"': ['jupyterlab_widgets>=1.0.0'], - 'test:python_version=="2.7"': ['mock'], - 'test': ['pytest>=3.6.0', 'pytest-cov'], - } --- -2.28.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/jupyterlab_widgets/SPKG.rst b/build/pkgs/jupyterlab_widgets/SPKG.rst index f17f3c08eda..758cff7b3db 100644 --- a/build/pkgs/jupyterlab_widgets/SPKG.rst +++ b/build/pkgs/jupyterlab_widgets/SPKG.rst @@ -1,18 +1,18 @@ -jupyterlab_widgets: A JupyterLab extension for Jupyter/IPython widgets -====================================================================== +jupyterlab_widgets: Jupyter interactive widgets for JupyterLab +============================================================== Description ----------- -A JupyterLab extension for Jupyter/IPython widgets. +Jupyter interactive widgets for JupyterLab License ------- -BSD License +BSD-3-Clause Upstream Contact ---------------- -Home page: https://github.com/jupyter-widgets/ipywidgets +https://pypi.org/project/jupyterlab-widgets/ diff --git a/build/pkgs/jupyterlab_widgets/checksums.ini b/build/pkgs/jupyterlab_widgets/checksums.ini new file mode 100644 index 00000000000..5d021049263 --- /dev/null +++ b/build/pkgs/jupyterlab_widgets/checksums.ini @@ -0,0 +1,5 @@ +tarball=jupyterlab_widgets-VERSION-py3-none-any.whl +sha1=584e25e221b38c3ca7139667621a3eaf23260ffc +md5=d7b643a04ef1bb9012c58e6833d277c9 +cksum=202463248 +upstream_url=https://pypi.io/packages/py3/j/jupyterlab_widgets/jupyterlab_widgets-VERSION-py3-none-any.whl diff --git a/build/pkgs/jupyterlab_widgets/dependencies b/build/pkgs/jupyterlab_widgets/dependencies index 4d2deddc8bf..0738c2d7777 100644 --- a/build/pkgs/jupyterlab_widgets/dependencies +++ b/build/pkgs/jupyterlab_widgets/dependencies @@ -1,4 +1,4 @@ -ipympl jupyterlab nodejs tornado $(PYTHON) | $(PYTHON_TOOLCHAIN) jupyter_packaging +$(PYTHON) | $(PYTHON_TOOLCHAIN) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/jupyterlab_widgets/requirements.txt b/build/pkgs/jupyterlab_widgets/install-requires.txt similarity index 100% rename from build/pkgs/jupyterlab_widgets/requirements.txt rename to build/pkgs/jupyterlab_widgets/install-requires.txt diff --git a/build/pkgs/jupyterlab_widgets/package-version.txt b/build/pkgs/jupyterlab_widgets/package-version.txt new file mode 100644 index 00000000000..75a22a26ac4 --- /dev/null +++ b/build/pkgs/jupyterlab_widgets/package-version.txt @@ -0,0 +1 @@ +3.0.3 diff --git a/build/pkgs/jupyterlab_widgets/type b/build/pkgs/jupyterlab_widgets/type index 134d9bc32d5..a6a7b9cd726 100644 --- a/build/pkgs/jupyterlab_widgets/type +++ b/build/pkgs/jupyterlab_widgets/type @@ -1 +1 @@ -optional +standard diff --git a/build/pkgs/latte_int/patches/6dbf7f07d5c9e1f3afe793f782d191d4465088ae.patch b/build/pkgs/latte_int/patches/6dbf7f07d5c9e1f3afe793f782d191d4465088ae.patch index 308456304d7..199ab2d0156 100644 --- a/build/pkgs/latte_int/patches/6dbf7f07d5c9e1f3afe793f782d191d4465088ae.patch +++ b/build/pkgs/latte_int/patches/6dbf7f07d5c9e1f3afe793f782d191d4465088ae.patch @@ -51,29 +51,3 @@ index c9fa4ace..43a4ab63 100644 ZZ scalar_power(const vec_ZZ &generic_vector, -diff --git a/code/latte/sqlite/IntegrationDB.cpp b/code/latte/sqlite/IntegrationDB.cpp -index ab8df535..c1dde830 100644 ---- a/code/latte/sqlite/IntegrationDB.cpp -+++ b/code/latte/sqlite/IntegrationDB.cpp -@@ -1277,7 +1277,7 @@ void IntegrationDB::insertSpecficPolytopeIntegrationTest(string polymakeFile, i - * @parm filePath: to the latte-style polynomial. - * @return rowid of the inserted row. - */ --int IntegrationDB::insertPolynomial(int dim, int degree, const char*filePath) throw(SqliteDBexception) -+int IntegrationDB::insertPolynomial(int dim, int degree, const char*filePath) - { - if ( doesPolynomialExist(filePath)) - throw SqliteDBexception(string("insertPolynomial::Polynomial ")+filePath+" already exist"); -diff --git a/code/latte/sqlite/IntegrationDB.h b/code/latte/sqlite/IntegrationDB.h -index d690a832..ce8cfac6 100644 ---- a/code/latte/sqlite/IntegrationDB.h -+++ b/code/latte/sqlite/IntegrationDB.h -@@ -67,7 +67,7 @@ class IntegrationDB: public SqliteDB - int insertIntegrationTest(int polynomialID, int polytopeID); - void insertIntegrationTest(int dim, int degree, int vertexCount, int count); - void insertSpecficPolytopeIntegrationTest(string polymakeFile, int degree, int count); -- int insertPolynomial(int dim, int degree, const char*filePath) throw(SqliteDBexception); -+ int insertPolynomial(int dim, int degree, const char*filePath); - - int insertPolytope(int dim, int vertexCount, int simple, int dualRowID, const char* latteFilePath, const char* polymakeFilePath); - 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/normaliz/checksums.ini b/build/pkgs/normaliz/checksums.ini index c3afbfb2656..f7d47180ceb 100644 --- a/build/pkgs/normaliz/checksums.ini +++ b/build/pkgs/normaliz/checksums.ini @@ -1,5 +1,5 @@ tarball=normaliz-VERSION.tar.gz -sha1=7486d046c5e8e352d6d7c3544a0e6a1164e9b1fd -md5=136edc12b5c027bb1a019e06fb8d9113 -cksum=1640404889 +sha1=6382fcb14b0e602f5bf7d5abd53b421d0e3a0a3d +md5=1c6bdd4da166da1718b08a3b9ee40949 +cksum=2272467212 upstream_url=https://github.com/Normaliz/Normaliz/releases/download/vVERSION/normaliz-VERSION.tar.gz diff --git a/build/pkgs/normaliz/distros/arch.txt b/build/pkgs/normaliz/distros/arch.txt new file mode 100644 index 00000000000..d0991c684ae --- /dev/null +++ b/build/pkgs/normaliz/distros/arch.txt @@ -0,0 +1 @@ +normaliz diff --git a/build/pkgs/normaliz/distros/debian.txt b/build/pkgs/normaliz/distros/debian.txt new file mode 100644 index 00000000000..a3144cefbbb --- /dev/null +++ b/build/pkgs/normaliz/distros/debian.txt @@ -0,0 +1 @@ +libnormaliz-dev diff --git a/build/pkgs/normaliz/distros/fedora.txt b/build/pkgs/normaliz/distros/fedora.txt new file mode 100644 index 00000000000..b48a8dfa158 --- /dev/null +++ b/build/pkgs/normaliz/distros/fedora.txt @@ -0,0 +1 @@ +libnormaliz-devel diff --git a/build/pkgs/normaliz/distros/gentoo.txt b/build/pkgs/normaliz/distros/gentoo.txt new file mode 100644 index 00000000000..4c0fae119ad --- /dev/null +++ b/build/pkgs/normaliz/distros/gentoo.txt @@ -0,0 +1 @@ +sci-mathematics/normaliz diff --git a/build/pkgs/normaliz/package-version.txt b/build/pkgs/normaliz/package-version.txt index d20cc2bf020..e0d61b5b062 100644 --- a/build/pkgs/normaliz/package-version.txt +++ b/build/pkgs/normaliz/package-version.txt @@ -1 +1 @@ -3.8.10 +3.9.4 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/openblas/checksums.ini b/build/pkgs/openblas/checksums.ini index eb87a1d197d..e6e83e7d891 100644 --- a/build/pkgs/openblas/checksums.ini +++ b/build/pkgs/openblas/checksums.ini @@ -1,5 +1,5 @@ tarball=openblas-VERSION.tar.gz -sha1=45ec54b75f53f5b704250e60bd8e82a49b430619 -md5=abfaa43d995046ca4c56ccf14165c93c -cksum=3182749926 +sha1=b052d196ad694b29302e074b3eb8cc66745f6e2f +md5=ffb6120e2309a2280471716301824805 +cksum=241092070 upstream_url=https://github.com/xianyi/OpenBLAS/archive/vVERSION.tar.gz diff --git a/build/pkgs/openblas/package-version.txt b/build/pkgs/openblas/package-version.txt index f9a4b5f993c..dfdc368868b 100644 --- a/build/pkgs/openblas/package-version.txt +++ b/build/pkgs/openblas/package-version.txt @@ -1 +1 @@ -0.3.20 +0.3.21 diff --git a/build/pkgs/pari/spkg-configure.m4 b/build/pkgs/pari/spkg-configure.m4 index 9721849e7ba..b864d72118e 100644 --- a/build/pkgs/pari/spkg-configure.m4 +++ b/build/pkgs/pari/spkg-configure.m4 @@ -1,6 +1,7 @@ SAGE_SPKG_CONFIGURE([pari], [ dnl See gp_version below on how the version is computed from MAJV.MINV.PATCHV - m4_pushdef([SAGE_PARI_MINVER],["134401"]) + m4_pushdef([SAGE_PARI_MINVER],["134401"])dnl this version and higher allowed + m4_pushdef([SAGE_PARI_MAXVER],["134912"])dnl this version and higher not allowed SAGE_SPKG_DEPCHECK([gmp readline], [ AC_PATH_PROG([GP], [gp]) if test x$GP = x; then dnl GP test @@ -101,6 +102,7 @@ SAGE_SPKG_CONFIGURE([pari], [ [AC_MSG_RESULT([cross compiling. Assume they match])]) AC_MSG_CHECKING([is GP's version good enough? ]) AX_COMPARE_VERSION([$gp_version], [ge], [$SAGE_PARI_MINVER], [ + AX_COMPARE_VERSION([$gp_version], [lt], [$SAGE_PARI_MAXVER], [ AC_MSG_RESULT([yes]) AC_MSG_CHECKING([getting GP's datadir]) gp_datadir=`echo "default(datadir)" | $GP -qf 2>> config.log` @@ -127,13 +129,17 @@ SAGE_SPKG_CONFIGURE([pari], [ [AC_MSG_RESULT([libpari's datadir does not match GP's datadir. Not good]) sage_spkg_install_pari=yes], [AC_MSG_RESULT([cross compiling. Assume yes])]) - ], [ + ], [dnl compared maxver + AC_MSG_RESULT([no]) + sage_spkg_install_pari=yes], [AC_MSG_RESULT([cross compiling. Assume yes])]) + ], [dnl compared minver AC_MSG_RESULT([no]) sage_spkg_install_pari=yes], [AC_MSG_RESULT([cross compiling. Assume yes])]) AC_LANG_POP() ], [sage_spkg_install_pari=yes]) fi dnl end main PARI test ]) + m4_popdef([SAGE_PARI_MAXVER]) m4_popdef([SAGE_PARI_MINVER]) ], [], [], [ if test x$sage_spkg_install_pari = xyes; then 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/primesieve/patches/107.patch b/build/pkgs/primesieve/patches/107.patch deleted file mode 100644 index d8986d29337..00000000000 --- a/build/pkgs/primesieve/patches/107.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 1f8d0470b4e9d50393032b86d21a7a2fcc512355 Mon Sep 17 00:00:00 2001 -From: Matthias Koeppe -Date: Sat, 27 Nov 2021 10:50:09 -0800 -Subject: [PATCH] src/MemoryPool.cpp: Work around missing std::align on GCC 4.x - ---- - src/MemoryPool.cpp | 27 ++++++++++++++++++++++++++- - 1 file changed, 26 insertions(+), 1 deletion(-) - -diff --git a/src/MemoryPool.cpp b/src/MemoryPool.cpp -index 7a4a4006..60f62101 100644 ---- a/src/MemoryPool.cpp -+++ b/src/MemoryPool.cpp -@@ -26,6 +26,31 @@ - - using std::size_t; - -+#if defined(__GNUC__) && __GNUC__ == 4 -+ -+// gcc 4.9 does not implement std::align. -+// Use the implementation from -+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57350#c11 -+ -+using std::uintptr_t; -+ -+static inline void *align(size_t alignment, size_t size, -+ void *&ptr, size_t &space) -+{ -+ uintptr_t pn = reinterpret_cast(ptr); -+ uintptr_t aligned = (pn + alignment - 1) & -alignment; -+ size_t padding = aligned - pn; -+ if (space < size + padding) return nullptr; -+ space -= padding; -+ return ptr = reinterpret_cast(aligned); -+} -+ -+#else -+ -+using std::align; -+ -+#endif -+ - namespace primesieve { - - void MemoryPool::addBucket(SievingPrime*& sievingPrime) -@@ -70,7 +95,7 @@ void MemoryPool::allocateBuckets() - void* ptr = memory; - - // Align pointer address to sizeof(Bucket) -- if (!std::align(sizeof(Bucket), sizeof(Bucket), ptr, bytes)) -+ if (!align(sizeof(Bucket), sizeof(Bucket), ptr, bytes)) - throw primesieve_error("MemoryPool: failed to align memory!"); - - initBuckets(ptr, bytes); diff --git a/build/pkgs/pynormaliz/checksums.ini b/build/pkgs/pynormaliz/checksums.ini index a7e0febfe80..d9f614efaf9 100644 --- a/build/pkgs/pynormaliz/checksums.ini +++ b/build/pkgs/pynormaliz/checksums.ini @@ -1,5 +1,5 @@ tarball=PyNormaliz-VERSION.tar.gz -sha1=f24f5c4a1b9b7a084ad1f2a0b95374d1a83e31b2 -md5=51e67733702d6cea3cd81144888d9dc7 -cksum=3201946747 +sha1=de8771b0339c4567665331df221c880bfe2b69a2 +md5=e8a571bdc3a8fcad16fdfabf9a6874d3 +cksum=2734845416 upstream_url=https://pypi.io/packages/source/p/pynormaliz/PyNormaliz-VERSION.tar.gz diff --git a/build/pkgs/pynormaliz/install-requires.txt b/build/pkgs/pynormaliz/install-requires.txt index ecc1ec0712b..b1e222ae76c 100644 --- a/build/pkgs/pynormaliz/install-requires.txt +++ b/build/pkgs/pynormaliz/install-requires.txt @@ -1 +1 @@ -pynormaliz ==2.14 +pynormaliz ==2.12 diff --git a/build/pkgs/pynormaliz/package-version.txt b/build/pkgs/pynormaliz/package-version.txt index 123a39a8e91..5c6fb54899b 100644 --- a/build/pkgs/pynormaliz/package-version.txt +++ b/build/pkgs/pynormaliz/package-version.txt @@ -1 +1 @@ -2.14 +2.17 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/python3/checksums.ini b/build/pkgs/python3/checksums.ini index 08ff0289325..d76bfeb7a4f 100644 --- a/build/pkgs/python3/checksums.ini +++ b/build/pkgs/python3/checksums.ini @@ -1,5 +1,5 @@ tarball=Python-VERSION.tar.xz -sha1=b80b9c13bb6ba5eb8762ca0d2b888c404582a405 -md5=f05727cb3489aa93cd57eb561c16747b -cksum=2773343227 +sha1=49ca7a5be7f13375e863442fbd9ead893ace3238 +md5=e92356b012ed4d0e09675131d39b1bde +cksum=3450973870 upstream_url=https://www.python.org/ftp/python/VERSION/Python-VERSION.tar.xz diff --git a/build/pkgs/python3/package-version.txt b/build/pkgs/python3/package-version.txt index c84ccce96a7..36435ac696d 100644 --- a/build/pkgs/python3/package-version.txt +++ b/build/pkgs/python3/package-version.txt @@ -1 +1 @@ -3.10.5 +3.10.8 diff --git a/build/pkgs/python_igraph/checksums.ini b/build/pkgs/python_igraph/checksums.ini index 9ddab211f0d..5f8bc59a4de 100644 --- a/build/pkgs/python_igraph/checksums.ini +++ b/build/pkgs/python_igraph/checksums.ini @@ -1,5 +1,5 @@ tarball=python-igraph-VERSION.tar.gz -sha1=75eae8ca6de2daa8c5ca43f99487cf20b5cdf432 -md5=18a54cd2fe507f5602e6c10584f665ee -cksum=594785782 +sha1=6a6bca77737ff501e97f808aa18a9045e86b3e3e +md5=6951cc2e803118b74209ae21d54de38a +cksum=650236223 upstream_url=https://pypi.io/packages/source/i/igraph/igraph-VERSION.tar.gz diff --git a/build/pkgs/python_igraph/package-version.txt b/build/pkgs/python_igraph/package-version.txt index 571215736a6..5eef0f10e8c 100644 --- a/build/pkgs/python_igraph/package-version.txt +++ b/build/pkgs/python_igraph/package-version.txt @@ -1 +1 @@ -0.10.1 +0.10.2 diff --git a/build/pkgs/r/bin/java b/build/pkgs/r/bin/java deleted file mode 100755 index d5e39b620f7..00000000000 --- a/build/pkgs/r/bin/java +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -exit 1 diff --git a/build/pkgs/r/bin/javac b/build/pkgs/r/bin/javac deleted file mode 100755 index d5e39b620f7..00000000000 --- a/build/pkgs/r/bin/javac +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env bash -exit 1 diff --git a/build/pkgs/r/checksums.ini b/build/pkgs/r/checksums.ini deleted file mode 100644 index 69a1a7059dc..00000000000 --- a/build/pkgs/r/checksums.ini +++ /dev/null @@ -1,5 +0,0 @@ -tarball=R-VERSION.tar.gz -sha1=d2383dabc0d6c70f8a0171a0fb1bfdc31ddb5b52 -md5=506c9576ba33e1262ad5b5624db9d96a -cksum=2403187565 -upstream_url=https://cran.r-project.org/src/base/R-3/R-VERSION.tar.gz diff --git a/build/pkgs/r/package-version.txt b/build/pkgs/r/package-version.txt deleted file mode 100644 index 4a788a01dad..00000000000 --- a/build/pkgs/r/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -3.6.3 diff --git a/build/pkgs/r/patches/autoconf_verb_dash.patch b/build/pkgs/r/patches/autoconf_verb_dash.patch deleted file mode 100644 index c5217fdd94d..00000000000 --- a/build/pkgs/r/patches/autoconf_verb_dash.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 04d878728603db345c0a0b01718864a12bcfa97d Mon Sep 17 00:00:00 2001 -From: Emmanuel Charpentier -Date: Wed, 14 Mar 2018 19:30:36 +0100 -Subject: [PATCH 1/9] autoconf_verb_dash - -Bug in autoconf and R macros. -Use -### instead of -v to detect linker options. -See Sage ticket #12787 and R ticket -* https://bugs.r-project.org/bugzilla3/show_bug.cgi?id=14865 -The corresponding patch to m4/clibs.m4 is not included, as -autoconf-2.68 gives errors, even on the clean upstream sources. - ---- - configure | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/configure b/configure -index a314719..dee602f 100755 ---- a/configure -+++ b/configure -@@ -24837,7 +24837,7 @@ _ACEOF - if ac_fn_f77_try_compile "$LINENO"; then : - ac_cv_prog_f77_v= - # Try some options frequently used verbose output --for ac_verb in -v -verbose --verbose -V -\#\#\#; do -+for ac_verb in -\#\#\# -v -verbose --verbose -V ; do - cat > conftest.$ac_ext <<_ACEOF - program main - -@@ -25193,7 +25193,7 @@ _ACEOF - if ac_fn_c_try_compile "$LINENO"; then : - r_cv_prog_c_v= - # Try some options frequently used verbose output --for r_verb in -v -verbose --verbose -V -\#\#\#; do -+for r_verb in -\#\#\# -v -verbose --verbose -V ; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext - /* end confdefs.h. */ - --- -2.16.1 - diff --git a/build/pkgs/r/patches/configure_bzlibtest.patch b/build/pkgs/r/patches/configure_bzlibtest.patch deleted file mode 100644 index b4d3f61ef9e..00000000000 --- a/build/pkgs/r/patches/configure_bzlibtest.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/configure b/configure -index 976de50..14b6b4c 100755 ---- a/configure -+++ b/configure -@@ -42239,6 +42239,8 @@ else - - #ifdef HAVE_BZLIB_H - #include -+#include -+#include - #endif - int main() { - char *ver = BZ2_bzlibVersion(); diff --git a/build/pkgs/r/patches/cygwin_build_support.patch b/build/pkgs/r/patches/cygwin_build_support.patch deleted file mode 100644 index e6965110602..00000000000 --- a/build/pkgs/r/patches/cygwin_build_support.patch +++ /dev/null @@ -1,123 +0,0 @@ -From b03ea08e8fe3cbda01824225447943c77c244ba8 Mon Sep 17 00:00:00 2001 -From: Emmanuel Charpentier -Date: Wed, 14 Mar 2018 19:30:36 +0100 -Subject: [PATCH 2/9] cygwin_build_support - -Patches required to explicitly support Cygwin when building R. - ---- - configure | 15 ++++++++++++--- - configure.ac | 15 ++++++++++++--- - src/library/tools/R/install.R | 2 +- - 3 files changed, 25 insertions(+), 7 deletions(-) - -diff --git a/configure b/configure -index dee602f..fadb84e 100755 ---- a/configure -+++ b/configure -@@ -27723,6 +27723,15 @@ case "${host_os}" in - shlib_cxxldflags="-shared ${shlib_cxxldflags}" - fi - ;; -+ cygwin*) -+ ## All Windows binaries are PIC -+ cpicflags= -+ cxxpicflags= -+ fpicflags= -+ fcpicflags= -+ SHLIB_EXT=".dll" -+ dylib_undefined_allowed=no -+ ;; - darwin*) - darwin_pic="-fPIC" - dylib_undefined_allowed=no -@@ -27987,7 +27996,7 @@ fi - : ${CPICFLAGS="${cpicflags}"} - if test -z "${CPICFLAGS}"; then - case "${host_os}" in -- aix*|mingw*) -+ aix*|cygwin*|mingw*) - ;; - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: I could not determine CPICFLAGS." >&5 -@@ -28000,7 +28009,7 @@ fi - : ${FPICFLAGS="${fpicflags}"} - if test -z "${FPICFLAGS}"; then - case "${host_os}" in -- aix*|mingw*) -+ aix*|cygwin*|mingw*) - ;; - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: I could not determine FPICFLAGS." >&5 -@@ -28013,7 +28022,7 @@ fi - : ${CXXPICFLAGS="${cxxpicflags}"} - if test -n "${CXX}" -a -z "${CXXPICFLAGS}"; then - case "${host_os}" in -- aix*|mingw*) -+ aix*|cygwin*|mingw*) - ;; - *) - warn_cxxpicflags="I could not determine CXXPICFLAGS." -diff --git a/configure.ac b/configure.ac -index 330d79a..ab7967b 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -1294,6 +1294,15 @@ case "${host_os}" in - shlib_cxxldflags="-shared ${shlib_cxxldflags}" - fi - ;; -+ cygwin*) -+ ## All Windows binaries are PIC -+ cpicflags= -+ cxxpicflags= -+ fpicflags= -+ fcpicflags= -+ SHLIB_EXT=".dll" -+ dylib_undefined_allowed=no -+ ;; - darwin*) - darwin_pic="-fPIC" - dylib_undefined_allowed=no -@@ -1542,7 +1551,7 @@ R_SH_VAR_ADD(MAIN_LDFLAGS, [${main_ldflags}]) - : ${CPICFLAGS="${cpicflags}"} - if test -z "${CPICFLAGS}"; then - case "${host_os}" in -- aix*|mingw*) -+ aix*|cygwin*|mingw*) - ;; - *) - AC_MSG_WARN([I could not determine CPICFLAGS.]) -@@ -1554,7 +1563,7 @@ fi - : ${FPICFLAGS="${fpicflags}"} - if test -z "${FPICFLAGS}"; then - case "${host_os}" in -- aix*|mingw*) -+ aix*|cygwin*|mingw*) - ;; - *) - AC_MSG_WARN([I could not determine FPICFLAGS.]) -@@ -1566,7 +1575,7 @@ fi - : ${CXXPICFLAGS="${cxxpicflags}"} - if test -n "${CXX}" -a -z "${CXXPICFLAGS}"; then - case "${host_os}" in -- aix*|mingw*) -+ aix*|cygwin*|mingw*) - ;; - *) - warn_cxxpicflags="I could not determine CXXPICFLAGS." -diff --git a/src/library/tools/R/install.R b/src/library/tools/R/install.R -index 6f1e9d7..662556b 100644 ---- a/src/library/tools/R/install.R -+++ b/src/library/tools/R/install.R -@@ -841,7 +841,7 @@ - setwd(owd) - test_archs <- archs - for(arch in archs) { -- if (arch == "R") { -+ if (arch == "R" || arch == "R.exe") { - ## top-level, so one arch without subdirs - has_error <- run_shlib(pkg_name, srcs, instdir, "") - } else { --- -2.16.1 - diff --git a/build/pkgs/r/patches/hardcoded_dirs.patch b/build/pkgs/r/patches/hardcoded_dirs.patch deleted file mode 100644 index e76ce4f607b..00000000000 --- a/build/pkgs/r/patches/hardcoded_dirs.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 4dc58ff28b6cc21dc9edc03b76277affc0da2bd6 Mon Sep 17 00:00:00 2001 -From: Emmanuel Charpentier -Date: Wed, 14 Mar 2018 19:30:37 +0100 -Subject: [PATCH 3/9] hardcoded_dirs - -Make R_HOME_DIR relative to SAGE_LOCAL by setting -R_HOME_DIR to "${SAGE_LOCAL}/lib/R/" when running R. - -Also remove the sed scripts hardcoding R_*_DIR's in the "frontend" R script. -See Sage trac #9668. - -This allows to move Sage install tree. - ---- - src/scripts/Makefile.in | 7 +------ - src/scripts/R.sh.in | 8 ++++++++ - 2 files changed, 9 insertions(+), 6 deletions(-) - -diff --git a/src/scripts/Makefile.in b/src/scripts/Makefile.in -index a7fa60d..ce504a0 100644 ---- a/src/scripts/Makefile.in -+++ b/src/scripts/Makefile.in -@@ -89,12 +89,7 @@ $(top_builddir)/libtool: - - install: installdirs install-cmds - @rm -f $(DESTDIR)$(bindir)/R -- @(d=`$(ECHO) '$(rhome)' | sed 's,/,\\\/,g';`; \ -- d2=`$(ECHO) '$(rsharedir)' | sed 's,/,\\\/,g';`; \ -- d3=`$(ECHO) '$(rincludedir)' | sed 's,/,\\\/,g';`; \ -- d4=`$(ECHO) '$(rdocdir)' | sed 's,/,\\\/,g';`; \ -- sed -e "1,/R_HOME_DIR=/s/\\(R_HOME_DIR=\\).*/\\1$${d}/;" -e "s/\\(R_SHARE_DIR=\\).*/\\1$${d2}/;" -e "s/\\(R_INCLUDE_DIR=\\).*/\\1$${d3}/;" -e "s/\\(R_DOC_DIR=\\).*/\\1$${d4}/;"\ -- < R.fe > "$(DESTDIR)$(Rexecbindir)/R") -+ @cat R.fe > "$(DESTDIR)$(Rexecbindir)/R" - @$(INSTALL_SCRIPT) "$(DESTDIR)$(Rexecbindir)/R" "$(DESTDIR)$(bindir)/R" - @chmod 755 "$(DESTDIR)$(bindir)/R" "$(DESTDIR)$(Rexecbindir)/R" - ## why of all the scripts does this alone chmod just one copy? -diff --git a/src/scripts/R.sh.in b/src/scripts/R.sh.in -index 674d5e0..11bfede 100644 ---- a/src/scripts/R.sh.in -+++ b/src/scripts/R.sh.in -@@ -26,6 +26,14 @@ if test "${R_HOME_DIR}" = "@prefix@/@LIBnn@/R"; then - esac - fi - -+# Make R_HOME_DIR relative to SAGE_LOCAL (if SAGE_LOCAL is set) -+# unless SAGE_BUILDING_R is set (as spkg-install does). -+if test -n "$SAGE_LOCAL"; then -+ if test -z "$SAGE_BUILDING_R"; then -+ R_HOME_DIR="$SAGE_LOCAL/lib/R/" -+ fi -+fi -+ - if test -n "${R_HOME}" && \ - test "${R_HOME}" != "${R_HOME_DIR}"; then - echo "WARNING: ignoring environment value of R_HOME" --- -2.16.1 - diff --git a/build/pkgs/r/patches/libcurl_https_support.patch b/build/pkgs/r/patches/libcurl_https_support.patch deleted file mode 100644 index 01c3c066232..00000000000 --- a/build/pkgs/r/patches/libcurl_https_support.patch +++ /dev/null @@ -1,116 +0,0 @@ -From 996ded767d76952d9aae596219f8fb1b9469ef57 Mon Sep 17 00:00:00 2001 -From: Emmanuel Charpentier -Date: Wed, 14 Mar 2018 19:30:37 +0100 -Subject: [PATCH 4/9] libcurl_https_support - -Don't check for HTTPS support in libcurl; see https://trac.sagemath.org/ticket/20523 - ---- - configure | 43 +------------------------------------------ - m4/R.m4 | 23 ++--------------------- - 2 files changed, 3 insertions(+), 63 deletions(-) - -diff --git a/configure b/configure -index fadb84e..02e210e 100755 ---- a/configure -+++ b/configure -@@ -41069,47 +41069,6 @@ if test "x${r_cv_have_curl722}" = xno; then - have_libcurl=no - fi - --if test "x${have_libcurl}" = "xyes"; then --{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if libcurl supports https" >&5 --$as_echo_n "checking if libcurl supports https... " >&6; } --if ${r_cv_have_curl_https+:} false; then : -- $as_echo_n "(cached) " >&6 --else -- if test "$cross_compiling" = yes; then : -- r_cv_have_curl_https=no --else -- cat confdefs.h - <<_ACEOF >conftest.$ac_ext --/* end confdefs.h. */ -- --#include --#include --int main() --{ -- curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); -- const char * const *p = data->protocols; -- int found = 0; -- for (; *p; p++) -- if(strcmp(*p, "https") == 0) {found = 1; break;} -- exit(found ? 0 : 1); --} -- --_ACEOF --if ac_fn_c_try_run "$LINENO"; then : -- r_cv_have_curl_https=yes --else -- r_cv_have_curl_https=no --fi --rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ -- conftest.$ac_objext conftest.beam conftest.$ac_ext --fi -- --fi --{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $r_cv_have_curl_https" >&5 --$as_echo "$r_cv_have_curl_https" >&6; } --fi --if test "x${r_cv_have_curl_https}" = xno; then -- have_libcurl=no --fi - if test "x${have_libcurl}" = xyes; then - - $as_echo "#define HAVE_LIBCURL 1" >>confdefs.h -@@ -41119,7 +41078,7 @@ $as_echo "#define HAVE_LIBCURL 1" >>confdefs.h - - - else -- as_fn_error $? "libcurl >= 7.22.0 library and headers are required with support for https" "$LINENO" 5 -+ as_fn_error $? "libcurl >= 7.22.0 library and headers are required" "$LINENO" 5 - fi - - -diff --git a/m4/R.m4 b/m4/R.m4 -index 3fe8b27..fb35a5f 100644 ---- a/m4/R.m4 -+++ b/m4/R.m4 -@@ -4205,33 +4205,14 @@ if test "x${r_cv_have_curl722}" = xno; then - have_libcurl=no - fi - --if test "x${have_libcurl}" = "xyes"; then --AC_CACHE_CHECK([if libcurl supports https], [r_cv_have_curl_https], --[AC_RUN_IFELSE([AC_LANG_SOURCE([[ --#include --#include --int main() --{ -- curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); -- const char * const *p = data->protocols; -- int found = 0; -- for (; *p; p++) -- if(strcmp(*p, "https") == 0) {found = 1; break;} -- exit(found ? 0 : 1); --} --]])], [r_cv_have_curl_https=yes], [r_cv_have_curl_https=no], [r_cv_have_curl_https=no])]) --fi --if test "x${r_cv_have_curl_https}" = xno; then -- have_libcurl=no --fi - if test "x${have_libcurl}" = xyes; then -- AC_DEFINE(HAVE_LIBCURL, 1, [Define if your system has libcurl >= 7.22.0 with support for https.]) -+ AC_DEFINE(HAVE_LIBCURL, 1, [Define if your system has libcurl >= 7.22.0.]) - CPPFLAGS="${r_save_CPPFLAGS}" - LIBS="${r_save_LIBS}" - AC_SUBST(CURL_CPPFLAGS) - AC_SUBST(CURL_LIBS) - else -- AC_MSG_ERROR([libcurl >= 7.22.0 library and headers are required with support for https]) -+ AC_MSG_ERROR([libcurl >= 7.22.0 library and headers are required]) - fi - ])# R_LIBCURL - --- -2.16.1 - diff --git a/build/pkgs/r/patches/link_all_shared_libs.patch b/build/pkgs/r/patches/link_all_shared_libs.patch deleted file mode 100644 index 980b6842ad3..00000000000 --- a/build/pkgs/r/patches/link_all_shared_libs.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 9250c9e75137e78091da1cf1c25b3dbe40c7e4bf Mon Sep 17 00:00:00 2001 -From: Emmanuel Charpentier -Date: Wed, 14 Mar 2018 19:30:37 +0100 -Subject: [PATCH 5/9] link_all_shared_libs - ---- - etc/Makeconf.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/etc/Makeconf.in b/etc/Makeconf.in -index e7d9fbd..3eccb2c 100644 ---- a/etc/Makeconf.in -+++ b/etc/Makeconf.in -@@ -150,7 +150,7 @@ ALL_OBJCFLAGS = $(PKG_OBJCFLAGS) $(CPICFLAGS) $(SHLIB_CFLAGS) $(OBJCFLAGS) - ALL_OBJCXXFLAGS = $(PKG_OBJCXXFLAGS) $(CXXPICFLAGS) $(SHLIB_CXXFLAGS) $(OBJCXXFLAGS) - ALL_FFLAGS = $(R_XTRA_FFLAGS) $(PKG_FFLAGS) $(FPICFLAGS) $(SHLIB_FFLAGS) $(FFLAGS) - ## LIBR here as a couple of packages use this without SHLIB_LINK --ALL_LIBS = $(PKG_LIBS) $(SHLIB_LIBADD) $(LIBR)@DYLIB_UNDEFINED_ALLOWED_FALSE@ $(LIBINTL) -+ALL_LIBS = $(PKG_LIBS) $(SHLIB_LIBADD) $(LIBR)@DYLIB_UNDEFINED_ALLOWED_FALSE@ $(LIBINTL) $(LIBS) - - .SUFFIXES: - .SUFFIXES: .c .cc .cpp .d .f .f90 .f95 .m .mm .M .o --- -2.16.1 - diff --git a/build/pkgs/r/patches/m4_macro_bug.patch b/build/pkgs/r/patches/m4_macro_bug.patch deleted file mode 100644 index bf96351c131..00000000000 --- a/build/pkgs/r/patches/m4_macro_bug.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 0b4ac9b9ff60a82f57bf3852056548274cbde09d Mon Sep 17 00:00:00 2001 -From: Emmanuel Charpentier -Date: Wed, 14 Mar 2018 19:30:37 +0100 -Subject: [PATCH 7/9] m4_macro_bug - -Fix bug in R_PCRE autoconf macro which leads to 'configure' losing '-lz' -and/or '-lbz2' from LIBS (under certain circumstances, and only relevant -if "system" versions of these libraries are used). (cf. #18229) - ---- - configure | 2 +- - m4/R.m4 | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/configure b/configure -index 02e210e..682b8cd 100755 ---- a/configure -+++ b/configure -@@ -40799,7 +40799,6 @@ fi - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $r_cv_have_pcre820" >&5 - $as_echo "$r_cv_have_pcre820" >&6; } --fi - if test "x${r_cv_have_pcre820}" != xyes; then - have_pcre=no - LIBS="${r_save_LIBS}" -@@ -40844,6 +40843,7 @@ fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $r_cv_have_pcre832" >&5 - $as_echo "$r_cv_have_pcre832" >&6; } - fi -+fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether PCRE support suffices" >&5 - $as_echo_n "checking whether PCRE support suffices... " >&6; } -diff --git a/m4/R.m4 b/m4/R.m4 -index fb35a5f..67cdd07 100644 ---- a/m4/R.m4 -+++ b/m4/R.m4 -@@ -3190,7 +3190,6 @@ int main() { - #endif - } - ]])], [r_cv_have_pcre820=yes], [r_cv_have_pcre820=no], [r_cv_have_pcre820=no])]) --fi - if test "x${r_cv_have_pcre820}" != xyes; then - have_pcre=no - LIBS="${r_save_LIBS}" -@@ -3213,6 +3212,7 @@ int main() { - } - ]])], [r_cv_have_pcre832=yes], [r_cv_have_pcre832=no], [r_cv_have_pcre832=no])]) - fi -+fi - - AC_MSG_CHECKING([whether PCRE support suffices]) - if test "x${r_cv_have_pcre820}" != xyes; then --- -2.16.1 - diff --git a/build/pkgs/r/patches/rcmd_exec.patch b/build/pkgs/r/patches/rcmd_exec.patch deleted file mode 100644 index f743e4791c5..00000000000 --- a/build/pkgs/r/patches/rcmd_exec.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 746b6908518c9725fece85270c587b5b110c08d3 Mon Sep 17 00:00:00 2001 -From: Emmanuel Charpentier -Date: Wed, 14 Mar 2018 19:30:37 +0100 -Subject: [PATCH 9/9] rcmd_exec - -On Cygwin some of the scripts in $R_HOME/bin can fail to be recognized -as executable, because they do no contain a shebang line and, depending -on the ACL settings in the Cygwin mount, may not have an executable flag -either. This results in the scripts not being run properly. It's fine -to just check that they exist. See https://trac.sagemath.org/ticket/20655 - ---- - src/scripts/Rcmd.in | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/src/scripts/Rcmd.in b/src/scripts/Rcmd.in -index 76d78d5..4b92483 100644 ---- a/src/scripts/Rcmd.in -+++ b/src/scripts/Rcmd.in -@@ -50,7 +50,7 @@ case "${1}" in - exit 1 - ;; - *) -- if test -x "${R_HOME}/bin/${1}"; then -+ if test -f "${R_HOME}/bin/${1}"; then - cmd="${R_HOME}/bin/${1}" - else - cmd="${1}" --- -2.16.1 - diff --git a/build/pkgs/r/spkg-check.in b/build/pkgs/r/spkg-check.in deleted file mode 100644 index 27cd9419538..00000000000 --- a/build/pkgs/r/spkg-check.in +++ /dev/null @@ -1,2 +0,0 @@ -cd src -$MAKE check diff --git a/build/pkgs/r/spkg-configure.m4 b/build/pkgs/r/spkg-configure.m4 index dafa9113ece..b31f6bef2ec 100644 --- a/build/pkgs/r/spkg-configure.m4 +++ b/build/pkgs/r/spkg-configure.m4 @@ -1,7 +1,7 @@ SAGE_SPKG_CONFIGURE([r], [ - m4_pushdef([SAGE_R_MINVER],["3.4.4"]) - SAGE_SPKG_DEPCHECK([openblas iconv readline bzip2 liblzma pcre curl], [ - AS_CASE([$host], + dnl https://rpy2.github.io/doc/v3.4.x/html/overview.html#requirements + m4_pushdef([SAGE_R_MINVER],["3.5"]) + AS_CASE([$host], [*-*-cygwin*], [ dnl #29486: rpy2 2.8.x does not build against system R on cygwin. sage_spkg_install_r=yes @@ -16,7 +16,6 @@ SAGE_SPKG_CONFIGURE([r], [ sage_spkg_install_r=no ]) ], [sage_spkg_install_r=yes]) - ]) ]) m4_popdef([SAGE_R_MINVER]) ]) diff --git a/build/pkgs/r/spkg-install.in b/build/pkgs/r/spkg-install.in deleted file mode 100644 index c63ff768f5b..00000000000 --- a/build/pkgs/r/spkg-install.in +++ /dev/null @@ -1,123 +0,0 @@ -# r uses grep output during its build -unset GREP_OPTIONS - -# Make sure CPPFLAGS and LDFLAGS are set to something (even the empty -# string) to prevent R from overriding them. Note: LDFLAGS is set by default. -# The --with-readline configure option only understands yes/no -# and cannot be used to pass this path. -CPPFLAGS="$CPPFLAGS" - -# #29170: Compilation errors caused by a silently failing configure check -# "for type of 'hidden' Fortran character lengths" -# on ubuntu-bionic-minimal, ubuntu-eoan/focal-minimal, debian-buster/bullseye/sid-minimal, -# linuxmint-19.3-minimal, archlinux-latest-minimal -CFLAGS="$CFLAGS_NON_NATIVE -fPIC" -FCFLAGS="$FCFLAGS_NON_NATIVE -fPIC" - -export CFLAGS CPPFLAGS FCFLAGS LDFLAGS - -if [ "$UNAME" = "Darwin" ]; then - # Put fake java on the PATH for OSX - export PATH="$(pwd)/bin:$PATH" -fi - -# Note by Karl-Dieter Crisman, April 12th 2010. X support would be nice -# to have in OSX, but see -# http://CRAN.R-project.org/bin/macosx/RMacOSX-FAQ.html#X11-window-server-_0028optional_0029 -# for how differently this would have to be handled on different OSX -# versions, none trivially. In any case, aqua, which we enable, -# performs the same function on OSX. -# -# Also, see #12172: for now, anyway, we disable X support on OS X. -# -# Note by David Kirkby, Feb 16th 2010. /usr/include/X11/Xwindows.h does -# not exist on Solaris, but R configures OK with X support. Hence I've added -# a more specific test on Solaris, by testing for a library. That library -# exists both on Solaris 10 03/2005 (SPARC) and on OpenSolaris. -if [ "$UNAME" = "Darwin" ]; then - XSUPPORT=no -elif [ -f /usr/include/X11/Xwindows.h ]; then - XSUPPORT=yes -elif [ "$UNAME" = "SunOS" ] && [ -f /usr/X11/lib/libXv.so ] ; then - XSUPPORT=yes -else - XSUPPORT=no -fi - -R_CONFIGURE_BLAS="--with-blas=$(pkg-config --libs blas)" -R_CONFIGURE_LAPACK="--with-lapack=$(pkg-config --libs lapack)" -echo "R_CONFIGURE_BLAS=$R_CONFIGURE_BLAS" -echo "R_CONFIGURE_LAPACK=$R_CONFIGURE_LAPACK" - -if [ "$UNAME" = "Darwin" ]; then - # We don't want to install R as a library framework on OSX - R_CONFIGURE="--enable-R-framework=no $R_CONFIGURE" - # OS X 10.10 and/or Xcode 6.3 and over broke the R installation. See - # http://trac.sagemath.org/ticket/18254. - if [ $MACOSX_VERSION -ge 14 ]; then - echo "OS X 10.$[$MACOSX_VERSION-4] Configuring R without aqua support." - R_CONFIGURE="--with-aqua=no $R_CONFIGURE" - fi - if [ $MACOSX_VERSION -ge 16 ]; then - echo "OS X 10.$[$MACOSX_VERSION-4] Building with clang." - CC=clang - fi -fi - -if [ "$SAGE_FAT_BINARY" = yes ]; then - echo "Disabling ICU, OpenMP for a binary build" - R_CONFIGURE="--without-ICU --disable-openmp $R_CONFIGURE" -elif [ "$UNAME" = "SunOS" ]; then - # Note by David Kirkby, 16th Feb 2010. Even after adding the iconv library - # R would not build properly on Solaris 10, complaining of undefined symbols - # uiter_setUTF8 and ucol_strcollIter - # After an email to r-help@r-project.org, Ei-ji Nakama (rim.nakama@gmail.com) - # emailed me and said the option --without-ICU might help, which it did. I don't see - # this option documented, but for now at least, it does allow R to build. - - echo "Disabling ICU on Solaris, using an undocumented option --without-ICU" - echo "since the ICU library is not included on Solaris." - R_CONFIGURE="--without-ICU $R_CONFIGURE" -fi - -cd src - -if [ "$UNAME" = "Darwin" ]; then - # Fixing install_name(s) - sed -i -e 's:\"-install_name :\"-install_name ${libdir}/R/lib/:' configure - sed -i -e "/SHLIB_EXT/s/\.so/.dylib/" configure -fi - -# Don't override R_HOME_DIR in local/bin/R while building R. -# See patches/R.sh.patch -export SAGE_BUILDING_R=yes - -R_HOME="$SAGE_LOCAL"/lib/R -# Set LDFLAGS as it is done in sage-env for $SAGE_LOCAL/lib -LDFLAGS="-L$R_HOME/lib -Wl,-rpath,$R_HOME/lib $LDFLAGS" -if [ "$UNAME" = "Linux" ]; then - LDFLAGS="-Wl,-rpath-link,$R_HOME/lib $LDFLAGS" -fi -export LDFLAGS - -config() { - sdh_configure --enable-R-shlib --with-recommended-packages \ - --with-readline=yes --with-x=$XSUPPORT \ - "$R_CONFIGURE_BLAS" "$R_CONFIGURE_LAPACK" \ - $R_CONFIGURE -} - -if ! (config); then - echo "Configuring R without X11" - export XSUPPORT=no - config -fi - -# Build R -sdh_make R - -# needed for help system -sdh_make vignettes - -# Install new version -sdh_make_install diff --git a/build/pkgs/r/spkg-src b/build/pkgs/r/spkg-src deleted file mode 100755 index 23ce98c4702..00000000000 --- a/build/pkgs/r/spkg-src +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash - -## What do we want ? -VERSION=$(cat package-version.txt | sed -re "s/^(.*)\\.p.+$/\\1/") -TARGET_TARBALL=r-$VERSION.tar.gz -SOURCE_TARBALL=R-$VERSION.tar.gz - -set -e - -wget http://cran.r-project.org/src/base/R-3/$SOURCE_TARBALL -mv $SOURCE_TARBALL $SAGE_ROOT/upstream/$TARGET_TARBALL - -sage --package fix-checksum diff --git a/build/pkgs/r/spkg-legacy-uninstall b/build/pkgs/r/spkg-uninstall similarity index 100% rename from build/pkgs/r/spkg-legacy-uninstall rename to build/pkgs/r/spkg-uninstall diff --git a/build/pkgs/r/type b/build/pkgs/r/type index a6a7b9cd726..134d9bc32d5 100644 --- a/build/pkgs/r/type +++ b/build/pkgs/r/type @@ -1 +1 @@ -standard +optional diff --git a/build/pkgs/rpy2/checksums.ini b/build/pkgs/rpy2/checksums.ini index 00cd4c4f123..ece539eec53 100644 --- a/build/pkgs/rpy2/checksums.ini +++ b/build/pkgs/rpy2/checksums.ini @@ -1,5 +1,5 @@ tarball=rpy2-VERSION.tar.gz -sha1=6436fc9bfc3118d6551c0e2a06d9ec2eb389c28a -md5=fd789967d3e46744cb1b2c4e55f47839 -cksum=906818309 +sha1=7d236c0c6982333b20b6a126f0c17a5481fea64b +md5=8842b153925a2eca21e2552e964facbb +cksum=1249008138 upstream_url=https://pypi.io/packages/source/r/rpy2/rpy2-VERSION.tar.gz diff --git a/build/pkgs/rpy2/install-requires.txt b/build/pkgs/rpy2/install-requires.txt index 7e5dc5f160a..769d7e61e92 100644 --- a/build/pkgs/rpy2/install-requires.txt +++ b/build/pkgs/rpy2/install-requires.txt @@ -1 +1 @@ -rpy2 >=3.3, <3.4 +rpy2 >=3.3 diff --git a/build/pkgs/rpy2/package-version.txt b/build/pkgs/rpy2/package-version.txt index 9c25013dbb8..4f5e69734c9 100644 --- a/build/pkgs/rpy2/package-version.txt +++ b/build/pkgs/rpy2/package-version.txt @@ -1 +1 @@ -3.3.6 +3.4.5 diff --git a/build/pkgs/rpy2/patches/716.patch b/build/pkgs/rpy2/patches/716.patch deleted file mode 100644 index 8446b281633..00000000000 --- a/build/pkgs/rpy2/patches/716.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 87d0f82e2f4be94893881913018ca9085c0ff8e5 Mon Sep 17 00:00:00 2001 -From: Matthias Koeppe -Date: Fri, 3 Jul 2020 12:47:41 -0700 -Subject: [PATCH] setup.py: Print CFFI configuration messages only on build - ---- - setup.py | 44 ++++++++++++++++++++++++++------------------ - 1 file changed, 26 insertions(+), 18 deletions(-) - -diff --git a/setup.py b/setup.py -index e4337838..7fead893 100755 ---- a/setup.py -+++ b/setup.py -@@ -21,6 +21,7 @@ - from rpy2 import situation - - from setuptools import setup -+from distutils.command.build import build as du_build - - PACKAGE_NAME = 'rpy2' - pack_version = __import__('rpy2').__version__ -@@ -111,7 +112,6 @@ def get_r_c_extension_status(): - - - cffi_mode = situation.get_cffi_mode() --print('cffi mode: %s' % cffi_mode) - c_extension_status = get_r_c_extension_status() - if cffi_mode == situation.CFFI_MODE.ABI: - cffi_modules = ['rpy2/_rinterface_cffi_build.py:ffibuilder_abi'] -@@ -135,6 +135,30 @@ def get_r_c_extension_status(): - # This should never happen. - raise ValueError('Invalid value for cffi_mode') - -+class build(du_build): -+ -+ def run(self): -+ print('cffi mode: %s' % cffi_mode) -+ -+ du_build.run(self) -+ -+ print('---') -+ print(cffi_mode) -+ if cffi_mode in (situation.CFFI_MODE.ABI, -+ situation.CFFI_MODE.BOTH, -+ situation.CFFI_MODE.ANY): -+ print('ABI mode interface built.') -+ if cffi_mode in (situation.CFFI_MODE.API, -+ situation.CFFI_MODE.BOTH): -+ print('API mode interface built.') -+ if cffi_mode == situation.CFFI_MODE.ANY: -+ if c_extension_status == COMPILATION_STATUS.OK: -+ print('API mode interface built.') -+ else: -+ print('API mode interface not built because: %s' % c_extension_status) -+ print('To change the API/ABI build mode, set or modify the environment ' -+ 'variable RPY2_CFFI_MODE.') -+ - LONG_DESCRIPTION = """ - Python interface to the R language. - -@@ -168,6 +192,7 @@ def get_r_c_extension_status(): - install_requires=requires + ['cffi>=1.10.0'], - setup_requires=['cffi>=1.10.0'], - cffi_modules=cffi_modules, -+ cmdclass = dict(build=build), - package_dir=pack_dir, - packages=([PACKAGE_NAME] + - ['{pack_name}.{x}'.format(pack_name=PACKAGE_NAME, x=x) -@@ -193,20 +218,3 @@ def get_r_c_extension_status(): - package_data={'rpy2': ['rinterface_lib/R_API.h', - 'rinterface_lib/R_API_eventloop.h']} - ) -- -- print('---') -- print(cffi_mode) -- if cffi_mode in (situation.CFFI_MODE.ABI, -- situation.CFFI_MODE.BOTH, -- situation.CFFI_MODE.ANY): -- print('ABI mode interface built and installed.') -- if cffi_mode in (situation.CFFI_MODE.API, -- situation.CFFI_MODE.BOTH): -- print('API mode interface built and installed.') -- if cffi_mode == situation.CFFI_MODE.ANY: -- if c_extension_status == COMPILATION_STATUS.OK: -- print('API mode interface built and installed.') -- else: -- print('API mode interface not build because: %s' % c_extension_status) -- print('To change the API/ABI build mode, set or modify the environment ' -- 'variable RPY2_CFFI_MODE.') diff --git a/build/pkgs/rpy2/patches/setup-no-pytest.patch b/build/pkgs/rpy2/patches/setup-no-pytest.patch deleted file mode 100644 index 91cb5127572..00000000000 --- a/build/pkgs/rpy2/patches/setup-no-pytest.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/setup.py b/setup.py -index a9f96f8..7ba69a1 100755 ---- a/setup.py -+++ b/setup.py -@@ -142,7 +142,7 @@ ipython. - if __name__ == '__main__': - pack_dir = {PACKAGE_NAME: os.path.join(package_prefix, 'rpy2')} - -- requires = ['pytest', 'jinja2', 'pytz', 'tzlocal'] -+ requires = ['jinja2', 'pytz', 'tzlocal'] - - setup( - name=PACKAGE_NAME, diff --git a/build/pkgs/rpy2/spkg-configure.m4 b/build/pkgs/rpy2/spkg-configure.m4 new file mode 100644 index 00000000000..c9831c6b60a --- /dev/null +++ b/build/pkgs/rpy2/spkg-configure.m4 @@ -0,0 +1,14 @@ +SAGE_SPKG_CONFIGURE([rpy2], [ + sage_spkg_install_rpy2=yes + ], [dnl REQUIRED-CHECK + AC_REQUIRE([SAGE_SPKG_CONFIGURE_R]) + dnl rpy2 is only needed when there is a usable system R + AS_VAR_IF([sage_spkg_install_r], [yes], [dnl + AS_VAR_IF([sage_use_system_r], [installed], [dnl + dnl Legacy SPKG installation of r + AS_VAR_SET([SPKG_REQUIRE], [yes]) + ], [dnl No system package, no legacy SPKG installation + AS_VAR_SET([SPKG_REQUIRE], [no]) + ]) + ]) +]) diff --git a/build/pkgs/sage_conf/install-requires.txt b/build/pkgs/sage_conf/install-requires.txt index 35a8993af20..e1ce4a85f34 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.8b3 diff --git a/build/pkgs/sage_conf/spkg-install b/build/pkgs/sage_conf/spkg-install index ee900be7164..a180fb36542 100755 --- a/build/pkgs/sage_conf/spkg-install +++ b/build/pkgs/sage_conf/spkg-install @@ -10,4 +10,11 @@ if [ $? -ne 0 ]; then exit 1 fi cd src -sdh_pip_install . +if [ "$SAGE_EDITABLE" = yes ]; then + sdh_pip_editable_install . + if [ "$SAGE_WHEELS" = yes ]; then + sdh_setup_bdist_wheel && sdh_store_wheel . + fi +else + sdh_pip_install . +fi diff --git a/build/pkgs/sage_docbuild/install-requires.txt b/build/pkgs/sage_docbuild/install-requires.txt index 002c6b79c65..3db13eeb1f7 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.8b3 diff --git a/build/pkgs/sage_docbuild/spkg-install b/build/pkgs/sage_docbuild/spkg-install index 1bb66bc4a07..cce58b40e22 100755 --- a/build/pkgs/sage_docbuild/spkg-install +++ b/build/pkgs/sage_docbuild/spkg-install @@ -12,6 +12,9 @@ fi cd src if [ "$SAGE_EDITABLE" = yes ]; then sdh_pip_editable_install . + if [ "$SAGE_WHEELS" = yes ]; then + sdh_setup_bdist_wheel && sdh_store_wheel . + fi else sdh_pip_install . fi diff --git a/build/pkgs/sage_setup/install-requires.txt b/build/pkgs/sage_setup/install-requires.txt index 5720bc8f2c5..d8a7c30eba0 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.8b3 diff --git a/build/pkgs/sage_setup/spkg-install b/build/pkgs/sage_setup/spkg-install index 77c1cc0e981..cce58b40e22 100755 --- a/build/pkgs/sage_setup/spkg-install +++ b/build/pkgs/sage_setup/spkg-install @@ -10,4 +10,11 @@ if [ $? -ne 0 ]; then exit 1 fi cd src -sdh_pip_install . +if [ "$SAGE_EDITABLE" = yes ]; then + sdh_pip_editable_install . + if [ "$SAGE_WHEELS" = yes ]; then + sdh_setup_bdist_wheel && sdh_store_wheel . + fi +else + sdh_pip_install . +fi diff --git a/build/pkgs/sage_sws2rst/install-requires.txt b/build/pkgs/sage_sws2rst/install-requires.txt index 70be4d731ee..95d6d392aa5 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.8b3 diff --git a/build/pkgs/sage_sws2rst/spkg-install b/build/pkgs/sage_sws2rst/spkg-install index 12d0d16dff1..47ef9ee6cbf 100755 --- a/build/pkgs/sage_sws2rst/spkg-install +++ b/build/pkgs/sage_sws2rst/spkg-install @@ -3,16 +3,21 @@ # For type=script packages, the build rule in build/make/Makefile sources # sage-env but not sage-dist-helpers. lib="$SAGE_ROOT/build/bin/sage-dist-helpers" -. "$lib" +source "$lib" if [ $? -ne 0 ]; then echo >&2 "Error: failed to source $lib" echo >&2 "Is $SAGE_ROOT the correct SAGE_ROOT?" exit 1 fi -set -e -# We build the wheel directly with "setup.py bdist_wheel", not with "pip wheel", -# because pip does not handle our symlinks correctly. -(cd src && sdh_setup_bdist_wheel && sdh_store_and_pip_install_wheel .) +cd src +if [ "$SAGE_EDITABLE" = yes ]; then + sdh_pip_editable_install . + if [ "$SAGE_WHEELS" = yes ]; then + sdh_setup_bdist_wheel && sdh_store_wheel . + fi +else + sdh_pip_install . +fi # For type=script packages, spkg-check is not run case "$SAGE_CHECK" in yes) diff --git a/build/pkgs/sagelib/install-requires.txt b/build/pkgs/sagelib/install-requires.txt index 359dff35670..3016d9eebcc 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.8b3 diff --git a/build/pkgs/sagelib/spkg-install b/build/pkgs/sagelib/spkg-install index 8d91b16b3f0..ad8b2ed43fc 100755 --- a/build/pkgs/sagelib/spkg-install +++ b/build/pkgs/sagelib/spkg-install @@ -1,4 +1,15 @@ #!/usr/bin/env bash +# From sage-spkg. +# For type=script packages, the build rule in build/make/Makefile sources +# sage-env but not sage-dist-helpers. +lib="$SAGE_ROOT/build/bin/sage-dist-helpers" +source "$lib" +if [ $? -ne 0 ]; then + echo >&2 "Error: failed to source $lib" + echo >&2 "Is $SAGE_ROOT the correct SAGE_ROOT?" + exit 1 +fi + if [ "$SAGE_EDITABLE" = yes ]; then cd "$SAGE_SRC" else @@ -27,8 +38,6 @@ export SAGE_SRC_ROOT=/doesnotexist export SAGE_DOC_SRC=/doesnotexist export SAGE_BUILD_DIR=/doesnotexist -export PYTHON="$SAGE_LOCAL/bin/python3" - # We also poison all directories below SAGE_LOCAL. export SAGE_PKGCONFIG=/doesnotexist export SAGE_SPKG_SCRIPTS=/doesnotexist @@ -51,15 +60,27 @@ if [ "$SAGE_EDITABLE" = yes ]; then # under the old distribution name "sage" (before #30912, which switched to setuptools # 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) - time python3 -m pip install --verbose --no-deps --no-index --no-build-isolation --isolated --editable . || exit 1 + (cd "$SITEPACKAGESDIR" && rm -rf sage sage-[1-9]*.egg-info sage-[1-9]*.dist-info) + time sdh_pip_editable_install . + + if [ "$SAGE_WHEELS" = yes ]; then + # Additionally build a wheel (for use in other venvs) + cd $SAGE_PKGS/sagelib/src && time sdh_setup_bdist_wheel && sdh_store_wheel . + fi else # Make sure that an installed old version of sagelib in which sage is an ordinary package # does not shadow the namespace package sage during the build. (cd "$SITEPACKAGESDIR" && rm -f sage/__init__.py) # Likewise, we should remove the egg-link that may have been installed previously. (cd "$SITEPACKAGESDIR" && rm -f sagemath-standard.egg-link) - time python3 -u setup.py --no-user-cfg build install || exit 1 + + if [ "$SAGE_WHEELS" = yes ]; then + # Use --no-build-isolation to avoid rebuilds because of dependencies: + # Compiling sage/interfaces/sagespawn.pyx because it depends on /private/var/folders/38/wnh4gf1552g_crsjnv2vmmww0000gp/T/pip-build-env-609n5985/overlay/lib/python3.10/site-packages/Cython/Includes/posix/unistd.pxd + time sdh_pip_install --no-build-isolation . + else + time python3 -u setup.py --no-user-cfg build install || exit 1 + fi fi # Trac #33103: The temp.* directories are large after a full build. 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..d1bce6cf96e 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.8b3 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..99458e3a96c 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.8b3 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..e0b880eaac0 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.8b3 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..3cd52abc7d6 --- /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.8b3 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_scm_git_archive/distros/conda.txt b/build/pkgs/setuptools_scm_git_archive/distros/conda.txt deleted file mode 100644 index 538474ff946..00000000000 --- a/build/pkgs/setuptools_scm_git_archive/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -setuptools-scm-git-archive 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/singular/spkg-configure.m4 b/build/pkgs/singular/spkg-configure.m4 index af2eb854143..d4d145defe3 100644 --- a/build/pkgs/singular/spkg-configure.m4 +++ b/build/pkgs/singular/spkg-configure.m4 @@ -7,7 +7,7 @@ SAGE_SPKG_CONFIGURE([singular], [ dnl Use pkg-config to ensure that Singular is new enough. PKG_CHECK_MODULES([SINGULAR], [Singular >= 4.2.1], [ AC_MSG_CHECKING([that Singular's help is working]) - AS_IF([test x`printf "system(\"--browser\", \"builtin\"); \n help;" | Singular 2>&1 | grep "error\ occurred"` = x], [ + AS_IF([test x`printf "system(\"--browser\", \"builtin\"); \n help;" | Singular 2>&1 | grep "error occurred"` = x], [ AC_MSG_RESULT(yes) dnl We have Singular. Now determine the shared library path on dnl platforms on which sage.libs.singular needs to reload the library with RTLD_GLOBAL. diff --git a/build/pkgs/sphinx/checksums.ini b/build/pkgs/sphinx/checksums.ini index 624ea28a1b1..99c08b0c2d5 100644 --- a/build/pkgs/sphinx/checksums.ini +++ b/build/pkgs/sphinx/checksums.ini @@ -1,5 +1,5 @@ tarball=Sphinx-VERSION.tar.gz -sha1=c0aa13911c331244877fc3947c0e7cec10d9e72b -md5=663e2f2ee9219ef4913831950825f68b -cksum=1902891868 +sha1=bef629b31b868d3b031050bd36653696f6b73d8e +md5=327ae7af29b3f08f059b52a4b9ed98cb +cksum=2569899835 upstream_url=https://pypi.io/packages/source/s/sphinx/Sphinx-VERSION.tar.gz diff --git a/build/pkgs/sphinx/install-requires.txt b/build/pkgs/sphinx/install-requires.txt index 9a8ff0bf429..16e1ac533d9 100644 --- a/build/pkgs/sphinx/install-requires.txt +++ b/build/pkgs/sphinx/install-requires.txt @@ -1 +1 @@ -sphinx >=4.3, <4.5 +sphinx >=5.2, <6 diff --git a/build/pkgs/sphinx/package-version.txt b/build/pkgs/sphinx/package-version.txt index fdc6698807a..c0baecbaaa9 100644 --- a/build/pkgs/sphinx/package-version.txt +++ b/build/pkgs/sphinx/package-version.txt @@ -1 +1 @@ -4.4.0 +5.2.3 diff --git a/build/pkgs/sphinxcontrib_websupport/checksums.ini b/build/pkgs/sphinxcontrib_websupport/checksums.ini index 5fd49b7e2ac..6291f2e8e03 100644 --- a/build/pkgs/sphinxcontrib_websupport/checksums.ini +++ b/build/pkgs/sphinxcontrib_websupport/checksums.ini @@ -1,5 +1,5 @@ tarball=sphinxcontrib-websupport-VERSION.tar.gz -sha1=313f4b764872d36f890e76579985e6aaa732f4ca -md5=4fe4d07afe1556c65182d0437228d7bb -cksum=1830011133 +sha1=39f6170825895ffeb0e06d52e351932b5f0c0147 +md5=eecfd8dc4933bd28c07ffb5e64fa2444 +cksum=431532871 upstream_url=https://pypi.io/packages/source/s/sphinxcontrib-websupport/sphinxcontrib-websupport-VERSION.tar.gz diff --git a/build/pkgs/sphinxcontrib_websupport/package-version.txt b/build/pkgs/sphinxcontrib_websupport/package-version.txt index 6085e946503..e8ea05db814 100644 --- a/build/pkgs/sphinxcontrib_websupport/package-version.txt +++ b/build/pkgs/sphinxcontrib_websupport/package-version.txt @@ -1 +1 @@ -1.2.1 +1.2.4 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/pkgs/topcom/checksums.ini b/build/pkgs/topcom/checksums.ini index 8c0bffb0731..764c422b5ac 100644 --- a/build/pkgs/topcom/checksums.ini +++ b/build/pkgs/topcom/checksums.ini @@ -1,4 +1,5 @@ -tarball=topcom-VERSION.tar.bz2 -sha1=e772365e7115289dfb1f75f28c335ec9d5feb0f1 -md5=117708cc3fdbb3368631c69e3cc95f1c -cksum=340369649 +tarball=TOPCOM-1_1_2.tgz +sha1=65db8c00309f3bf8467ee5ba9da109c196db3461 +md5=dbda1ae7946251c9502444ee9b0a2c62 +cksum=1598684291 +upstream_url=https://users.ox.ac.uk/~coml0531/tmp/TOPCOM-1_1_2.tgz diff --git a/build/pkgs/topcom/package-version.txt b/build/pkgs/topcom/package-version.txt index 793949533eb..45a1b3f4452 100644 --- a/build/pkgs/topcom/package-version.txt +++ b/build/pkgs/topcom/package-version.txt @@ -1 +1 @@ -0.17.7 +1.1.2 diff --git a/build/pkgs/topcom/patches/no_vendor_cddlib.patch b/build/pkgs/topcom/patches/no_vendor_cddlib.patch new file mode 100644 index 00000000000..b9e6c97a4ec --- /dev/null +++ b/build/pkgs/topcom/patches/no_vendor_cddlib.patch @@ -0,0 +1,2189 @@ +diff --git a/INSTALL b/INSTALL +index 9d4fccc..8865734 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -1,284 +1,368 @@ +-Remark concerning consistent 32 resp. 64 bit compilation +-======================================================== ++Installation Instructions ++************************* + +-The easiest way to guarantee consistent compilation is +-to configure with explicit setting of CFLAGS and CXXFLAGS +-to "-m32" or "-m64". This can be achieved by calling ++ Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software ++Foundation, Inc. + +- ./configure [other-configure-options-see-below] CFLAGS="-m64" CXXFLAGS="-m64" ++ Copying and distribution of this file, with or without modification, ++are permitted in any medium without royalty provided the copyright ++notice and this notice are preserved. This file is offered as-is, ++without warranty of any kind. + +-This way, all C/C++-Compilations are carried out with +-the corresponding compiler flag. +- +- +-Remark concerning external packages gmp, cdd, and qsopt_ex +-========================================================== +- +-If gmp, cddlib, or qsopt_ex are missing on your system then configure will +-build the version coming with TOPCOM in the `external' subdirectory +-of the TOPCOM root directory. +- +-If $(TOPCOM_DIRECTORY) is the root directory of the TOPCOM package, then +-the necessary files are installed into +- +- $(TOPCOM_DIRECTORY)/external/include +- $(TOPCOM_DIRECTORY)/external/lib ++Basic Installation ++================== + ++ Briefly, the shell command './configure && make && make install' ++should configure, build, and install this package. The following ++more-detailed instructions are generic; see the 'README' file for ++instructions specific to this package. Some packages provide this ++'INSTALL' file but do not implement all of the features documented ++below. The lack of an optional feature in a given package is not ++necessarily a bug. More recommendations for GNU packages can be found ++in *note Makefile Conventions: (standards)Makefile Conventions. + +-Remark concerning the pacakged cddlib LP solver library +-======================================================= ++ The 'configure' shell script attempts to guess correct values for ++various system-dependent variables used during compilation. It uses ++those values to create a 'Makefile' in each directory of the package. ++It may also create one or more '.h' files containing system-dependent ++definitions. Finally, it creates a shell script 'config.status' that ++you can run in the future to recreate the current configuration, and a ++file 'config.log' containing compiler output (useful mainly for ++debugging 'configure'). ++ ++ It can also use an optional file (typically called 'config.cache' and ++enabled with '--cache-file=config.cache' or simply '-C') that saves the ++results of its tests to speed up reconfiguring. Caching is disabled by ++default to prevent problems with accidental use of stale cache files. + +-The packaaged LP solver in cddlib is not thread-safe out of the box. +-Therefore, the version packaged with TOPCOM has been patched to version +-0.94j-TOPCOM. This patched version will be compiled with C++ and +-has thread_local global variables. This is enough to make cddlib +-threadsafe, thus, parallel enumeration can be used. ++ If you need to do unusual things to compile the package, please try ++to figure out how 'configure' could check whether to do them, and mail ++diffs or instructions to the address given in the 'README' so they can ++be considered for the next release. If you are using the cache, and at ++some point 'config.cache' contains results you don't want to keep, you ++may remove or edit it. ++ ++ The file 'configure.ac' (or 'configure.in') is used to create ++'configure' by a program called 'autoconf'. You need 'configure.ac' if ++you want to change it or regenerate 'configure' using a newer version of ++'autoconf'. ++ ++ The simplest way to compile this package is: ++ ++ 1. 'cd' to the directory containing the package's source code and type ++ './configure' to configure the package for your system. ++ ++ Running 'configure' might take a while. While running, it prints ++ some messages telling which features it is checking for. ++ ++ 2. Type 'make' to compile the package. ++ ++ 3. Optionally, type 'make check' to run any self-tests that come with ++ the package, generally using the just-built uninstalled binaries. ++ ++ 4. Type 'make install' to install the programs and any data files and ++ documentation. When installing into a prefix owned by root, it is ++ recommended that the package be configured and built as a regular ++ user, and only the 'make install' phase executed with root ++ privileges. ++ ++ 5. Optionally, type 'make installcheck' to repeat any self-tests, but ++ this time using the binaries in their final installed location. ++ This target does not install anything. Running this target as a ++ regular user, particularly if the prior 'make install' required ++ root privileges, verifies that the installation completed ++ correctly. ++ ++ 6. You can remove the program binaries and object files from the ++ source code directory by typing 'make clean'. To also remove the ++ files that 'configure' created (so you can compile the package for ++ a different kind of computer), type 'make distclean'. There is ++ also a 'make maintainer-clean' target, but that is intended mainly ++ for the package's developers. If you use it, you may have to get ++ all sorts of other programs in order to regenerate files that came ++ with the distribution. + ++ 7. Often, you can also type 'make uninstall' to remove the installed ++ files again. In practice, not all packages have tested that ++ uninstallation works correctly, even though it is required by the ++ GNU Coding Standards. + +-Remark concerning the pacakged qsopt_ex LP solver library +-========================================================= ++ 8. Some packages, particularly those that use Automake, provide 'make ++ distcheck', which can by used by developers to test that all other ++ targets like 'make install' and 'make uninstall' work correctly. ++ This target is generally not run by end users. + +-Configuring with option ++Compilers and Options ++===================== + +- ./configure --enable-qsoptex ++ Some systems require unusual options for compilation or linking that ++the 'configure' script does not know about. Run './configure --help' ++for details on some of the pertinent environment variables. + +-compiles a binary with QSOpt_ex support. ++ You can give 'configure' initial values for configuration parameters ++by setting variables in the command line or in the environment. Here is ++an example: + +-The packaaged LP solver QSOpt_ex is very fast but not threadsafe. +-Therefore, if you use it (option --qsoptex), then no parallel enumeration +-will be carried out. Still, the internal memory managament +-of qsopt_ex may core-dump at the very end of the run. +-I have no idea why. This all happens after the TOPCOM computations +-have finished. So, the results should be ok anyway. ++ ./configure CC=c99 CFLAGS=-g LIBS=-lposix + ++ *Note Defining Variables::, for more details. + +-Remark concerning the soplex LP solver library (versions >= 6.0.0) +-================================================================== ++Compiling For Multiple Architectures ++==================================== + +-The academic licence of soplex does not allow a common delivery within +-the TOPCOM package. Therefore, if you want to use soplex you must +-install it in a place where it can be found by the compiler and +-the linker. This is slightly tedious but rewarding, since +-soplex is faster than cddlib. ++ You can compile the package for more than one kind of computer at the ++same time, by placing the object files for each architecture in their ++own directory. To do this, you can use GNU 'make'. 'cd' to the ++directory where you want the object files and executables to go and run ++the 'configure' script. 'configure' automatically checks for the source ++code in the directory that 'configure' is in and in '..'. This is known ++as a "VPATH" build. ++ ++ With a non-GNU 'make', it is safer to compile the package for one ++architecture at a time in the source code directory. After you have ++installed the package for one architecture, use 'make distclean' before ++reconfiguring for another architecture. ++ ++ On MacOS X 10.5 and later systems, you can create libraries and ++executables that work on multiple system types--known as "fat" or ++"universal" binaries--by specifying multiple '-arch' options to the ++compiler but only a single '-arch' option to the preprocessor. Like ++this: + +-Using soplex requires libsoplex.a in ${TOPCOM_DIRECTORY}/external/lib and +-all the soplex includes in ${TOPCOM_DIRECTORY}/external/include. +-As 6.0.0 of soplex, the boost includes are required in the same place. +-This changed, e.g., the access to the underlying gmp rationals. +-Therefore, versions of soplex prior to 6.0.0 are not supported out +-of the box. ++ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ ++ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ ++ CPP="gcc -E" CXXCPP="g++ -E" + +-In order to use soplex, I recommend to place symbolic links in +-${TOPCOM_DIRECTORY}/external/lib to the libraries and all the soplex includes +-in ${TOPCOM_DIRECTORY}/external/include. +-(This method supports that non-superusers can install TOPCOM locally +-without the help of a system-administrator.) ++ This is not guaranteed to produce working output in all cases, you ++may have to build one architecture at a time and combine the results ++using the 'lipo' tool if you have problems. + +-Summarized, if you have the includes and the libs of soplex 6.0.0 +-or later below ${SOPLEX_INCLUDES_DIR} and ${SOPLEX_LIBS_DIR}, resp., +-and boost below ${BOOST_INCLUDES_DIR}, then you can start with ++Installation Names ++================== + +- ./configure --enable-soplex ++ By default, 'make install' installs the package's commands under ++'/usr/local/bin', include files under '/usr/local/include', etc. You ++can specify an installation prefix other than '/usr/local' by giving ++'configure' the option '--prefix=PREFIX', where PREFIX must be an ++absolute file name. + +-to activate the soplex support in TOPCOM. Then you can place +-the symbolic links by ++ You can specify separate installation prefixes for ++architecture-specific files and architecture-independent files. If you ++pass the option '--exec-prefix=PREFIX' to 'configure', the package uses ++PREFIX as the prefix for installing programs and libraries. ++Documentation and other data files still use the regular prefix. + +- cd ${TOPCOM_DIRECTORY}/external/ +- cd include +- ln -s ${SOPLEX_INCLUDES_DIR}/soplex* . +- ln -s ${BOOST_INCLUDES_DIR}/boost . +- cd ../lib +- ln -s ${SOPLEX_LIBS_DIR}/libsoplex*.a . +- cd ../.. ++ In addition, if you use an unusual directory layout you can give ++options like '--bindir=DIR' to specify different values for particular ++kinds of files. Run 'configure --help' for a list of the directories ++you can set and what kinds of files go in them. In general, the default ++for these options is expressed in terms of '${prefix}', so that ++specifying just '--prefix' will affect all of the other directory ++specifications that were not explicitly provided. ++ ++ The most portable way to affect installation locations is to pass the ++correct locations to 'configure'; however, many packages provide one or ++both of the following shortcuts of passing variable assignments to the ++'make install' command line to change installation locations without ++having to reconfigure or recompile. ++ ++ The first method involves providing an override variable for each ++affected directory. For example, 'make install ++prefix=/alternate/directory' will choose an alternate location for all ++directory configuration variables that were expressed in terms of ++'${prefix}'. Any directories that were specified during 'configure', ++but not in terms of '${prefix}', must each be overridden at install time ++for the entire installation to be relocated. The approach of makefile ++variable overrides for each directory variable is required by the GNU ++Coding Standards, and ideally causes no recompilation. However, some ++platforms have known limitations with the semantics of shared libraries ++that end up requiring recompilation when using this method, particularly ++noticeable in packages that use GNU Libtool. ++ ++ The second method involves providing the 'DESTDIR' variable. For ++example, 'make install DESTDIR=/alternate/directory' will prepend ++'/alternate/directory' before all installation names. The approach of ++'DESTDIR' overrides is not required by the GNU Coding Standards, and ++does not work on platforms that have drive letters. On the other hand, ++it does better at avoiding recompilation issues, and works well even ++when some directory options were not specified in terms of '${prefix}' ++at 'configure' time. + +-to link the includes and libraries to the right place where TOPCOM can +-find them. Finally, just ++Optional Features ++================= + +- make +- make install ++ If the package supports it, you can cause programs to be installed ++with an extra prefix or suffix on their names by giving 'configure' the ++option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'. ++ ++ Some packages pay attention to '--enable-FEATURE' options to ++'configure', where FEATURE indicates an optional part of the package. ++They may also pay attention to '--with-PACKAGE' options, where PACKAGE ++is something like 'gnu-as' or 'x' (for the X Window System). The ++'README' should mention any '--enable-' and '--with-' options that the ++package recognizes. + +-and you are set. ++ For packages that use the X Window System, 'configure' can usually ++find the X include and library files automatically, but if it doesn't, ++you can use the 'configure' options '--x-includes=DIR' and ++'--x-libraries=DIR' to specify their locations. + ++ Some packages offer the ability to configure how verbose the ++execution of 'make' will be. For these packages, running './configure ++--enable-silent-rules' sets the default to minimal output, which can be ++overridden with 'make V=1'; while running './configure ++--disable-silent-rules' sets the default to verbose, which can be ++overridden with 'make V=0'. + +-Basic Installation ++Particular systems + ================== + +- These are generic installation instructions. ++ On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC ++is not installed, it is recommended to use the following options in ++order to use an ANSI C compiler: + +- The `configure' shell script attempts to guess correct values for +-various system-dependent variables used during compilation. It uses +-those values to create a `Makefile' in each directory of the package. +-It may also create one or more `.h' files containing system-dependent +-definitions. Finally, it creates a shell script `config.status' that +-you can run in the future to recreate the current configuration, a file +-`config.cache' that saves the results of its tests to speed up +-reconfiguring, and a file `config.log' containing compiler output +-(useful mainly for debugging `configure'). ++ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +- If you need to do unusual things to compile the package, please try +-to figure out how `configure' could check whether to do them, and mail +-diffs or instructions to the address given in the `README' so they can +-be considered for the next release. If at some point `config.cache' +-contains results you don't want to keep, you may remove or edit it. ++and if that doesn't work, install pre-built binaries of GCC for HP-UX. + +- The file `configure.in' is used to create `configure' by a program +-called `autoconf'. You only need `configure.in' if you want to change +-it or regenerate `configure' using a newer version of `autoconf'. ++ HP-UX 'make' updates targets which have the same time stamps as their ++prerequisites, which makes it generally unusable when shipped generated ++files such as 'configure' are involved. Use GNU 'make' instead. + +-The simplest way to compile this package is: ++ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot ++parse its '' header file. The option '-nodtk' can be used as a ++workaround. If GNU CC is not installed, it is therefore recommended to ++try + +- 1. `cd' to the directory containing the package's source code and type +- `./configure' to configure the package for your system. If you're +- using `csh' on an old version of System V, you might need to type +- `sh ./configure' instead to prevent `csh' from trying to execute +- `configure' itself. ++ ./configure CC="cc" + +- Running `configure' takes awhile. While running, it prints some +- messages telling which features it is checking for. ++and if that doesn't work, try + +- 2. Type `make' to compile the package. ++ ./configure CC="cc -nodtk" + +- 3. Optionally, type `make check' to run any self-tests that come with +- the package. ++ On Solaris, don't put '/usr/ucb' early in your 'PATH'. This ++directory contains several dysfunctional programs; working variants of ++these programs are available in '/usr/bin'. So, if you need '/usr/ucb' ++in your 'PATH', put it _after_ '/usr/bin'. + +- 4. Type `make install' to install the programs and any data files and +- documentation. ++ On Haiku, software installed for all users goes in '/boot/common', ++not '/usr/local'. It is recommended to use the following options: + +- 5. You can remove the program binaries and object files from the +- source code directory by typing `make clean'. To also remove the +- files that `configure' created (so you can compile the package for +- a different kind of computer), type `make distclean'. There is +- also a `make maintainer-clean' target, but that is intended mainly +- for the package's developers. If you use it, you may have to get +- all sorts of other programs in order to regenerate files that came +- with the distribution. ++ ./configure --prefix=/boot/common + +-Compilers and Options +-===================== +- +- Some systems require unusual options for compilation or linking that +-the `configure' script does not know about. You can give `configure' +-initial values for variables by setting them in the environment. Using +-a Bourne-compatible shell, you can do that on the command line like +-this: +- CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure ++Specifying the System Type ++========================== + +-Or on systems that have the `env' program, you can do it like this: +- env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure ++ There may be some features 'configure' cannot figure out ++automatically, but needs to determine by the type of machine the package ++will run on. Usually, assuming the package is built to be run on the ++_same_ architectures, 'configure' can figure that out, but if it prints ++a message saying it cannot guess the machine type, give it the ++'--build=TYPE' option. TYPE can either be a short name for the system ++type, such as 'sun4', or a canonical name which has the form: + +-Compiling For Multiple Architectures +-==================================== ++ CPU-COMPANY-SYSTEM + +- You can compile the package for more than one kind of computer at the +-same time, by placing the object files for each architecture in their +-own directory. To do this, you must use a version of `make' that +-supports the `VPATH' variable, such as GNU `make'. `cd' to the +-directory where you want the object files and executables to go and run +-the `configure' script. `configure' automatically checks for the +-source code in the directory that `configure' is in and in `..'. ++where SYSTEM can have one of these forms: + +- If you have to use a `make' that does not supports the `VPATH' +-variable, you have to compile the package for one architecture at a time +-in the source code directory. After you have installed the package for +-one architecture, use `make distclean' before reconfiguring for another +-architecture. ++ OS ++ KERNEL-OS + +-Installation Names +-================== ++ See the file 'config.sub' for the possible values of each field. If ++'config.sub' isn't included in this package, then this package doesn't ++need to know the machine type. + +- By default, `make install' will install the package's files in +-`/usr/local/bin', `/usr/local/man', etc. You can specify an +-installation prefix other than `/usr/local' by giving `configure' the +-option `--prefix=PATH'. ++ If you are _building_ compiler tools for cross-compiling, you should ++use the option '--target=TYPE' to select the type of system they will ++produce code for. + +- You can specify separate installation prefixes for +-architecture-specific files and architecture-independent files. If you +-give `configure' the option `--exec-prefix=PATH', the package will use +-PATH as the prefix for installing programs and libraries. +-Documentation and other data files will still use the regular prefix. ++ If you want to _use_ a cross compiler, that generates code for a ++platform different from the build platform, you should specify the ++"host" platform (i.e., that on which the generated programs will ++eventually be run) with '--host=TYPE'. + +- In addition, if you use an unusual directory layout you can give +-options like `--bindir=PATH' to specify different values for particular +-kinds of files. Run `configure --help' for a list of the directories +-you can set and what kinds of files go in them. ++Sharing Defaults ++================ + +- If the package supports it, you can cause programs to be installed +-with an extra prefix or suffix on their names by giving `configure' the +-option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. ++ If you want to set default values for 'configure' scripts to share, ++you can create a site shell script called 'config.site' that gives ++default values for variables like 'CC', 'cache_file', and 'prefix'. ++'configure' looks for 'PREFIX/share/config.site' if it exists, then ++'PREFIX/etc/config.site' if it exists. Or, you can set the ++'CONFIG_SITE' environment variable to the location of the site script. ++A warning: not all 'configure' scripts look for a site script. + +-Optional Features +-================= ++Defining Variables ++================== + +- Some packages pay attention to `--enable-FEATURE' options to +-`configure', where FEATURE indicates an optional part of the package. +-They may also pay attention to `--with-PACKAGE' options, where PACKAGE +-is something like `gnu-as' or `x' (for the X Window System). The +-`README' should mention any `--enable-' and `--with-' options that the +-package recognizes. ++ Variables not defined in a site shell script can be set in the ++environment passed to 'configure'. However, some packages may run ++configure again during the build, and the customized values of these ++variables may be lost. In order to avoid this problem, you should set ++them in the 'configure' command line, using 'VAR=value'. For example: + +- For packages that use the X Window System, `configure' can usually +-find the X include and library files automatically, but if it doesn't, +-you can use the `configure' options `--x-includes=DIR' and +-`--x-libraries=DIR' to specify their locations. ++ ./configure CC=/usr/local2/bin/gcc + +-Specifying the System Type +-========================== ++causes the specified 'gcc' to be used as the C compiler (unless it is ++overridden in the site shell script). + +- There may be some features `configure' can not figure out +-automatically, but needs to determine by the type of host the package +-will run on. Usually `configure' can figure that out, but if it prints +-a message saying it can not guess the host type, give it the +-`--host=TYPE' option. TYPE can either be a short name for the system +-type, such as `sun4', or a canonical name with three fields: +- CPU-COMPANY-SYSTEM ++Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an ++Autoconf limitation. Until the limitation is lifted, you can use this ++workaround: + +-See the file `config.sub' for the possible values of each field. If +-`config.sub' isn't included in this package, then this package doesn't +-need to know the host type. ++ CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash + +- If you are building compiler tools for cross-compiling, you can also +-use the `--target=TYPE' option to select the type of system they will +-produce code for and the `--build=TYPE' option to select the type of +-system on which you are compiling the package. ++'configure' Invocation ++====================== + +-Sharing Defaults +-================ ++ 'configure' recognizes the following options to control how it ++operates. + +- If you want to set default values for `configure' scripts to share, +-you can create a site shell script called `config.site' that gives +-default values for variables like `CC', `cache_file', and `prefix'. +-`configure' looks for `PREFIX/share/config.site' if it exists, then +-`PREFIX/etc/config.site' if it exists. Or, you can set the +-`CONFIG_SITE' environment variable to the location of the site script. +-A warning: not all `configure' scripts look for a site script. ++'--help' ++'-h' ++ Print a summary of all of the options to 'configure', and exit. + +-Operation Controls +-================== ++'--help=short' ++'--help=recursive' ++ Print a summary of the options unique to this package's ++ 'configure', and exit. The 'short' variant lists options used only ++ in the top level, while the 'recursive' variant lists options also ++ present in any nested packages. + +- `configure' recognizes the following options to control how it +-operates. ++'--version' ++'-V' ++ Print the version of Autoconf used to generate the 'configure' ++ script, and exit. + +-`--cache-file=FILE' +- Use and save the results of the tests in FILE instead of +- `./config.cache'. Set FILE to `/dev/null' to disable caching, for +- debugging `configure'. ++'--cache-file=FILE' ++ Enable the cache: use and save the results of the tests in FILE, ++ traditionally 'config.cache'. FILE defaults to '/dev/null' to ++ disable caching. + +-`--help' +- Print a summary of the options to `configure', and exit. ++'--config-cache' ++'-C' ++ Alias for '--cache-file=config.cache'. + +-`--quiet' +-`--silent' +-`-q' ++'--quiet' ++'--silent' ++'-q' + Do not print messages saying which checks are being made. To +- suppress all normal output, redirect it to `/dev/null' (any error ++ suppress all normal output, redirect it to '/dev/null' (any error + messages will still be shown). + +-`--srcdir=DIR' ++'--srcdir=DIR' + Look for the package's source code in directory DIR. Usually +- `configure' can determine that directory automatically. ++ 'configure' can determine that directory automatically. + +-`--version' +- Print the version of Autoconf used to generate the `configure' +- script, and exit. ++'--prefix=DIR' ++ Use DIR as the installation prefix. *note Installation Names:: for ++ more details, including other options available for fine-tuning the ++ installation locations. ++ ++'--no-create' ++'-n' ++ Run the configure checks, but stop before creating any output ++ files. + +-`configure' also accepts some other, not widely useful, options. ++'configure' also accepts some other, not widely useful, options. Run ++'configure --help' for more details. +diff --git a/Makefile.am b/Makefile.am +index 17f6960..992689e 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -1,7 +1,5 @@ + SUBDIRS = wrap-gmp-gmpxx lib-src-reg lib-src src-reg src examples share + EXTRA_DIST = external/Makefile +-EXTRA_DIST += external/gmp-6.2.1.tar.bz2 +-EXTRA_DIST += external/cddlib-0.94j-TOPCOMb.tar.gz + EXTRA_DIST += external/qsopt_ex-2.5.10.3.tar.gz + EXTRA_DIST += external/gmpxx-patch + +diff --git a/Makefile.in b/Makefile.in +index b9902f5..93002b8 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -1,7 +1,7 @@ +-# Makefile.in generated by automake 1.16.1 from Makefile.am. ++# Makefile.in generated by automake 1.16.2 from Makefile.am. + # @configure_input@ + +-# Copyright (C) 1994-2018 Free Software Foundation, Inc. ++# Copyright (C) 1994-2020 Free Software Foundation, Inc. + + # This Makefile.in is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -211,6 +211,7 @@ AWK = @AWK@ + CC = @CC@ + CCDEPMODE = @CCDEPMODE@ + CFLAGS = @CFLAGS@ ++CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CXX = @CXX@ + CXXCPP = @CXXCPP@ +@@ -286,6 +287,7 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ ++runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +@@ -295,9 +297,8 @@ top_build_prefix = @top_build_prefix@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ + SUBDIRS = wrap-gmp-gmpxx lib-src-reg lib-src src-reg src examples share +-EXTRA_DIST = external/Makefile external/gmp-6.2.1.tar.bz2 \ +- external/cddlib-0.94j-TOPCOMb.tar.gz \ +- external/qsopt_ex-2.5.10.3.tar.gz external/gmpxx-patch ++EXTRA_DIST = external/Makefile external/qsopt_ex-2.5.10.3.tar.gz \ ++ external/gmpxx-patch + all: all-recursive + + .SUFFIXES: +@@ -524,6 +525,10 @@ dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__post_remove_distdir) + ++dist-zstd: distdir ++ tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst ++ $(am__post_remove_distdir) ++ + dist-tarZ: distdir + @echo WARNING: "Support for distribution archives compressed with" \ + "legacy program 'compress' is deprecated." >&2 +@@ -566,6 +571,8 @@ distcheck: dist + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ ++ *.tar.zst*) \ ++ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ + esac + chmod -R a-w $(distdir) + chmod u+w $(distdir) +@@ -742,7 +749,7 @@ uninstall-am: + am--refresh check check-am clean clean-cscope clean-generic \ + cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ + dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ +- distcheck distclean distclean-generic distclean-tags \ ++ dist-zstd distcheck distclean distclean-generic distclean-tags \ + distcleancheck distdir distuninstallcheck dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ +diff --git a/aclocal.m4 b/aclocal.m4 +index 8c6b78f..e4b15fc 100644 +--- a/aclocal.m4 ++++ b/aclocal.m4 +@@ -1,6 +1,6 @@ +-# generated automatically by aclocal 1.16.1 -*- Autoconf -*- ++# generated automatically by aclocal 1.16.2 -*- Autoconf -*- + +-# Copyright (C) 1996-2018 Free Software Foundation, Inc. ++# Copyright (C) 1996-2020 Free Software Foundation, Inc. + + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -20,7 +20,7 @@ You have another version of autoconf. It may work, but is not guaranteed to. + If you have problems, you may need to regenerate the build system entirely. + To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +-# Copyright (C) 2002-2018 Free Software Foundation, Inc. ++# Copyright (C) 2002-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -35,7 +35,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], + [am__api_version='1.16' + dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to + dnl require some minimum version. Point them to the right macro. +-m4_if([$1], [1.16.1], [], ++m4_if([$1], [1.16.2], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl + ]) + +@@ -51,14 +51,14 @@ m4_define([_AM_AUTOCONF_VERSION], []) + # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. + # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. + AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +-[AM_AUTOMAKE_VERSION([1.16.1])dnl ++[AM_AUTOMAKE_VERSION([1.16.2])dnl + m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl + _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + + # AM_AUX_DIR_EXPAND -*- Autoconf -*- + +-# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# Copyright (C) 2001-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -110,7 +110,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` + + # AM_CONDITIONAL -*- Autoconf -*- + +-# Copyright (C) 1997-2018 Free Software Foundation, Inc. ++# Copyright (C) 1997-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -141,7 +141,7 @@ AC_CONFIG_COMMANDS_PRE( + Usually this means the macro was only invoked conditionally.]]) + fi])]) + +-# Copyright (C) 1999-2018 Free Software Foundation, Inc. ++# Copyright (C) 1999-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -332,7 +332,7 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl + + # Generate code to set up dependency tracking. -*- Autoconf -*- + +-# Copyright (C) 1999-2018 Free Software Foundation, Inc. ++# Copyright (C) 1999-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -371,7 +371,9 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], + done + if test $am_rc -ne 0; then + AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments +- for automatic dependency tracking. Try re-running configure with the ++ for automatic dependency tracking. If GNU make was not used, consider ++ re-running the configure script with MAKE="gmake" (or whatever is ++ necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking).]) + fi +@@ -398,7 +400,7 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], + + # Do all the work for Automake. -*- Autoconf -*- + +-# Copyright (C) 1996-2018 Free Software Foundation, Inc. ++# Copyright (C) 1996-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -595,7 +597,7 @@ for _am_header in $config_headers :; do + done + echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +-# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# Copyright (C) 2001-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -616,7 +618,7 @@ if test x"${install_sh+set}" != xset; then + fi + AC_SUBST([install_sh])]) + +-# Copyright (C) 2003-2018 Free Software Foundation, Inc. ++# Copyright (C) 2003-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -637,7 +639,7 @@ AC_SUBST([am__leading_dot])]) + + # Check to see how 'make' treats includes. -*- Autoconf -*- + +-# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# Copyright (C) 2001-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -680,7 +682,7 @@ AC_SUBST([am__quote])]) + + # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +-# Copyright (C) 1997-2018 Free Software Foundation, Inc. ++# Copyright (C) 1997-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -719,7 +721,7 @@ fi + + # Helper functions for option handling. -*- Autoconf -*- + +-# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# Copyright (C) 2001-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -748,7 +750,7 @@ AC_DEFUN([_AM_SET_OPTIONS], + AC_DEFUN([_AM_IF_OPTION], + [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +-# Copyright (C) 1999-2018 Free Software Foundation, Inc. ++# Copyright (C) 1999-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -795,7 +797,7 @@ AC_LANG_POP([C])]) + # For backward compatibility. + AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) + +-# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# Copyright (C) 2001-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -814,7 +816,7 @@ AC_DEFUN([AM_RUN_LOG], + + # Check to make sure that the build environment is sane. -*- Autoconf -*- + +-# Copyright (C) 1996-2018 Free Software Foundation, Inc. ++# Copyright (C) 1996-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -895,7 +897,7 @@ AC_CONFIG_COMMANDS_PRE( + rm -f conftest.file + ]) + +-# Copyright (C) 2009-2018 Free Software Foundation, Inc. ++# Copyright (C) 2009-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -955,7 +957,7 @@ AC_SUBST([AM_BACKSLASH])dnl + _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl + ]) + +-# Copyright (C) 2001-2018 Free Software Foundation, Inc. ++# Copyright (C) 2001-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -983,7 +985,7 @@ fi + INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +-# Copyright (C) 2006-2018 Free Software Foundation, Inc. ++# Copyright (C) 2006-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -1002,7 +1004,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + + # Check how to create a tarball. -*- Autoconf -*- + +-# Copyright (C) 2004-2018 Free Software Foundation, Inc. ++# Copyright (C) 2004-2020 Free Software Foundation, Inc. + # + # This file is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +diff --git a/compile b/compile +index 99e5052..23fcba0 100755 +--- a/compile ++++ b/compile +@@ -3,7 +3,7 @@ + + scriptversion=2018-03-07.03; # UTC + +-# Copyright (C) 1999-2018 Free Software Foundation, Inc. ++# Copyright (C) 1999-2020 Free Software Foundation, Inc. + # Written by Tom Tromey . + # + # This program is free software; you can redistribute it and/or modify +@@ -53,7 +53,7 @@ func_file_conv () + MINGW*) + file_conv=mingw + ;; +- CYGWIN*) ++ CYGWIN* | MSYS*) + file_conv=cygwin + ;; + *) +@@ -67,7 +67,7 @@ func_file_conv () + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; +- cygwin/*) ++ cygwin/* | msys/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) +diff --git a/configure b/configure +index 7aebaca..6afa3b8 100755 +--- a/configure ++++ b/configure +@@ -627,6 +627,7 @@ USE_SOPLEX_FALSE + USE_SOPLEX_TRUE + USE_QSOPTEX_FALSE + USE_QSOPTEX_TRUE ++CPP + USE_LOCAL_GMP_FALSE + USE_LOCAL_GMP_TRUE + EGREP +@@ -705,6 +706,7 @@ infodir + docdir + oldincludedir + includedir ++runstatedir + localstatedir + sharedstatedir + sysconfdir +@@ -744,7 +746,8 @@ CPPFLAGS + CXX + CXXFLAGS + CCC +-CXXCPP' ++CXXCPP ++CPP' + + + # Initialize some variables set by options. +@@ -783,6 +786,7 @@ datadir='${datarootdir}' + sysconfdir='${prefix}/etc' + sharedstatedir='${prefix}/com' + localstatedir='${prefix}/var' ++runstatedir='${localstatedir}/run' + includedir='${prefix}/include' + oldincludedir='/usr/include' + docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +@@ -1035,6 +1039,15 @@ do + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + ++ -runstatedir | --runstatedir | --runstatedi | --runstated \ ++ | --runstate | --runstat | --runsta | --runst | --runs \ ++ | --run | --ru | --r) ++ ac_prev=runstatedir ;; ++ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ ++ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ ++ | --run=* | --ru=* | --r=*) ++ runstatedir=$ac_optarg ;; ++ + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ +@@ -1172,7 +1185,7 @@ fi + for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ +- libdir localedir mandir ++ libdir localedir mandir runstatedir + do + eval ac_val=\$$ac_var + # Remove trailing slashes. +@@ -1325,6 +1338,7 @@ Fine tuning of the installation directories: + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] ++ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] +@@ -1388,6 +1402,7 @@ Some influential environment variables: + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor ++ CPP C preprocessor + + Use these variables to override the choices made by `configure' or to help + it to find libraries and programs with nonstandard names/locations. +@@ -1742,6 +1757,130 @@ $as_echo "$ac_res" >&6; } + + } # ac_fn_cxx_check_header_compile + ++# ac_fn_c_try_cpp LINENO ++# ---------------------- ++# Try to preprocess conftest.$ac_ext, and return whether this succeeded. ++ac_fn_c_try_cpp () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ if { { ac_try="$ac_cpp conftest.$ac_ext" ++case "(($ac_try" in ++ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; ++ *) ac_try_echo=$ac_try;; ++esac ++eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" ++$as_echo "$ac_try_echo"; } >&5 ++ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ++ ac_status=$? ++ if test -s conftest.err; then ++ grep -v '^ *+' conftest.err >conftest.er1 ++ cat conftest.er1 >&5 ++ mv -f conftest.er1 conftest.err ++ fi ++ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; } > conftest.i && { ++ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || ++ test ! -s conftest.err ++ }; then : ++ ac_retval=0 ++else ++ $as_echo "$as_me: failed program was:" >&5 ++sed 's/^/| /' conftest.$ac_ext >&5 ++ ++ ac_retval=1 ++fi ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ as_fn_set_status $ac_retval ++ ++} # ac_fn_c_try_cpp ++ ++# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES ++# ------------------------------------------------------- ++# Tests whether HEADER exists, giving a warning if it cannot be compiled using ++# the include files in INCLUDES and setting the cache variable VAR ++# accordingly. ++ac_fn_c_check_header_mongrel () ++{ ++ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack ++ if eval \${$3+:} false; then : ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 ++$as_echo_n "checking for $2... " >&6; } ++if eval \${$3+:} false; then : ++ $as_echo_n "(cached) " >&6 ++fi ++eval ac_res=\$$3 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++else ++ # Is the header compilable? ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 ++$as_echo_n "checking $2 usability... " >&6; } ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++$4 ++#include <$2> ++_ACEOF ++if ac_fn_c_try_compile "$LINENO"; then : ++ ac_header_compiler=yes ++else ++ ac_header_compiler=no ++fi ++rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 ++$as_echo "$ac_header_compiler" >&6; } ++ ++# Is the header present? ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 ++$as_echo_n "checking $2 presence... " >&6; } ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include <$2> ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ ac_header_preproc=yes ++else ++ ac_header_preproc=no ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 ++$as_echo "$ac_header_preproc" >&6; } ++ ++# So? What about this header? ++case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( ++ yes:no: ) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 ++$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 ++$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ++ ;; ++ no:yes:* ) ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 ++$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 ++$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 ++$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 ++$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} ++ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 ++$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ++ ;; ++esac ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 ++$as_echo_n "checking for $2... " >&6; } ++if eval \${$3+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ eval "$3=\$ac_header_compiler" ++fi ++eval ac_res=\$$3 ++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 ++$as_echo "$ac_res" >&6; } ++fi ++ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ++ ++} # ac_fn_c_check_header_mongrel ++ + # ac_fn_c_try_link LINENO + # ----------------------- + # Try to link conftest.$ac_ext, and return whether this succeeded. +@@ -4801,7 +4940,218 @@ $as_echo "$as_me: gmpxx.h not found on system - building gmp locally ..." >&6;} + $as_echo "$as_me: ... done" >&6;} + fi + +-make -C external cdd ++ ++ac_ext=c ++ac_cpp='$CPP $CPPFLAGS' ++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_c_compiler_gnu ++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 ++$as_echo_n "checking how to run the C preprocessor... " >&6; } ++# On Suns, sometimes $CPP names a directory. ++if test -n "$CPP" && test -d "$CPP"; then ++ CPP= ++fi ++if test -z "$CPP"; then ++ if ${ac_cv_prog_CPP+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ # Double quotes because CPP needs to be expanded ++ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" ++ do ++ ac_preproc_ok=false ++for ac_c_preproc_warn_flag in '' yes ++do ++ # Use a header file that comes with gcc, so configuring glibc ++ # with a fresh cross-compiler works. ++ # Prefer to if __STDC__ is defined, since ++ # exists even on freestanding compilers. ++ # On the NeXT, cc -E runs the code through the compiler's parser, ++ # not just through cpp. "Syntax error" is here to catch this case. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#ifdef __STDC__ ++# include ++#else ++# include ++#endif ++ Syntax error ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ ++else ++ # Broken: fails on valid input. ++continue ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++ # OK, works on sane cases. Now check whether nonexistent headers ++ # can be detected and how. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ # Broken: success on invalid input. ++continue ++else ++ # Passes both tests. ++ac_preproc_ok=: ++break ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++done ++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++rm -f conftest.i conftest.err conftest.$ac_ext ++if $ac_preproc_ok; then : ++ break ++fi ++ ++ done ++ ac_cv_prog_CPP=$CPP ++ ++fi ++ CPP=$ac_cv_prog_CPP ++else ++ ac_cv_prog_CPP=$CPP ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 ++$as_echo "$CPP" >&6; } ++ac_preproc_ok=false ++for ac_c_preproc_warn_flag in '' yes ++do ++ # Use a header file that comes with gcc, so configuring glibc ++ # with a fresh cross-compiler works. ++ # Prefer to if __STDC__ is defined, since ++ # exists even on freestanding compilers. ++ # On the NeXT, cc -E runs the code through the compiler's parser, ++ # not just through cpp. "Syntax error" is here to catch this case. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#ifdef __STDC__ ++# include ++#else ++# include ++#endif ++ Syntax error ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ ++else ++ # Broken: fails on valid input. ++continue ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++ # OK, works on sane cases. Now check whether nonexistent headers ++ # can be detected and how. ++ cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++#include ++_ACEOF ++if ac_fn_c_try_cpp "$LINENO"; then : ++ # Broken: success on invalid input. ++continue ++else ++ # Passes both tests. ++ac_preproc_ok=: ++break ++fi ++rm -f conftest.err conftest.i conftest.$ac_ext ++ ++done ++# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. ++rm -f conftest.i conftest.err conftest.$ac_ext ++if $ac_preproc_ok; then : ++ ++else ++ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 ++$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} ++as_fn_error $? "C preprocessor \"$CPP\" fails sanity check ++See \`config.log' for more details" "$LINENO" 5; } ++fi ++ ++ac_ext=c ++ac_cpp='$CPP $CPPFLAGS' ++ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ++ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ++ac_compiler_gnu=$ac_cv_c_compiler_gnu ++ ++ ++for ac_header in cddlib/setoper.h ++do : ++ ac_fn_c_check_header_mongrel "$LINENO" "cddlib/setoper.h" "ac_cv_header_cddlib_setoper_h" "$ac_includes_default" ++if test "x$ac_cv_header_cddlib_setoper_h" = xyes; then : ++ cat >>confdefs.h <<_ACEOF ++#define HAVE_CDDLIB_SETOPER_H 1 ++_ACEOF ++ ++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dd_free_global_constants" >&5 ++$as_echo_n "checking for library containing dd_free_global_constants... " >&6; } ++if ${ac_cv_search_dd_free_global_constants+:} false; then : ++ $as_echo_n "(cached) " >&6 ++else ++ ac_func_search_save_LIBS=$LIBS ++cat confdefs.h - <<_ACEOF >conftest.$ac_ext ++/* end confdefs.h. */ ++ ++/* Override any GCC internal prototype to avoid an error. ++ Use char because int might match the return type of a GCC ++ builtin and then its argument prototype would still apply. */ ++#ifdef __cplusplus ++extern "C" ++#endif ++char dd_free_global_constants (); ++int ++main () ++{ ++return dd_free_global_constants (); ++ ; ++ return 0; ++} ++_ACEOF ++for ac_lib in '' cddgmp; do ++ if test -z "$ac_lib"; then ++ ac_res="none required" ++ else ++ ac_res=-l$ac_lib ++ LIBS="-l$ac_lib $ac_func_search_save_LIBS" ++ fi ++ if ac_fn_c_try_link "$LINENO"; then : ++ ac_cv_search_dd_free_global_constants=$ac_res ++fi ++rm -f core conftest.err conftest.$ac_objext \ ++ conftest$ac_exeext ++ if ${ac_cv_search_dd_free_global_constants+:} false; then : ++ break ++fi ++done ++if ${ac_cv_search_dd_free_global_constants+:} false; then : ++ ++else ++ ac_cv_search_dd_free_global_constants=no ++fi ++rm conftest.$ac_ext ++LIBS=$ac_func_search_save_LIBS ++fi ++{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dd_free_global_constants" >&5 ++$as_echo "$ac_cv_search_dd_free_global_constants" >&6; } ++ac_res=$ac_cv_search_dd_free_global_constants ++if test "$ac_res" != no; then : ++ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" ++ ++else ++ as_fn_error $? "Can't use cddgmp library" "$LINENO" 5 ++fi ++ ++ ++else ++ as_fn_error $? "Can't find cdd library headers" "$LINENO" 5 ++fi ++ ++done ++ + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether QSOpt_ex support was enabled" >&5 + $as_echo_n "checking whether QSOpt_ex support was enabled... " >&6; } +@@ -6276,7 +6626,9 @@ $as_echo X/"$am_mf" | + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 + $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + as_fn_error $? "Something went wrong bootstrapping makefile fragments +- for automatic dependency tracking. Try re-running configure with the ++ for automatic dependency tracking. If GNU make was not used, consider ++ re-running the configure script with MAKE=\"gmake\" (or whatever is ++ necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking). + See \`config.log' for more details" "$LINENO" 5; } +diff --git a/configure.ac b/configure.ac +index 2372711..430f01b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -43,8 +43,10 @@ else + AC_MSG_NOTICE([... done]) + fi + +-dnl Make libcddgmp: +-make -C external cdd ++ ++AC_CHECK_HEADERS([cddlib/setoper.h],[ ++ AC_SEARCH_LIBS([dd_free_global_constants],[cddgmp], [], [AC_MSG_ERROR([Can't use cddgmp library])]) ++ ], [AC_MSG_ERROR([Can't find cdd library headers])]) + + dnl Check for requests for third-party packages: + dnl Check for qsopt_ex: +diff --git a/depcomp b/depcomp +index 65cbf70..6b39162 100755 +--- a/depcomp ++++ b/depcomp +@@ -3,7 +3,7 @@ + + scriptversion=2018-03-07.03; # UTC + +-# Copyright (C) 1999-2018 Free Software Foundation, Inc. ++# Copyright (C) 1999-2020 Free Software Foundation, Inc. + + # 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 +diff --git a/examples/Makefile.in b/examples/Makefile.in +index 92a0212..30ac680 100644 +--- a/examples/Makefile.in ++++ b/examples/Makefile.in +@@ -1,7 +1,7 @@ +-# Makefile.in generated by automake 1.16.1 from Makefile.am. ++# Makefile.in generated by automake 1.16.2 from Makefile.am. + # @configure_input@ + +-# Copyright (C) 1994-2018 Free Software Foundation, Inc. ++# Copyright (C) 1994-2020 Free Software Foundation, Inc. + + # This Makefile.in is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -129,6 +129,7 @@ AWK = @AWK@ + CC = @CC@ + CCDEPMODE = @CCDEPMODE@ + CFLAGS = @CFLAGS@ ++CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CXX = @CXX@ + CXXCPP = @CXXCPP@ +@@ -204,6 +205,7 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ ++runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +diff --git a/install-sh b/install-sh +index 8175c64..20d8b2e 100755 +--- a/install-sh ++++ b/install-sh +@@ -451,7 +451,18 @@ do + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. +- (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && ++ (umask $cp_umask && ++ { test -z "$stripcmd" || { ++ # Create $dsttmp read-write so that cp doesn't create it read-only, ++ # which would cause strip to fail. ++ if test -z "$doit"; then ++ : >"$dsttmp" # No need to fork-exec 'touch'. ++ else ++ $doit touch "$dsttmp" ++ fi ++ } ++ } && ++ $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # +diff --git a/lib-src-reg/LPinterface.hh b/lib-src-reg/LPinterface.hh +index 6522dbe..622a224 100644 +--- a/lib-src-reg/LPinterface.hh ++++ b/lib-src-reg/LPinterface.hh +@@ -21,8 +21,8 @@ + #include "LabelSet.hh" + #include "Rational.h" + +-#include "setoper.h" +-#include "cdd.h" ++#include ++#include + + namespace topcom { + +diff --git a/lib-src-reg/Makefile.in b/lib-src-reg/Makefile.in +index 977f8f8..368b2a5 100644 +--- a/lib-src-reg/Makefile.in ++++ b/lib-src-reg/Makefile.in +@@ -1,7 +1,7 @@ +-# Makefile.in generated by automake 1.16.1 from Makefile.am. ++# Makefile.in generated by automake 1.16.2 from Makefile.am. + # @configure_input@ + +-# Copyright (C) 1994-2018 Free Software Foundation, Inc. ++# Copyright (C) 1994-2020 Free Software Foundation, Inc. + + # This Makefile.in is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -214,6 +214,7 @@ AWK = @AWK@ + CC = @CC@ + CCDEPMODE = @CCDEPMODE@ + CFLAGS = @CFLAGS@ ++CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CXX = @CXX@ + CXXCPP = @CXXCPP@ +@@ -289,6 +290,7 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ ++runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +diff --git a/lib-src/Makefile.in b/lib-src/Makefile.in +index 4407b62..a3d3316 100644 +--- a/lib-src/Makefile.in ++++ b/lib-src/Makefile.in +@@ -1,7 +1,7 @@ +-# Makefile.in generated by automake 1.16.1 from Makefile.am. ++# Makefile.in generated by automake 1.16.2 from Makefile.am. + # @configure_input@ + +-# Copyright (C) 1994-2018 Free Software Foundation, Inc. ++# Copyright (C) 1994-2020 Free Software Foundation, Inc. + + # This Makefile.in is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -267,6 +267,7 @@ AWK = @AWK@ + CC = @CC@ + CCDEPMODE = @CCDEPMODE@ + CFLAGS = @CFLAGS@ ++CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CXX = @CXX@ + CXXCPP = @CXXCPP@ +@@ -342,6 +343,7 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ ++runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +diff --git a/missing b/missing +index 625aeb1..8d0eaad 100755 +--- a/missing ++++ b/missing +@@ -3,7 +3,7 @@ + + scriptversion=2018-03-07.03; # UTC + +-# Copyright (C) 1996-2018 Free Software Foundation, Inc. ++# Copyright (C) 1996-2020 Free Software Foundation, Inc. + # Originally written by Fran,cois Pinard , 1996. + + # This program is free software; you can redistribute it and/or modify +diff --git a/share/Makefile.in b/share/Makefile.in +index 23488b7..2326a9e 100644 +--- a/share/Makefile.in ++++ b/share/Makefile.in +@@ -1,7 +1,7 @@ +-# Makefile.in generated by automake 1.16.1 from Makefile.am. ++# Makefile.in generated by automake 1.16.2 from Makefile.am. + # @configure_input@ + +-# Copyright (C) 1994-2018 Free Software Foundation, Inc. ++# Copyright (C) 1994-2020 Free Software Foundation, Inc. + + # This Makefile.in is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -129,6 +129,7 @@ AWK = @AWK@ + CC = @CC@ + CCDEPMODE = @CCDEPMODE@ + CFLAGS = @CFLAGS@ ++CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CXX = @CXX@ + CXXCPP = @CXXCPP@ +@@ -204,6 +205,7 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ ++runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +diff --git a/src-reg/Makefile.am b/src-reg/Makefile.am +index ed4a016..2ad9026 100644 +--- a/src-reg/Makefile.am ++++ b/src-reg/Makefile.am +@@ -4,7 +4,9 @@ checkregularity_SOURCES = checkregularity.cc + + LDADD = ../lib-src/libTOPCOM.a \ + ../lib-src-reg/libCHECKREG.a \ +- ../external/lib/libcddgmp.a ++ -lgmpxx -lgmp ++ ++ + if USE_QSOPTEX + LDADD += ../external/lib/libqsopt_ex.a + endif +@@ -12,12 +14,6 @@ endif + if USE_SOPLEX + LDADD += ../external/lib/libsoplex.a + endif +-if USE_LOCAL_GMP +-LDADD += ../external/lib/libgmpxx.a \ +- ../external/lib/libgmp.a +-else +-LIBS += -lgmpxx -lgmp +-endif + + AM_CPPFLAGS += -I../lib-src + AM_CPPFLAGS += -I../lib-src-reg +diff --git a/src-reg/Makefile.in b/src-reg/Makefile.in +index f4b7c08..7ccd2f7 100644 +--- a/src-reg/Makefile.in ++++ b/src-reg/Makefile.in +@@ -1,7 +1,7 @@ +-# Makefile.in generated by automake 1.16.1 from Makefile.am. ++# Makefile.in generated by automake 1.16.2 from Makefile.am. + # @configure_input@ + +-# Copyright (C) 1994-2018 Free Software Foundation, Inc. ++# Copyright (C) 1994-2020 Free Software Foundation, Inc. + + # This Makefile.in is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -89,10 +89,6 @@ POST_UNINSTALL = : + bin_PROGRAMS = checkregularity$(EXEEXT) + @USE_QSOPTEX_TRUE@am__append_1 = ../external/lib/libqsopt_ex.a + @USE_SOPLEX_TRUE@am__append_2 = ../external/lib/libsoplex.a +-@USE_LOCAL_GMP_TRUE@am__append_3 = ../external/lib/libgmpxx.a \ +-@USE_LOCAL_GMP_TRUE@ ../external/lib/libgmp.a +- +-@USE_LOCAL_GMP_FALSE@am__append_4 = -lgmpxx -lgmp + subdir = src-reg + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 + am__aclocal_m4_deps = $(top_srcdir)/configure.ac +@@ -108,8 +104,7 @@ am_checkregularity_OBJECTS = checkregularity.$(OBJEXT) + checkregularity_OBJECTS = $(am_checkregularity_OBJECTS) + checkregularity_LDADD = $(LDADD) + checkregularity_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + AM_V_P = $(am__v_P_@AM_V@) + am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) + am__v_P_0 = false +@@ -184,6 +179,7 @@ AWK = @AWK@ + CC = @CC@ + CCDEPMODE = @CCDEPMODE@ + CFLAGS = @CFLAGS@ ++CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CXX = @CXX@ + CXXCPP = @CXXCPP@ +@@ -205,7 +201,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ + INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ + LDFLAGS = @LDFLAGS@ + LIBOBJS = @LIBOBJS@ +-LIBS = @LIBS@ $(am__append_4) ++LIBS = @LIBS@ + LTLIBOBJS = @LTLIBOBJS@ + MAKEINFO = @MAKEINFO@ + MKDIR_P = @MKDIR_P@ +@@ -259,6 +255,7 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ ++runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +@@ -268,9 +265,8 @@ top_build_prefix = @top_build_prefix@ + top_builddir = @top_builddir@ + top_srcdir = @top_srcdir@ + checkregularity_SOURCES = checkregularity.cc +-LDADD = ../lib-src/libTOPCOM.a ../lib-src-reg/libCHECKREG.a \ +- ../external/lib/libcddgmp.a $(am__append_1) $(am__append_2) \ +- $(am__append_3) ++LDADD = ../lib-src/libTOPCOM.a ../lib-src-reg/libCHECKREG.a -lgmpxx \ ++ -lgmp $(am__append_1) $(am__append_2) + all: all-am + + .SUFFIXES: +diff --git a/src/Makefile.am b/src/Makefile.am +index c97ecc5..e20e1c3 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -122,20 +122,15 @@ santos_dim4_triang_SOURCES = santos_dim4_triang.cc + santos_22_triang_SOURCES = santos_22_triang.cc + + LDADD = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a \ +- ../external/lib/libcddgmp.a ++ ../lib-src-reg/libCHECKREG.a ++ + if USE_QSOPTEX + LDADD += ../external/lib/libqsopt_ex.a + endif + if USE_SOPLEX + LDADD += ../external/lib/libsoplex.a + endif +-if USE_LOCAL_GMP +-LDADD += ../external/lib/libgmpxx.a \ +- ../external/lib/libgmp.a +-else + LIBS += -lgmpxx -lgmp +-endif + + + AM_CPPFLAGS += -I../lib-src +diff --git a/src/Makefile.in b/src/Makefile.in +index 47a6ac0..bcca997 100644 +--- a/src/Makefile.in ++++ b/src/Makefile.in +@@ -1,7 +1,7 @@ +-# Makefile.in generated by automake 1.16.1 from Makefile.am. ++# Makefile.in generated by automake 1.16.2 from Makefile.am. + # @configure_input@ + +-# Copyright (C) 1994-2018 Free Software Foundation, Inc. ++# Copyright (C) 1994-2020 Free Software Foundation, Inc. + + # This Makefile.in is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -115,10 +115,6 @@ bin_PROGRAMS = B_A$(EXEEXT) B_A_center$(EXEEXT) B_D$(EXEEXT) \ + santos_dim4_triang$(EXEEXT) santos_22_triang$(EXEEXT) + @USE_QSOPTEX_TRUE@am__append_1 = ../external/lib/libqsopt_ex.a + @USE_SOPLEX_TRUE@am__append_2 = ../external/lib/libsoplex.a +-@USE_LOCAL_GMP_TRUE@am__append_3 = ../external/lib/libgmpxx.a \ +-@USE_LOCAL_GMP_TRUE@ ../external/lib/libgmp.a +- +-@USE_LOCAL_GMP_FALSE@am__append_4 = -lgmpxx -lgmp + subdir = src + ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 + am__aclocal_m4_deps = $(top_srcdir)/configure.ac +@@ -134,362 +130,302 @@ am_B_A_OBJECTS = B_A.$(OBJEXT) + B_A_OBJECTS = $(am_B_A_OBJECTS) + B_A_LDADD = $(LDADD) + B_A_DEPENDENCIES = ../lib-src/libTOPCOM.a ../lib-src-reg/libCHECKREG.a \ +- ../external/lib/libcddgmp.a $(am__append_1) $(am__append_2) \ +- $(am__append_3) ++ $(am__append_1) $(am__append_2) + am_B_A_center_OBJECTS = B_A_center.$(OBJEXT) + B_A_center_OBJECTS = $(am_B_A_center_OBJECTS) + B_A_center_LDADD = $(LDADD) + B_A_center_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_B_D_OBJECTS = B_D.$(OBJEXT) + B_D_OBJECTS = $(am_B_D_OBJECTS) + B_D_LDADD = $(LDADD) + B_D_DEPENDENCIES = ../lib-src/libTOPCOM.a ../lib-src-reg/libCHECKREG.a \ +- ../external/lib/libcddgmp.a $(am__append_1) $(am__append_2) \ +- $(am__append_3) ++ $(am__append_1) $(am__append_2) + am_B_D_center_OBJECTS = B_D_center.$(OBJEXT) + B_D_center_OBJECTS = $(am_B_D_center_OBJECTS) + B_D_center_LDADD = $(LDADD) + B_D_center_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_B_S_OBJECTS = B_S.$(OBJEXT) + B_S_OBJECTS = $(am_B_S_OBJECTS) + B_S_LDADD = $(LDADD) + B_S_DEPENDENCIES = ../lib-src/libTOPCOM.a ../lib-src-reg/libCHECKREG.a \ +- ../external/lib/libcddgmp.a $(am__append_1) $(am__append_2) \ +- $(am__append_3) ++ $(am__append_1) $(am__append_2) + am_B_S_center_OBJECTS = B_S_center.$(OBJEXT) + B_S_center_OBJECTS = $(am_B_S_center_OBJECTS) + B_S_center_LDADD = $(LDADD) + B_S_center_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_Dnxk_OBJECTS = Dnxk.$(OBJEXT) + Dnxk_OBJECTS = $(am_Dnxk_OBJECTS) + Dnxk_LDADD = $(LDADD) + Dnxk_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_binomial_OBJECTS = binomial.$(OBJEXT) + binomial_OBJECTS = $(am_binomial_OBJECTS) + binomial_LDADD = $(LDADD) + binomial_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_check_OBJECTS = check.$(OBJEXT) + check_OBJECTS = $(am_check_OBJECTS) + check_LDADD = $(LDADD) + check_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2allfinetriangs_OBJECTS = chiro2allfinetriangs.$(OBJEXT) + chiro2allfinetriangs_OBJECTS = $(am_chiro2allfinetriangs_OBJECTS) + chiro2allfinetriangs_LDADD = $(LDADD) + chiro2allfinetriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2alltriangs_OBJECTS = chiro2alltriangs.$(OBJEXT) + chiro2alltriangs_OBJECTS = $(am_chiro2alltriangs_OBJECTS) + chiro2alltriangs_LDADD = $(LDADD) + chiro2alltriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2circuits_OBJECTS = chiro2circuits.$(OBJEXT) + chiro2circuits_OBJECTS = $(am_chiro2circuits_OBJECTS) + chiro2circuits_LDADD = $(LDADD) + chiro2circuits_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2cocircuits_OBJECTS = chiro2cocircuits.$(OBJEXT) + chiro2cocircuits_OBJECTS = $(am_chiro2cocircuits_OBJECTS) + chiro2cocircuits_LDADD = $(LDADD) + chiro2cocircuits_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2dual_OBJECTS = chiro2dual.$(OBJEXT) + chiro2dual_OBJECTS = $(am_chiro2dual_OBJECTS) + chiro2dual_LDADD = $(LDADD) + chiro2dual_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2finetriang_OBJECTS = chiro2finetriang.$(OBJEXT) + chiro2finetriang_OBJECTS = $(am_chiro2finetriang_OBJECTS) + chiro2finetriang_LDADD = $(LDADD) + chiro2finetriang_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2finetriangs_OBJECTS = chiro2finetriangs.$(OBJEXT) + chiro2finetriangs_OBJECTS = $(am_chiro2finetriangs_OBJECTS) + chiro2finetriangs_LDADD = $(LDADD) + chiro2finetriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2mintriang_OBJECTS = chiro2mintriang.$(OBJEXT) + chiro2mintriang_OBJECTS = $(am_chiro2mintriang_OBJECTS) + chiro2mintriang_LDADD = $(LDADD) + chiro2mintriang_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2nallfinetriangs_OBJECTS = chiro2nallfinetriangs.$(OBJEXT) + chiro2nallfinetriangs_OBJECTS = $(am_chiro2nallfinetriangs_OBJECTS) + chiro2nallfinetriangs_LDADD = $(LDADD) + chiro2nallfinetriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2nalltriangs_OBJECTS = chiro2nalltriangs.$(OBJEXT) + chiro2nalltriangs_OBJECTS = $(am_chiro2nalltriangs_OBJECTS) + chiro2nalltriangs_LDADD = $(LDADD) + chiro2nalltriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2ncircuits_OBJECTS = chiro2ncircuits.$(OBJEXT) + chiro2ncircuits_OBJECTS = $(am_chiro2ncircuits_OBJECTS) + chiro2ncircuits_LDADD = $(LDADD) + chiro2ncircuits_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2ncocircuits_OBJECTS = chiro2ncocircuits.$(OBJEXT) + chiro2ncocircuits_OBJECTS = $(am_chiro2ncocircuits_OBJECTS) + chiro2ncocircuits_LDADD = $(LDADD) + chiro2ncocircuits_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2nfinetriangs_OBJECTS = chiro2nfinetriangs.$(OBJEXT) + chiro2nfinetriangs_OBJECTS = $(am_chiro2nfinetriangs_OBJECTS) + chiro2nfinetriangs_LDADD = $(LDADD) + chiro2nfinetriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2ntriangs_OBJECTS = chiro2ntriangs.$(OBJEXT) + chiro2ntriangs_OBJECTS = $(am_chiro2ntriangs_OBJECTS) + chiro2ntriangs_LDADD = $(LDADD) + chiro2ntriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2placingtriang_OBJECTS = chiro2placingtriang.$(OBJEXT) + chiro2placingtriang_OBJECTS = $(am_chiro2placingtriang_OBJECTS) + chiro2placingtriang_LDADD = $(LDADD) + chiro2placingtriang_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_chiro2triangs_OBJECTS = chiro2triangs.$(OBJEXT) + chiro2triangs_OBJECTS = $(am_chiro2triangs_OBJECTS) + chiro2triangs_LDADD = $(LDADD) + chiro2triangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_cocircuits2facets_OBJECTS = cocircuits2facets.$(OBJEXT) + cocircuits2facets_OBJECTS = $(am_cocircuits2facets_OBJECTS) + cocircuits2facets_LDADD = $(LDADD) + cocircuits2facets_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_cross_OBJECTS = cross.$(OBJEXT) + cross_OBJECTS = $(am_cross_OBJECTS) + cross_LDADD = $(LDADD) + cross_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_cube_OBJECTS = cube.$(OBJEXT) + cube_OBJECTS = $(am_cube_OBJECTS) + cube_LDADD = $(LDADD) + cube_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_cyclic_OBJECTS = cyclic.$(OBJEXT) + cyclic_OBJECTS = $(am_cyclic_OBJECTS) + cyclic_LDADD = $(LDADD) + cyclic_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_hypersimplex_OBJECTS = hypersimplex.$(OBJEXT) + hypersimplex_OBJECTS = $(am_hypersimplex_OBJECTS) + hypersimplex_LDADD = $(LDADD) + hypersimplex_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_kDn_OBJECTS = kDn.$(OBJEXT) + kDn_OBJECTS = $(am_kDn_OBJECTS) + kDn_LDADD = $(LDADD) + kDn_DEPENDENCIES = ../lib-src/libTOPCOM.a ../lib-src-reg/libCHECKREG.a \ +- ../external/lib/libcddgmp.a $(am__append_1) $(am__append_2) \ +- $(am__append_3) ++ $(am__append_1) $(am__append_2) + am_lattice_OBJECTS = lattice.$(OBJEXT) + lattice_OBJECTS = $(am_lattice_OBJECTS) + lattice_LDADD = $(LDADD) + lattice_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_permutahedron_OBJECTS = permutahedron.$(OBJEXT) + permutahedron_OBJECTS = $(am_permutahedron_OBJECTS) + permutahedron_LDADD = $(LDADD) + permutahedron_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2allfinetriangs_OBJECTS = points2allfinetriangs.$(OBJEXT) + points2allfinetriangs_OBJECTS = $(am_points2allfinetriangs_OBJECTS) + points2allfinetriangs_LDADD = $(LDADD) + points2allfinetriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2alltriangs_OBJECTS = points2alltriangs.$(OBJEXT) + points2alltriangs_OBJECTS = $(am_points2alltriangs_OBJECTS) + points2alltriangs_LDADD = $(LDADD) + points2alltriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2chiro_OBJECTS = points2chiro.$(OBJEXT) + points2chiro_OBJECTS = $(am_points2chiro_OBJECTS) + points2chiro_LDADD = $(LDADD) + points2chiro_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2circuits_OBJECTS = points2circuits.$(OBJEXT) + points2circuits_OBJECTS = $(am_points2circuits_OBJECTS) + points2circuits_LDADD = $(LDADD) + points2circuits_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2cocircuits_OBJECTS = points2cocircuits.$(OBJEXT) + points2cocircuits_OBJECTS = $(am_points2cocircuits_OBJECTS) + points2cocircuits_LDADD = $(LDADD) + points2cocircuits_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2facets_OBJECTS = points2facets.$(OBJEXT) + points2facets_OBJECTS = $(am_points2facets_OBJECTS) + points2facets_LDADD = $(LDADD) + points2facets_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2finetriang_OBJECTS = points2finetriang.$(OBJEXT) + points2finetriang_OBJECTS = $(am_points2finetriang_OBJECTS) + points2finetriang_LDADD = $(LDADD) + points2finetriang_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2finetriangs_OBJECTS = points2finetriangs.$(OBJEXT) + points2finetriangs_OBJECTS = $(am_points2finetriangs_OBJECTS) + points2finetriangs_LDADD = $(LDADD) + points2finetriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2flips_OBJECTS = points2flips.$(OBJEXT) + points2flips_OBJECTS = $(am_points2flips_OBJECTS) + points2flips_LDADD = $(LDADD) + points2flips_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2gale_OBJECTS = points2gale.$(OBJEXT) + points2gale_OBJECTS = $(am_points2gale_OBJECTS) + points2gale_LDADD = $(LDADD) + points2gale_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2mintriang_OBJECTS = points2mintriang.$(OBJEXT) + points2mintriang_OBJECTS = $(am_points2mintriang_OBJECTS) + points2mintriang_LDADD = $(LDADD) + points2mintriang_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2nallfinetriangs_OBJECTS = points2nallfinetriangs.$(OBJEXT) + points2nallfinetriangs_OBJECTS = $(am_points2nallfinetriangs_OBJECTS) + points2nallfinetriangs_LDADD = $(LDADD) + points2nallfinetriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2nalltriangs_OBJECTS = points2nalltriangs.$(OBJEXT) + points2nalltriangs_OBJECTS = $(am_points2nalltriangs_OBJECTS) + points2nalltriangs_LDADD = $(LDADD) + points2nalltriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2ncircuits_OBJECTS = points2ncircuits.$(OBJEXT) + points2ncircuits_OBJECTS = $(am_points2ncircuits_OBJECTS) + points2ncircuits_LDADD = $(LDADD) + points2ncircuits_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2ncocircuits_OBJECTS = points2ncocircuits.$(OBJEXT) + points2ncocircuits_OBJECTS = $(am_points2ncocircuits_OBJECTS) + points2ncocircuits_LDADD = $(LDADD) + points2ncocircuits_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2nfinetriangs_OBJECTS = points2nfinetriangs.$(OBJEXT) + points2nfinetriangs_OBJECTS = $(am_points2nfinetriangs_OBJECTS) + points2nfinetriangs_LDADD = $(LDADD) + points2nfinetriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2nflips_OBJECTS = points2nflips.$(OBJEXT) + points2nflips_OBJECTS = $(am_points2nflips_OBJECTS) + points2nflips_LDADD = $(LDADD) + points2nflips_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2ntriangs_OBJECTS = points2ntriangs.$(OBJEXT) + points2ntriangs_OBJECTS = $(am_points2ntriangs_OBJECTS) + points2ntriangs_LDADD = $(LDADD) + points2ntriangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2placingtriang_OBJECTS = points2placingtriang.$(OBJEXT) + points2placingtriang_OBJECTS = $(am_points2placingtriang_OBJECTS) + points2placingtriang_LDADD = $(LDADD) + points2placingtriang_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2prettyprint_OBJECTS = points2prettyprint.$(OBJEXT) + points2prettyprint_OBJECTS = $(am_points2prettyprint_OBJECTS) + points2prettyprint_LDADD = $(LDADD) + points2prettyprint_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2symmetries_OBJECTS = points2symmetries.$(OBJEXT) + points2symmetries_OBJECTS = $(am_points2symmetries_OBJECTS) + points2symmetries_LDADD = $(LDADD) + points2symmetries_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2triangs_OBJECTS = points2triangs.$(OBJEXT) + points2triangs_OBJECTS = $(am_points2triangs_OBJECTS) + points2triangs_LDADD = $(LDADD) + points2triangs_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2vertices_OBJECTS = points2vertices.$(OBJEXT) + points2vertices_OBJECTS = $(am_points2vertices_OBJECTS) + points2vertices_LDADD = $(LDADD) + points2vertices_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_points2volume_OBJECTS = points2volume.$(OBJEXT) + points2volume_OBJECTS = $(am_points2volume_OBJECTS) + points2volume_LDADD = $(LDADD) + points2volume_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_santos_22_triang_OBJECTS = santos_22_triang.$(OBJEXT) + santos_22_triang_OBJECTS = $(am_santos_22_triang_OBJECTS) + santos_22_triang_LDADD = $(LDADD) + santos_22_triang_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_santos_dim4_triang_OBJECTS = santos_dim4_triang.$(OBJEXT) + santos_dim4_triang_OBJECTS = $(am_santos_dim4_triang_OBJECTS) + santos_dim4_triang_LDADD = $(LDADD) + santos_dim4_triang_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + am_santos_triang_OBJECTS = santos_triang.$(OBJEXT) + santos_triang_OBJECTS = $(am_santos_triang_OBJECTS) + santos_triang_LDADD = $(LDADD) + santos_triang_DEPENDENCIES = ../lib-src/libTOPCOM.a \ +- ../lib-src-reg/libCHECKREG.a ../external/lib/libcddgmp.a \ +- $(am__append_1) $(am__append_2) $(am__append_3) ++ ../lib-src-reg/libCHECKREG.a $(am__append_1) $(am__append_2) + AM_V_P = $(am__v_P_@AM_V@) + am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) + am__v_P_0 = false +@@ -657,6 +593,7 @@ AWK = @AWK@ + CC = @CC@ + CCDEPMODE = @CCDEPMODE@ + CFLAGS = @CFLAGS@ ++CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CXX = @CXX@ + CXXCPP = @CXXCPP@ +@@ -678,7 +615,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ + INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ + LDFLAGS = @LDFLAGS@ + LIBOBJS = @LIBOBJS@ +-LIBS = @LIBS@ $(am__append_4) ++LIBS = @LIBS@ -lgmpxx -lgmp + LTLIBOBJS = @LTLIBOBJS@ + MAKEINFO = @MAKEINFO@ + MKDIR_P = @MKDIR_P@ +@@ -732,6 +669,7 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ ++runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ +@@ -801,8 +739,7 @@ santos_triang_SOURCES = santos_triang.cc + santos_dim4_triang_SOURCES = santos_dim4_triang.cc + santos_22_triang_SOURCES = santos_22_triang.cc + LDADD = ../lib-src/libTOPCOM.a ../lib-src-reg/libCHECKREG.a \ +- ../external/lib/libcddgmp.a $(am__append_1) $(am__append_2) \ +- $(am__append_3) ++ $(am__append_1) $(am__append_2) + all: all-am + + .SUFFIXES: +diff --git a/wrap-gmp-gmpxx/Makefile.in b/wrap-gmp-gmpxx/Makefile.in +index 86f0be0..bd4c95f 100644 +--- a/wrap-gmp-gmpxx/Makefile.in ++++ b/wrap-gmp-gmpxx/Makefile.in +@@ -1,7 +1,7 @@ +-# Makefile.in generated by automake 1.16.1 from Makefile.am. ++# Makefile.in generated by automake 1.16.2 from Makefile.am. + # @configure_input@ + +-# Copyright (C) 1994-2018 Free Software Foundation, Inc. ++# Copyright (C) 1994-2020 Free Software Foundation, Inc. + + # This Makefile.in is free software; the Free Software Foundation + # gives unlimited permission to copy and/or distribute it, +@@ -178,6 +178,7 @@ AWK = @AWK@ + CC = @CC@ + CCDEPMODE = @CCDEPMODE@ + CFLAGS = @CFLAGS@ ++CPP = @CPP@ + CPPFLAGS = @CPPFLAGS@ + CXX = @CXX@ + CXXCPP = @CXXCPP@ +@@ -253,6 +254,7 @@ pdfdir = @pdfdir@ + prefix = @prefix@ + program_transform_name = @program_transform_name@ + psdir = @psdir@ ++runstatedir = @runstatedir@ + sbindir = @sbindir@ + sharedstatedir = @sharedstatedir@ + srcdir = @srcdir@ diff --git a/build/pkgs/widgetsnbextension/checksums.ini b/build/pkgs/widgetsnbextension/checksums.ini index 520bd3a6401..2b335f09484 100644 --- a/build/pkgs/widgetsnbextension/checksums.ini +++ b/build/pkgs/widgetsnbextension/checksums.ini @@ -1,5 +1,5 @@ tarball=widgetsnbextension-VERSION.tar.gz -sha1=0dddc23af2ec56d3a666bba070da1518312d1163 -md5=86dd0471c4e376d981d7633224aa0607 -cksum=3308939542 +sha1=21f8dc7732adad09921bf590fa0eb0d4c3dd7f48 +md5=2d44896382b3a587823e08df6d2f3165 +cksum=209268639 upstream_url=https://pypi.io/packages/source/w/widgetsnbextension/widgetsnbextension-VERSION.tar.gz diff --git a/build/pkgs/widgetsnbextension/dependencies b/build/pkgs/widgetsnbextension/dependencies index dd63a9f4ef1..f7ff1dca568 100644 --- a/build/pkgs/widgetsnbextension/dependencies +++ b/build/pkgs/widgetsnbextension/dependencies @@ -1,4 +1,4 @@ -$(PYTHON) | $(PYTHON_TOOLCHAIN) jupyter_core +$(PYTHON) jupyter_packaging | $(PYTHON_TOOLCHAIN) jupyter_core ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/widgetsnbextension/package-version.txt b/build/pkgs/widgetsnbextension/package-version.txt index 9575d51bad2..c4e41f94594 100644 --- a/build/pkgs/widgetsnbextension/package-version.txt +++ b/build/pkgs/widgetsnbextension/package-version.txt @@ -1 +1 @@ -3.6.1 +4.0.3 diff --git a/build/pkgs/widgetsnbextension/patches/no-notebook-dep.patch b/build/pkgs/widgetsnbextension/patches/no-notebook-dep.patch deleted file mode 100644 index 976091637f5..00000000000 --- a/build/pkgs/widgetsnbextension/patches/no-notebook-dep.patch +++ /dev/null @@ -1,24 +0,0 @@ -commit 55bc3c93bf4310d4f4d9d02f2e51d1d65b7f6533 (HEAD -> 7.6.3-sage) -Author: Sylvain Corlay -Date: Mon Oct 21 01:33:23 2019 +0200 - - Drop notebook dependency from widgetsnbextension - -diff --git a/widgetsnbextension/setup.py b/widgetsnbextension/setup.py -index 866d82eb..88746f95 100644 ---- a/setup.py -+++ b/setup.py -@@ -219,13 +219,5 @@ if 'setuptools' in sys.modules: - from setuptools.command.develop import develop - setup_args['cmdclass']['develop'] = js_prerelease(develop, strict=True) - --setuptools_args = {} --install_requires = setuptools_args['install_requires'] = [ -- 'notebook>=4.4.1', --] -- --if 'setuptools' in sys.modules: -- setup_args.update(setuptools_args) -- - if __name__ == '__main__': - setup(**setup_args) diff --git a/build/sage_bootstrap/app.py b/build/sage_bootstrap/app.py index d6094609d88..66da2665e84 100644 --- a/build/sage_bootstrap/app.py +++ b/build/sage_bootstrap/app.py @@ -148,13 +148,22 @@ def update_latest(self, package_name, commit=False): """ Update a package to the latest version. This modifies the Sage sources. """ + pkg = Package(package_name) + dist_name = pkg.distribution_name + if dist_name is None: + log.debug('%s does not have Python distribution info in install-requires.txt' % pkg) + return + if pkg.tarball_pattern.endswith('.whl'): + source = 'wheel' + else: + source = 'pypi' try: - pypi = PyPiVersion(package_name) + pypi = PyPiVersion(dist_name, source=source) except PyPiNotFound: - log.debug('%s is not a pypi package', package_name) + log.debug('%s is not a pypi package', dist_name) return else: - pypi.update(Package(package_name)) + pypi.update(pkg) if commit: self.commit(package_name) @@ -266,12 +275,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 +298,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/package.py b/build/sage_bootstrap/package.py index ffe790f9c74..15b342223c4 100644 --- a/build/sage_bootstrap/package.py +++ b/build/sage_bootstrap/package.py @@ -46,6 +46,7 @@ def __init__(self, package_name): self._init_checksum() self._init_version() self._init_type() + self._init_install_requires() def __repr__(self): return 'Package {0}'.format(self.name) @@ -229,6 +230,21 @@ def type(self): """ return self.__type + @property + def distribution_name(self): + """ + Return the Python distribution name or ``None`` for non-Python packages + """ + if self.__install_requires is None: + return None + for line in self.__install_requires.split('\n'): + line = line.strip() + if line.startswith('#'): + continue + for part in line.split(): + return part + return None + def __eq__(self, other): return self.tarball == other.tarball @@ -312,3 +328,10 @@ def _init_type(self): 'base', 'standard', 'optional', 'experimental' ] self.__type = package_type + + def _init_install_requires(self): + try: + with open(os.path.join(self.path, 'install-requires.txt')) as f: + self.__install_requires = f.read().strip() + except IOError: + self.__install_requires = None 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/build/sage_bootstrap/uncompress/filter_os_files.py b/build/sage_bootstrap/uncompress/filter_os_files.py index db05e4303ae..f6d99ee3280 100644 --- a/build/sage_bootstrap/uncompress/filter_os_files.py +++ b/build/sage_bootstrap/uncompress/filter_os_files.py @@ -1,19 +1,16 @@ """ Filtering out OS-specific files """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Volker Braun # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** import os -import sys def filter_os_files(filenames): @@ -23,7 +20,6 @@ def filter_os_files(filenames): Currently removes OSX .DS_Store files and AppleDouble format ._ files. """ - files_set = set(filenames) def is_os_file(path): @@ -45,10 +41,4 @@ def is_os_file(path): return False - filenames = filter(lambda f: not is_os_file(f), filenames) - - if sys.version_info[0] == 2: - return filenames - else: - # Make sure to return a list on Python >= 3 - return list(filenames) + return [f for f in filenames if not is_os_file(f)] diff --git a/configure.ac b/configure.ac index 10351b8c416..1070ac424ab 100644 --- a/configure.ac +++ b/configure.ac @@ -132,6 +132,12 @@ AC_ARG_ENABLE([editable], [AC_SUBST([SAGE_EDITABLE], [$enableval])], [AC_SUBST([SAGE_EDITABLE], [yes])]) +AC_ARG_ENABLE([wheels], + [AS_HELP_STRING([--enable-wheels], + [build wheels for the Sage library and update them on "sage -b"; if disabled, use "make wheels" to build wheels])], + [AC_SUBST([SAGE_WHEELS], [$enableval])], + []) + # Check whether we are on a supported platform AC_CANONICAL_BUILD() AC_CANONICAL_HOST() diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index aadd65deb15..b0789c4fde8 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta3 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index aadd65deb15..b0789c4fde8 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta3 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index aadd65deb15..b0789c4fde8 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta3 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index aadd65deb15..b0789c4fde8 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta3 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index aadd65deb15..b0789c4fde8 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta3 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..b0789c4fde8 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta3 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..b0789c4fde8 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta3 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..b0789c4fde8 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta3 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..b0789c4fde8 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta3 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/setup.py b/pkgs/sagemath-standard/setup.py index b6006188d33..ce9fd0a70aa 100755 --- a/pkgs/sagemath-standard/setup.py +++ b/pkgs/sagemath-standard/setup.py @@ -15,6 +15,15 @@ import multiprocessing multiprocessing.set_start_method('fork', force=True) +# If build isolation is not in use and setuptools_scm is installed, +# then its file_finders entry point is invoked, which we don't need. +# Workaround from ​https://github.com/pypa/setuptools_scm/issues/190#issuecomment-351181286 +try: + import setuptools_scm.integration + setuptools_scm.integration.find_files = lambda _: [] +except ImportError: + pass + ######################################################### ### Set source directory ######################################################### @@ -30,7 +39,7 @@ ### Configuration ######################################################### -if len(sys.argv) > 1 and (sys.argv[1] == "sdist" or sys.argv[1] == "egg_info"): +if len(sys.argv) > 1 and (sys.argv[1] in ["sdist", "egg_info", "dist_info"]): sdist = True else: sdist = False diff --git a/pkgs/sagemath-standard/tox.ini b/pkgs/sagemath-standard/tox.ini index 9f20ae256bc..765f7ffc415 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/MANIFEST.in b/src/MANIFEST.in index f63856e03aa..3a63d07fc32 100644 --- a/src/MANIFEST.in +++ b/src/MANIFEST.in @@ -1,11 +1,47 @@ -global-include *.c *.cc *.cpp *.h *.hh *.hpp *.inc *.py *.pyx *.pxd *.pxi *.rst *.txt *.tex - -include MANIFEST.in -include pyproject.toml - -prune .tox - prune sage/ext/interpreters # In particular, __init__.py must not be present in the distribution; or sage_setup.autogen.interpreters.rebuild will not generate the code prune sage_setup prune sage_docbuild prune doc + +# +# Most C and C++ files are generated by Cython and should not +# be included in the sdist. +# +global-exclude *.c +global-exclude *.cpp + +# +# List of C and C++ files that are actual source files, +# NOT generated by Cython. The same list appears in SAGE_ROOT/.gitignore +# +include sage/cpython/debugimpl.c +include sage/graphs/base/boost_interface.cpp +include sage/graphs/cliquer/cl.c +include sage/graphs/graph_decompositions/sage_tdlib.cpp +include sage/libs/eclib/wrap.cpp +include sage/libs/linkages/padics/relaxed/flint_helper.c +include sage/misc/inherit_comparison_impl.c +include sage/modular/arithgroup/farey.cpp +include sage/modular/arithgroup/sl2z.cpp +include sage/rings/bernmm/bern_modp.cpp +include sage/rings/bernmm/bern_modp_util.cpp +include sage/rings/bernmm/bern_rat.cpp +include sage/rings/bernmm/bernmm-test.cpp +include sage/rings/padics/transcendantal.c +include sage/rings/polynomial/weil/power_sums.c +include sage/schemes/hyperelliptic_curves/hypellfrob/hypellfrob.cpp +include sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_ntl.cpp +include sage/schemes/hyperelliptic_curves/hypellfrob/recurrences_zn_poly.cpp +include sage/stats/distributions/dgs_bern.c +include sage/stats/distributions/dgs_gauss_dp.c +include sage/stats/distributions/dgs_gauss_mp.c +include sage/symbolic/ginac/*.cpp + +global-exclude __pycache__ +global-exclude *.py[co] +global-exclude *.bak +global-exclude *.so +global-exclude *~ +prune .tox +prune build +prune dist diff --git a/src/VERSION.txt b/src/VERSION.txt index aadd65deb15..b0789c4fde8 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -9.8.beta0 +9.8.beta3 diff --git a/src/bin/sage-notebook b/src/bin/sage-notebook index 13636b88703..2e8b12e1a1c 100755 --- a/src/bin/sage-notebook +++ b/src/bin/sage-notebook @@ -60,9 +60,6 @@ class NotebookJupyterlab(): traceback.print_exc() print("Jupyterlab is not installed (at least not in this Sage installation).") print("You can install it by running") - print(" sage -i jupyterlab_widgets") - print("which includes support for interacts and the ability to download and") - print("install other Jupyterlab extensions. For a minimal installation, run") print(" sage -i jupyterlab") print("Alternatively, you can follow the instructions at") print(" " + _system_jupyter_url) @@ -89,9 +86,6 @@ class NotebookNbclassic(): traceback.print_exc() print("Jupyterlab is not installed (at least not in this Sage installation).") print("You can install it by running") - print(" sage -i jupyterlab_widgets") - print("which includes support for interacts and the ability to download and") - print("install other Jupyterlab extensions. For a minimal installation, run") print(" sage -i jupyterlab") raise SystemExit(1) self.print_banner() @@ -115,9 +109,6 @@ class NotebookRetrolab(): traceback.print_exc() print("Retrolab is not installed (at least not in this Sage installation).") print("You can install it by running") - print(" sage -i jupyterlab_widgets retrolab") - print("which includes support for interacts and the ability to download and") - print("install other Jupyterlab extensions. For a minimal installation, run") print(" sage -i retrolab") raise SystemExit(1) self.print_banner() diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 802ca805250..b4ab677a7f3 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.beta3' +SAGE_RELEASE_DATE='2022-10-30' +SAGE_VERSION_BANNER='SageMath version 9.8.beta3, Release Date: 2022-10-30' diff --git a/src/doc/Makefile b/src/doc/Makefile index 62fb1cafd18..2f76dfb9cb4 100644 --- a/src/doc/Makefile +++ b/src/doc/Makefile @@ -14,6 +14,7 @@ all: doc-html clean: rm -rf en/reference/*/sage + rm -rf en/reference/documentation/sage_docbuild rm -rf en/reference/sage rm -f common/*.pyc diff --git a/src/doc/de/thematische_anleitungen/conf.py b/src/doc/de/thematische_anleitungen/conf.py index 114346944d5..7f2753ab0e4 100644 --- a/src/doc/de/thematische_anleitungen/conf.py +++ b/src/doc/de/thematische_anleitungen/conf.py @@ -27,7 +27,7 @@ # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -html_title = project + " v"+release +html_title = project + " v" + release # Output file base name for HTML help builder. htmlhelp_basename = name @@ -35,7 +35,6 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ - ('index', name+'.tex', project, + ('index', name + '.tex', project, 'The Sage Group', 'manual'), ] - diff --git a/src/doc/de/tutorial/conf.py b/src/doc/de/tutorial/conf.py index 16804d981c9..8d18c44aa6b 100644 --- a/src/doc/de/tutorial/conf.py +++ b/src/doc/de/tutorial/conf.py @@ -38,4 +38,3 @@ ('index', name+'.tex', project, 'The Sage Group', 'manual'), ] - diff --git a/src/doc/en/a_tour_of_sage/conf.py b/src/doc/en/a_tour_of_sage/conf.py index 89225513782..14ecb994215 100644 --- a/src/doc/en/a_tour_of_sage/conf.py +++ b/src/doc/en/a_tour_of_sage/conf.py @@ -37,4 +37,3 @@ ('index', 'a_tour_of_sage.tex', 'A Tour Of Sage', 'The Sage Development Team', 'manual'), ] - diff --git a/src/doc/en/constructions/conf.py b/src/doc/en/constructions/conf.py index eee2feb033a..37215f418c6 100644 --- a/src/doc/en/constructions/conf.py +++ b/src/doc/en/constructions/conf.py @@ -36,4 +36,3 @@ ('index', 'constructions.tex', 'Constructions', 'The Sage Development Team', 'manual'), ] - diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index 4f208b8e357..0371341a3ab 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -44,7 +44,7 @@ In particular, - Use 4 spaces for indentation levels. Do not use tabs as they can result in indentation confusion. Most editors have a feature that - will insert 4 spaces when the tab key is hit. Also, many editors + will insert 4 spaces when the :kbd:`Tab` key is hit. Also, many editors will automatically search/replace leading tabs with 4 spaces. - Whitespace before and after assignment and binary operator of the diff --git a/src/doc/en/developer/conf.py b/src/doc/en/developer/conf.py index 1ee9e105947..bde00a0970d 100644 --- a/src/doc/en/developer/conf.py +++ b/src/doc/en/developer/conf.py @@ -36,4 +36,3 @@ ('index', 'developer.tex', 'Developer\'s Guide', 'The Sage Development Team', 'manual'), ] - 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/faq/faq-usage.rst b/src/doc/en/faq/faq-usage.rst index 9d5f2cbeb95..40e4be5ddec 100644 --- a/src/doc/en/faq/faq-usage.rst +++ b/src/doc/en/faq/faq-usage.rst @@ -229,13 +229,13 @@ Can I do X in Sage? """"""""""""""""""" You are encouraged to use Sage's tab autocompletion. Just type a few -characters, hit the tab key, and see if the command you want appears +characters, hit the :kbd:`Tab` key, and see if the command you want appears in the list of tab autocompletion. If you have a command called -``mycmd``, then type ``mycmd.`` and hit the tab key to get a list of +``mycmd``, then type ``mycmd.`` and hit the :kbd:`Tab` key to get a list of functionalities that are supported by that command. To read the -documentation of ``mycmd``, type ``mycmd?`` and press the enter key to +documentation of ``mycmd``, type ``mycmd?`` and press the :kbd:`Enter` key to read the documentation for that command. Similarly, type ``mycmd??`` -and hit the enter key to get the source code of that command. You are +and hit the :kbd:`Enter` key to get the source code of that command. You are also encouraged to search through the source code and documentation of the Sage library. To search through the source code of the Sage library, use the command ``search_src("")`` where you diff --git a/src/doc/en/installation/conf.py b/src/doc/en/installation/conf.py index 33ed20fa8e9..e50bf3c1c57 100644 --- a/src/doc/en/installation/conf.py +++ b/src/doc/en/installation/conf.py @@ -36,4 +36,3 @@ ('index', 'installation.tex', 'Installation Guide', 'The Sage Development Team', 'manual'), ] - 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/prep/Advanced-2DPlotting.rst b/src/doc/en/prep/Advanced-2DPlotting.rst index 337457afef4..633e33d68b3 100644 --- a/src/doc/en/prep/Advanced-2DPlotting.rst +++ b/src/doc/en/prep/Advanced-2DPlotting.rst @@ -39,9 +39,10 @@ following sections: - :ref:`Saving` -This tutorial assumes that one is familiar with the basics of Sage, such -as evaluating a cell by clicking the "evaluate" link, or by pressing -Shift\-Enter (hold down Shift while pressing the Enter key). +This tutorial assumes that one is familiar with the basics of Sage, +such as evaluating a cell by clicking the "evaluate" link, or by +pressing :kbd:`Shift` + :kbd:`Enter` (hold down :kbd:`Shift` while +pressing the :kbd:`Enter` key). .. fixme - if log plots are in by the time this makes it in, put them in!!! diff --git a/src/doc/en/prep/Calculus.rst b/src/doc/en/prep/Calculus.rst index 8c9ea73777b..af6902b9e04 100644 --- a/src/doc/en/prep/Calculus.rst +++ b/src/doc/en/prep/Calculus.rst @@ -29,10 +29,10 @@ the United States; the final section is a checkpoint of sorts. The tutorial assumes that one is familiar with the basics of Sage, such as outlined in the previous tutorials. -For a refresher, make sure the syntax below for defining a function and -getting a value makes sense; then evaluate the cell by clicking the -"evaluate" link, or by pressing Shift\-Enter (hold down Shift while -pressing the Enter key). +For a refresher, make sure the syntax below for defining a function +and getting a value makes sense; then evaluate the cell by clicking +the "evaluate" link, or by pressing :kbd:`Shift` + :kbd:`Enter` (hold +down :kbd:`Shift` while pressing the :kbd:`Enter` key). :: diff --git a/src/doc/en/prep/Intro-Tutorial.rst b/src/doc/en/prep/Intro-Tutorial.rst index 2febd01ac19..7ab0a4ad97d 100644 --- a/src/doc/en/prep/Intro-Tutorial.rst +++ b/src/doc/en/prep/Intro-Tutorial.rst @@ -75,8 +75,9 @@ To do math in a Jupyter cell, one must do two things. .. image:: media/RunCellIcon.png :align: center - Or one can use the keyboard shortcut of holding down the Shift key - while you press the Enter key. We call this "Shift\-Enter". + Or one can use the keyboard shortcut of holding down the :kbd:`Shift` key + while you press the :kbd:`Enter` key. + We call this :kbd:`Shift` + :kbd:`Enter`. Sage prints out its response just below the cell (that's the ``4`` below, so Sage confirms that :math:`2+2=4`). Note also that Sage has @@ -365,7 +366,7 @@ Here's an example. - Still, it seems reasonable that the command might start with ``pl``. -- Then one can type ``pl`` in an input cell, and then press the tab key +- Then one can type ``pl`` in an input cell, and then press the :kbd:`Tab` key to see all the commands that start with the letters ``pl``. Try tabbing after the ``pl`` in the following cell to see all the @@ -379,7 +380,7 @@ commands that start with the letters ``pl``. You should see that sage: pl To pick one, just click on it; to stop viewing them, press the -Escape/esc key. +:kbd:`Escape` key. You can also use this to see what you can do to an expression or mathematical object. @@ -399,7 +400,7 @@ defined. sage: f(x)=x^2 -Now put your cursor after the period and press your tab key. +Now put your cursor after the period and press your :kbd:`Tab` key. .. skip @@ -407,7 +408,7 @@ Now put your cursor after the period and press your tab key. sage: f. -Again, Escape should remove the list. +Again, :kbd:`Escape` should remove the list. One of the things in that list above was ``integrate``. Let's try it. @@ -437,7 +438,7 @@ that can illustrate how to use the function. - Press tab *or* evaluate to see the documentation. To see how this help works, move your cursor after the question mark -below and press tab. +below and press :kbd:`Tab`. .. skip @@ -449,8 +450,8 @@ The examples illustrate that the syntax requires ``f.integrate(x)`` and not just ``f.integrate()``. (After all, the latter could be ambiguous if several variables had already been defined). -To stop viewing the documentation after pressing tab, you can press the -Escape key, just like with the completion of options. +To stop viewing the documentation after pressing :kbd:`Tab`, you can press the +:kbd:`Escape` key, just like with the completion of options. If you would like the documentation to be visible longer\-term, you can *evaluate* a command with the question mark (like below) to access the diff --git a/src/doc/en/prep/Symbolics-and-Basic-Plotting.rst b/src/doc/en/prep/Symbolics-and-Basic-Plotting.rst index c6da1f7c112..6e0ab69765a 100644 --- a/src/doc/en/prep/Symbolics-and-Basic-Plotting.rst +++ b/src/doc/en/prep/Symbolics-and-Basic-Plotting.rst @@ -29,7 +29,8 @@ and evaluation in Sage. We provide a (very) brief refresher. value makes sense. #. Then evaluate the cell by clicking the "evaluate" link, or by - pressing Shift\-Enter (hold down Shift while pressing the Enter key). + pressing :kbd:`Shift` + :kbd:`Enter` (hold down :kbd:`Shift` + while pressing the :kbd:`Enter` key). :: diff --git a/src/doc/en/reference/combinat/module_list.rst b/src/doc/en/reference/combinat/module_list.rst index 7a97a40e30d..e42e3891d45 100644 --- a/src/doc/en/reference/combinat/module_list.rst +++ b/src/doc/en/reference/combinat/module_list.rst @@ -339,11 +339,8 @@ Comprehensive Module List sage/combinat/species/permutation_species sage/combinat/species/product_species sage/combinat/species/recursive_species - sage/combinat/species/series - sage/combinat/species/series_order sage/combinat/species/set_species sage/combinat/species/species - sage/combinat/species/stream sage/combinat/species/structure sage/combinat/species/subset_species sage/combinat/species/sum_species 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/doc/en/reference/documentation/index.rst b/src/doc/en/reference/documentation/index.rst index 13d17594db3..4a96c47ed8c 100644 --- a/src/doc/en/reference/documentation/index.rst +++ b/src/doc/en/reference/documentation/index.rst @@ -1,6 +1,9 @@ Documentation System ==================== +Sage Doc Builders +----------------- + .. toctree:: :maxdepth: 1 @@ -10,3 +13,13 @@ Documentation System sage_docbuild/sphinxbuild sage_docbuild/conf sage_docbuild/utils + +Sphinx Extensions +----------------- + +.. toctree:: + :maxdepth: 1 + + sage_docbuild/ext/inventory_builder + sage_docbuild/ext/sage_autodoc + sage_docbuild/ext/multidocs diff --git a/src/doc/en/reference/index.rst b/src/doc/en/reference/index.rst index 9008c78e157..144b57760bc 100644 --- a/src/doc/en/reference/index.rst +++ b/src/doc/en/reference/index.rst @@ -143,23 +143,23 @@ Miscellaneous * :doc:`Databases ` * :doc:`Games ` -Programming -=========== +Infrastructure +============== -Facilities ----------- +Programming Facilities +---------------------- * :doc:`Data Structures ` * :doc:`Utilities ` * :doc:`Test Framework ` * :doc:`Parallel Computing ` +* :doc:`Python Technicalities ` -Interfaces ----------- +Subsystem Interfaces +-------------------- * :doc:`Interpreter Interfaces ` * :doc:`C/C++ Library Interfaces ` -* :doc:`Python Technicalities ` Documentation System -------------------- diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index cc87e5490cb..118f8422a04 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -3679,6 +3679,10 @@ REFERENCES: and its use for certified homotopy continuation of systems of plane algebraic curves, :arxiv:`1505.03432` +.. [Krumm2016] Daid Krumm, *Computing Points of Bounded Height in Projective Space over a Number Field*, + MATHEMATICS OF COMPUTATION, Volume 85, Number 297, January 2016, Pages 423–447. + http://dx.doi.org/10.1090/mcom/2984 + .. [KR2001] \J. Kahane and A. Ryba. *The hexad game*, Electronic Journal of Combinatorics, **8** (2001). http://www.combinatorics.org/Volume_8/Abstracts/v8i2r11.html @@ -4209,6 +4213,7 @@ REFERENCES: .. [MagmaHGM] *Hypergeometric motives* in Magma, http://magma.maths.usyd.edu.au/~watkins/papers/HGM-chapter.pdf + .. [Mar1980] Jacques Martinet, Petits discriminants des corps de nombres, Journ. Arithm. 1980, Cambridge Univ. Press, 1982, 151--193. @@ -4395,6 +4400,11 @@ REFERENCES: *Symmetric cyclotomic Hecke algebras* J. Algebra. **205** (1998) pp. 275-293. +.. [MM2008] Manel Maia and Miguel Méndez. + On the arithmetic product of combinatorial species. + Discrete Mathematics (2008), Volume 308, Issue 23, pp. 5407-5427, + :arxiv:`math/0503436v2`. + .. [MM2015] \J. Matherne and \G. Muller, *Computing upper cluster algebras*, Int. Math. Res. Not. IMRN, 2015, 3121-3149. diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py index cdcbdb584c9..b8eef385e4f 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py @@ -40,4 +40,3 @@ ('index', name + '.tex', 'Three Lectures about Explicit Methods in\nNumber Theory Using Sage', 'William Stein', 'manual'), ] - diff --git a/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst b/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst index a0c98ea3836..ee96fe1831e 100644 --- a/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst +++ b/src/doc/en/thematic_tutorials/geometry/polytope_tikz.rst @@ -15,7 +15,7 @@ paper. TikZ is a very versatile tool to draw in scientific documents and Sage can deal easily with 3-dimensional polytopes. Finally sagetex makes everything work together nicely between Sage, TikZ and LaTeX. Since version 6.3 of Sage, there is a function for (projection -of) polytopes to output a TikZ picture of the polytope. Since version 9.7 of +of) polytopes to output a TikZ picture of the polytope. Since version 9.8 of SageMath, the tikz output can be a ``TikzPicture`` object from the sage module ``sage.misc.latex_standalone``. This short tutorial shows how it all works. @@ -61,7 +61,7 @@ You can customize the polytope using the following options in the command ``P.ti - ``opacity`` : real number (default: ``0.8``) between 0 and 1 giving the opacity of the front facets, - ``axis`` : Boolean (default: ``False``) draw the axes at the origin or not. - ``output_type`` : string (default: ``None``) ``None``, ``'LatexExpr'`` or - ``'TikzPicture'``, the type of the output. Since SageMath 9.7, the value ``None`` is deprecated + ``'TikzPicture'``, the type of the output. Since SageMath 9.8, the value ``None`` is deprecated as the default value will soon be changed from ``'LatexExpr'`` to ``'TikzPicture'``. Examples @@ -90,7 +90,7 @@ When you found a good angle, follow the above procedure to obtain the values .. end of output -Note: the ``output_type='TikzPicture'`` is necessary since SagMath 9.7 to avoid +Note: the ``output_type='TikzPicture'`` is necessary since SagMath 9.8 to avoid a deprecation warning message since the default output type will soon change from a ``LatexExpr`` (Python str) to a ``TikzPicture`` object (allowing more versatility, like being able to view it directly in the Jupyter notebook). diff --git a/src/doc/en/thematic_tutorials/group_theory.rst b/src/doc/en/thematic_tutorials/group_theory.rst index ca45acf7082..9a4edca73c2 100644 --- a/src/doc/en/thematic_tutorials/group_theory.rst +++ b/src/doc/en/thematic_tutorials/group_theory.rst @@ -318,7 +318,7 @@ since `\sigma` is an odd permutation. Many more available functions that can be applied to a permutation can be found via "tab-completion." With ``sigma`` defined as an element of a permutation group, in a Sage cell, type ``sigma.`` (Note the -"``.``") and then press the tab key. You will get a list of available +"``.``") and then press the :kbd:`Tab` key. You will get a list of available functions (you may need to scroll down to see the whole list). Experiment and explore! It is what Sage is all about. You really cannot break anything. @@ -359,13 +359,13 @@ and then a variety of functions become available. After trying the examples below, experiment with tab-completion. Having defined ``H``, type ``H.`` (note the "``.``") and then press -the tab key. You will get a list of available functions (you may need +the :kbd:`Tab` key. You will get a list of available functions (you may need to scroll down to see the whole list). As before, *experiment and explore*---it is really hard to break anything. Here is another couple of ways to experiment and explore. Find a function that looks interesting, say ``is_abelian()``. Type -``H.is_abelian?`` (note the question mark) followed by the enter key. +``H.is_abelian?`` (note the question mark) followed by the :kbd:`Enter` key. This will display a portion of the source code for the ``is_abelian()`` function, describing the inputs and output, possibly illustrated with example uses. diff --git a/src/doc/en/thematic_tutorials/numerical_sage/conf.py b/src/doc/en/thematic_tutorials/numerical_sage/conf.py index 08e174fde3b..5772289f6fa 100644 --- a/src/doc/en/thematic_tutorials/numerical_sage/conf.py +++ b/src/doc/en/thematic_tutorials/numerical_sage/conf.py @@ -40,4 +40,3 @@ ('index', name + '.tex', 'Numerical Computing with Sage', 'The Sage Development Team', 'manual'), ] - diff --git a/src/doc/en/tutorial/conf.py b/src/doc/en/tutorial/conf.py index b2b525d2c2a..8a4f626f440 100644 --- a/src/doc/en/tutorial/conf.py +++ b/src/doc/en/tutorial/conf.py @@ -36,4 +36,3 @@ ('index', 'sage_tutorial.tex', 'Tutorial', 'The Sage Development Team', 'manual'), ] - diff --git a/src/doc/en/tutorial/interactive_shell.rst b/src/doc/en/tutorial/interactive_shell.rst index 7ae821e416d..4c06c6a6255 100644 --- a/src/doc/en/tutorial/interactive_shell.rst +++ b/src/doc/en/tutorial/interactive_shell.rst @@ -549,7 +549,7 @@ You can also use the following more concise notation: sage: V = QQ^3 Then it is easy to list all member functions for :math:`V` using tab -completion. Just type ``V.``, then type the ``[tab key]`` key on your +completion. Just type ``V.``, then type the :kbd:`Tab` key on your keyboard: .. skip @@ -567,7 +567,7 @@ keyboard: ... V.zero_vector -If you type the first few letters of a function, then ``[tab key]``, +If you type the first few letters of a function, then the :kbd:`Tab` key, you get only functions that begin as indicated. .. skip diff --git a/src/doc/en/tutorial/latex.rst b/src/doc/en/tutorial/latex.rst index 5c10f4ac183..b9297a1cfab 100644 --- a/src/doc/en/tutorial/latex.rst +++ b/src/doc/en/tutorial/latex.rst @@ -151,7 +151,7 @@ Customizing LaTeX Generation There are several ways to customize the actual LaTeX code generated by the ``latex()`` command. In the notebook and at the Sage command-line there is a pre-defined object named ``latex`` which has several methods, -which you can list by typing ``latex.``, followed by the tab key +which you can list by typing ``latex.``, followed by the :kbd:`Tab` key (note the period). A good example is the ``latex.matrix_delimiters`` method. It can be diff --git a/src/doc/en/tutorial/tour_help.rst b/src/doc/en/tutorial/tour_help.rst index c66c24e470b..87bce8c60e1 100644 --- a/src/doc/en/tutorial/tour_help.rst +++ b/src/doc/en/tutorial/tour_help.rst @@ -94,12 +94,11 @@ question mark: [6 3 5 1 7 2 8 9 4] [4 9 1 8 5 6 7 2 3] -Sage also provides 'Tab completion': type the first few letters of -a function and then hit the tab key. For example, if you type ``ta`` -followed by ``TAB``, Sage will print -``tachyon, tan, tanh, -taylor``. This provides a good way to find -the names of functions and other structures in Sage. +Sage also provides 'Tab completion': type the first few letters of a +function and then hit the :kbd:`Tab` key. For example, if you type +``ta`` followed by :kbd:`Tab`, Sage will print ``tachyon, tan, tanh, +taylor``. This provides a good way to find the names of functions and +other structures in Sage. .. _section-functions: diff --git a/src/doc/en/website/conf.py b/src/doc/en/website/conf.py index 1f7847b232a..099a10865c4 100644 --- a/src/doc/en/website/conf.py +++ b/src/doc/en/website/conf.py @@ -43,4 +43,3 @@ html_additional_pages = { 'index': 'index_furo.html' if html_theme == 'furo' else 'index.html', } - diff --git a/src/doc/fr/tutorial/conf.py b/src/doc/fr/tutorial/conf.py index b23aaf6841c..7208ddada17 100644 --- a/src/doc/fr/tutorial/conf.py +++ b/src/doc/fr/tutorial/conf.py @@ -45,4 +45,3 @@ # the definition of \\at in the standard preamble of the sphinx doc # conflicts with that in babel/french[b] latex_elements['preamble'] += '\\let\\at\\undefined' - diff --git a/src/doc/ja/tutorial/latex.rst b/src/doc/ja/tutorial/latex.rst index 72fa3d0e162..e02d8507eb6 100644 --- a/src/doc/ja/tutorial/latex.rst +++ b/src/doc/ja/tutorial/latex.rst @@ -124,7 +124,7 @@ LaTeXコード生成のカスタマイズ .. There are several ways to customize the actual LaTeX code generated by .. the ``latex()`` command. In the notebook and at the Sage command-line .. there is a pre-defined object named ``latex`` which has several methods, -.. which you can list by typing ``latex.``, followed by the tab key +.. which you can list by typing ``latex.``, followed by the :kbd:`Tab` key .. (note the period). ここでは ``latex.matrix_delimiters`` メソッドに注目してみよう. diff --git a/src/doc/ru/tutorial/conf.py b/src/doc/ru/tutorial/conf.py index c237e769ed4..0b7a8c4e3db 100644 --- a/src/doc/ru/tutorial/conf.py +++ b/src/doc/ru/tutorial/conf.py @@ -41,4 +41,3 @@ # Additional LaTeX stuff if necessary: #latex_elements['preamble'] += '\\DeclareUnicodeCharacter{00A0}{\\nobreakspace}\n' - diff --git a/src/doc/tr/a_tour_of_sage/conf.py b/src/doc/tr/a_tour_of_sage/conf.py index adb526f1c78..f969a1b516a 100644 --- a/src/doc/tr/a_tour_of_sage/conf.py +++ b/src/doc/tr/a_tour_of_sage/conf.py @@ -35,7 +35,6 @@ # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [ - ('index', name+'.tex', 'Sage Turu', + ('index', name + '.tex', 'Sage Turu', 'The Sage Development Team', 'manual'), ] - diff --git a/src/sage/algebras/catalog.py b/src/sage/algebras/catalog.py index cce33d64029..1ccf517e2c0 100644 --- a/src/sage/algebras/catalog.py +++ b/src/sage/algebras/catalog.py @@ -6,7 +6,7 @@ easy way to discover and quickly create the algebras that are available (as listed here). -Let ```` indicate pressing the tab key. So begin by typing +Let ```` indicate pressing the :kbd:`Tab` key. So begin by typing ``algebras.`` to the see the currently implemented named algebras. - :class:`algebras.AlternatingCentralExtensionQuantumOnsager @@ -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/cellular_basis.py b/src/sage/algebras/cellular_basis.py index 9e484492954..42ce84307d5 100644 --- a/src/sage/algebras/cellular_basis.py +++ b/src/sage/algebras/cellular_basis.py @@ -1,4 +1,4 @@ -r""" +r""" Cellular Basis ============== 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/clifford_algebra_element.pyx b/src/sage/algebras/clifford_algebra_element.pyx index e065b6b70b9..c52a022e139 100644 --- a/src/sage/algebras/clifford_algebra_element.pyx +++ b/src/sage/algebras/clifford_algebra_element.pyx @@ -982,4 +982,3 @@ cdef class CohomologyRAAGElement(CliffordAlgebraElement): del d[tp] return self.__class__(self._parent, d) - diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index 98e338d3468..cdd445e7253 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: @@ -715,4 +715,3 @@ cdef class GroebnerStrategyDegLex(GroebnerStrategy): from sage.combinat.combination import from_rank return FrozenBitset(from_rank(n, self.rank, deg)) - diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx index 60148f063c4..b0ae904d3d2 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra_element.pyx @@ -640,4 +640,3 @@ cdef class FiniteDimensionalAlgebraElement(AlgebraElement): True """ return self.matrix().characteristic_polynomial() - 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/jordan_algebra.py b/src/sage/algebras/jordan_algebra.py index 0923934c514..f5824069797 100644 --- a/src/sage/algebras/jordan_algebra.py +++ b/src/sage/algebras/jordan_algebra.py @@ -397,7 +397,7 @@ def _latex_(self): from sage.misc.latex import latex return latex(self._x) - def __bool__(self): + def __bool__(self) -> bool: """ Return if ``self`` is non-zero. @@ -411,8 +411,6 @@ def __bool__(self): """ return bool(self._x) - - def __eq__(self, other): """ Check equality. @@ -817,7 +815,7 @@ def _latex_(self): from sage.misc.latex import latex return "{} + {}".format(latex(self._s), latex(self._v)) - def __bool__(self): + def __bool__(self) -> bool: """ Return if ``self`` is non-zero. @@ -834,8 +832,6 @@ def __bool__(self): """ return bool(self._s) or bool(self._v) - - def __eq__(self, other): """ Check equality. diff --git a/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx b/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx index fc1d43c574c..41444812c49 100644 --- a/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx +++ b/src/sage/algebras/letterplace/free_algebra_element_letterplace.pyx @@ -107,9 +107,9 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(QQ, implementation='letterplace') sage: loads(dumps(x*y*x)) == x*y*x # indirect doctest True - """ - return self.__class__, (self._parent,self._poly) + return self.__class__, (self._parent, self._poly) + def __copy__(self): """ TESTS:: @@ -117,10 +117,10 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(QQ, implementation='letterplace') sage: copy(x*y*z+z*y*x) == x*y*z+z*y*x # indirect doctest True - """ self._poly = (self._parent)._current_ring(self._poly) - return self.__class__(self._parent,self._poly,check=False) + return self.__class__(self._parent, self._poly, check=False) + def __hash__(self): """ TESTS:: @@ -128,7 +128,6 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(QQ, implementation='letterplace') sage: set([x*y*z, z*y+x*z,x*y*z]) # indirect doctest {x*z + z*y, x*y*z} - """ return hash(self._poly) @@ -163,66 +162,65 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): w + (z + 1)*x - y sage: print(a+b*(z+1)-c) a + (z + 1)*b - c - """ cdef list L = [] cdef FreeAlgebra_letterplace P = self._parent cdef int ngens = P.__ngens if P._base._repr_option('element_is_atomic'): - for E,c in zip(self._poly.exponents(),self._poly.coefficients()): + for E, c in zip(self._poly.exponents(), self._poly.coefficients()): monstr = P.exponents_to_string(E) if monstr: - if c==1: + if c == 1: if L: - L.extend(['+',monstr]) + L.extend(['+', monstr]) else: L.append(monstr) - elif c==-1: + elif c == -1: if L: - L.extend(['-',monstr]) + L.extend(['-', monstr]) else: - L.append('-'+monstr) + L.append('-' + monstr) else: if L: - if c>=0: - L.extend(['+',repr(c)+'*'+monstr]) + if c >= 0: + L.extend(['+', repr(c) + '*' + monstr]) else: - L.extend(['-',repr(-c)+'*'+monstr]) + L.extend(['-', repr(-c) + '*' + monstr]) else: - L.append(repr(c)+'*'+monstr) + L.append(repr(c) + '*' + monstr) else: - if c>=0: + if c >= 0: if L: - L.extend(['+',repr(c)]) + L.extend(['+', repr(c)]) else: L.append(repr(c)) else: if L: - L.extend(['-',repr(-c)]) + L.extend(['-', repr(-c)]) else: L.append(repr(c)) else: - for E,c in zip(self._poly.exponents(),self._poly.coefficients()): + for E, c in zip(self._poly.exponents(), self._poly.coefficients()): monstr = P.exponents_to_string(E) if monstr: - if c==1: + if c == 1: if L: - L.extend(['+',monstr]) + L.extend(['+', monstr]) else: L.append(monstr) - elif c==-1: + elif c == -1: if L: - L.extend(['-',monstr]) + L.extend(['-', monstr]) else: - L.append('-'+monstr) + L.append('-' + monstr) else: if L: - L.extend(['+','('+repr(c)+')*'+monstr]) + L.extend(['+', '(' + repr(c) + ')*' + monstr]) else: - L.append('('+repr(c)+')*'+monstr) + L.append('(' + repr(c) + ')*' + monstr) else: if L: - L.extend(['+',repr(c)]) + L.extend(['+', repr(c)]) else: L.append(repr(c)) if L: @@ -245,60 +243,60 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): cdef int ngens = P.__ngens from sage.misc.latex import latex if P._base._repr_option('element_is_atomic'): - for E,c in zip(self._poly.exponents(),self._poly.coefficients()): + for E, c in zip(self._poly.exponents(), self._poly.coefficients()): monstr = P.exponents_to_latex(E) if monstr: - if c==1: + if c == 1: if L: - L.extend(['+',monstr]) + L.extend(['+', monstr]) else: L.append(monstr) - elif c==-1: + elif c == -1: if L: - L.extend(['-',monstr]) + L.extend(['-', monstr]) else: - L.append('-'+monstr) + L.append('-' + monstr) else: if L: - if c>=0: - L.extend(['+',repr(latex(c))+' '+monstr]) + if c >= 0: + L.extend(['+', repr(latex(c)) + ' ' + monstr]) else: - L.extend(['-',repr(latex(-c))+' '+monstr]) + L.extend(['-', repr(latex(-c)) + ' ' + monstr]) else: - L.append(repr(latex(c))+' '+monstr) + L.append(repr(latex(c)) + ' ' + monstr) else: - if c>=0: + if c >= 0: if L: - L.extend(['+',repr(latex(c))]) + L.extend(['+', repr(latex(c))]) else: L.append(repr(latex(c))) else: if L: - L.extend(['-',repr(latex(-c))]) + L.extend(['-', repr(latex(-c))]) else: L.append(repr(c)) else: - for E,c in zip(self._poly.exponents(),self._poly.coefficients()): + for E, c in zip(self._poly.exponents(), self._poly.coefficients()): monstr = P.exponents_to_latex(E) if monstr: - if c==1: + if c == 1: if L: - L.extend(['+',monstr]) + L.extend(['+', monstr]) else: L.append(monstr) - elif c==-1: + elif c == -1: if L: - L.extend(['-',monstr]) + L.extend(['-', monstr]) else: - L.append('-'+monstr) + L.append('-' + monstr) else: if L: - L.extend(['+','\\left('+repr(latex(c))+'\\right) '+monstr]) + L.extend(['+', '\\left(' + repr(latex(c)) + '\\right) ' + monstr]) else: - L.append('\\left('+repr(latex(c))+'\\right) '+monstr) + L.append('\\left(' + repr(latex(c)) + '\\right) ' + monstr) else: if L: - L.extend(['+',repr(latex(c))]) + L.extend(['+', repr(latex(c))]) else: L.append(repr(latex(c))) if L: @@ -309,10 +307,10 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): """ Return the degree of this element. - NOTE: + .. NOTE:: - Generators may have a positive integral degree weight. All - elements must be weighted homogeneous. + Generators may have a positive integral degree weight. All + elements must be weighted homogeneous. EXAMPLES:: @@ -322,7 +320,6 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) sage: ((x*y+z)^3).degree() 9 - """ return self._poly.degree() @@ -342,7 +339,6 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) sage: ((x*y+z)^2).letterplace_polynomial() x*x__1*y_2*x_3*x__4*y_5 + x*x__1*y_2*z_3*x__4*x__5 + z*x__1*x__2*x_3*x__4*y_5 + z*x__1*x__2*z_3*x__4*x__5 - """ return self._poly @@ -358,7 +354,6 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) sage: ((2*x*y+z)^2).lm() x*y*x*y - """ return FreeAlgebraElement_letterplace(self._parent, self._poly.lm()) @@ -375,7 +370,6 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) sage: ((2*x*y+z)^2).lt() 4*x*y*x*y - """ return FreeAlgebraElement_letterplace(self._parent, self._poly.lt()) @@ -394,7 +388,6 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) sage: ((2*x*y+z)^2).lc() 4 - """ return self._poly.lc() @@ -407,7 +400,6 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): True sage: bool(F.zero()) False - """ return bool(self._poly) @@ -416,10 +408,10 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): Tell whether or not the leading monomial of self divides the leading monomial of another element. - NOTE: + .. NOTE:: - A free algebra element `p` divides another one `q` if there are - free algebra elements `s` and `t` such that `spt = q`. + A free algebra element `p` divides another one `q` if there are + free algebra elements `s` and `t` such that `spt = q`. EXAMPLES:: @@ -430,7 +422,6 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): y*x*y sage: (y*x*y-y^4).lm_divides((2*x*y+z)^2*z) True - """ if self._parent is not p._parent: raise TypeError("the two arguments must be elements in the same free algebra") @@ -440,16 +431,16 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): s_poly = self._poly = P(self._poly) cdef int p_d = p_poly.degree() cdef int s_d = s_poly.degree() - if s_d>p_d: + if s_d > p_d: return False cdef int i - if P.monomial_divides(s_poly,p_poly): + if P.monomial_divides(s_poly, p_poly): return True realngens = A._commutative_ring.ngens() CG = CyclicPermutationGroup(P.ngens()) - for i from 0 <= i < p_d-s_d: + for i in range(p_d - s_d): s_poly = s_poly * CG[realngens] - if P.monomial_divides(s_poly,p_poly): + if P.monomial_divides(s_poly, p_poly): return True return False @@ -469,7 +460,7 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): return PyObject_RichCompare(left, right, op) ################################ - ## Arithmetic + # Arithmetic cpdef _neg_(self): """ TESTS:: @@ -483,7 +474,9 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): -3*x*y - 2*z*z """ - return FreeAlgebraElement_letterplace(self._parent,-self._poly,check=False) + return FreeAlgebraElement_letterplace(self._parent, -self._poly, + check=False) + cpdef _add_(self, other): """ Addition, under the side condition that either one summand @@ -502,20 +495,21 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): x sage: 0+x x - """ if not other: return self if not self: return other cdef FreeAlgebraElement_letterplace right = other - if right._poly.degree()!=self._poly.degree(): + if right._poly.degree() != self._poly.degree(): raise ArithmeticError("can only add elements of the same weighted degree") # update the polynomials cdef FreeAlgebra_letterplace A = self._parent self._poly = A._current_ring(self._poly) right._poly = A._current_ring(right._poly) - return FreeAlgebraElement_letterplace(self._parent,self._poly+right._poly,check=False) + return FreeAlgebraElement_letterplace(self._parent, + self._poly + right._poly, + check=False) cpdef _sub_(self, other): """ @@ -541,20 +535,21 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) sage: x*y+z x*y + z - """ if not other: return self if not self: return -other cdef FreeAlgebraElement_letterplace right = other - if right._poly.degree()!=self._poly.degree(): + if right._poly.degree() != self._poly.degree(): raise ArithmeticError("can only subtract elements of the same degree") # update the polynomials cdef FreeAlgebra_letterplace A = self._parent self._poly = A._current_ring(self._poly) right._poly = A._current_ring(right._poly) - return FreeAlgebraElement_letterplace(self._parent,self._poly-right._poly,check=False) + return FreeAlgebraElement_letterplace(self._parent, + self._poly - right._poly, + check=False) cpdef _lmul_(self, Element right): """ @@ -566,9 +561,10 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(K, implementation='letterplace') sage: (a+b)*(z+1) # indirect doctest (z + 1)*a + (z + 1)*b - """ - return FreeAlgebraElement_letterplace(self._parent,self._poly._lmul_(right),check=False) + return FreeAlgebraElement_letterplace(self._parent, + self._poly._lmul_(right), + check=False) cpdef _rmul_(self, Element left): """ @@ -580,9 +576,10 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(K, implementation='letterplace') sage: (z+1)*(a+b) # indirect doctest (z + 1)*a + (z + 1)*b - """ - return FreeAlgebraElement_letterplace(self._parent,self._poly._rmul_(left),check=False) + return FreeAlgebraElement_letterplace(self._parent, + self._poly._rmul_(left), + check=False) cpdef _mul_(self, other): """ @@ -598,14 +595,15 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): cdef FreeAlgebraElement_letterplace left = self cdef FreeAlgebraElement_letterplace right = other cdef FreeAlgebra_letterplace A = left._parent - A.set_degbound(left._poly.degree()+right._poly.degree()) + A.set_degbound(left._poly.degree() + right._poly.degree()) # we must put the polynomials into the same ring left._poly = A._current_ring(left._poly) right._poly = A._current_ring(right._poly) realngens = A._commutative_ring.ngens() CG = CyclicPermutationGroup(A._current_ring.ngens()) rshift = right._poly * CG[left._poly.degree() * realngens] - return FreeAlgebraElement_letterplace(A,left._poly*rshift, check=False) + return FreeAlgebraElement_letterplace(A, left._poly * rshift, + check=False) def __pow__(FreeAlgebraElement_letterplace self, int n, k): """ @@ -615,30 +613,29 @@ cdef class FreeAlgebraElement_letterplace(AlgebraElement): sage: F. = FreeAlgebra(K, implementation='letterplace') sage: (a+z*b)^3 # indirect doctest a*a*a + (z)*a*a*b + (z)*a*b*a + (z + 3)*a*b*b + (z)*b*a*a + (z + 3)*b*a*b + (z + 3)*b*b*a + (4*z + 3)*b*b*b - """ cdef FreeAlgebra_letterplace A = self._parent - if n<0: + if n < 0: raise ValueError("negative exponents are not allowed") - if n==0: + if n == 0: return FreeAlgebraElement_letterplace(A, A._current_ring(1), check=False) - if n==1: + if n == 1: return self - A.set_degbound(self._poly.degree()*n) - cdef MPolynomial_libsingular p,q + A.set_degbound(self._poly.degree() * n) + cdef MPolynomial_libsingular p, q self._poly = A._current_ring(self._poly) cdef int d = self._poly.degree() q = p = self._poly realngens = A._commutative_ring.ngens() cdef int i CG = CyclicPermutationGroup(A._current_ring.ngens()) - for i from 0 # Distributed under the terms of the GNU General Public License (GPL), # version 2 or any later version. The full text of the GPL is available at: -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # ############################################################################### @@ -133,13 +133,13 @@ freeAlgebra = singular_function("freeAlgebra") # unfortunately we cannot set Singular attributes for MPolynomialRing_libsingular # Hence, we must constantly work around Letterplace's sanity checks, # and cannot use the following library functions: -#set_letterplace_attributes = singular_function("setLetterplaceAttributes") -#lpMult = singular_function("lpMult") +# set_letterplace_attributes = singular_function("setLetterplaceAttributes") +# lpMult = singular_function("lpMult") ##################### -# Auxiliar functions +# Auxiliary functions -cdef MPolynomialRing_libsingular make_letterplace_ring(base_ring,blocks): +cdef MPolynomialRing_libsingular make_letterplace_ring(base_ring, blocks): """ Create a polynomial ring in block order. @@ -177,7 +177,6 @@ cdef MPolynomialRing_libsingular make_letterplace_ring(base_ring,blocks): Block term order with blocks: (Lexicographic term order of length 3, Lexicographic term order of length 3) - """ n = base_ring.ngens() T0 = base_ring.term_order() @@ -185,11 +184,11 @@ cdef MPolynomialRing_libsingular make_letterplace_ring(base_ring,blocks): cdef i cdef tuple names0 = base_ring.variable_names() cdef list names = list(names0) - for i from 1<=i = FreeAlgebra(K, implementation='letterplace') sage: loads(dumps(F)) is F # indirect doctest True - """ from sage.algebras.free_algebra import FreeAlgebra - if self._nb_slackvars==0: - return FreeAlgebra,(self._commutative_ring,) - return FreeAlgebra,(self._commutative_ring,None,None,None,None,None,None,None,self._degrees) + if self._nb_slackvars == 0: + return FreeAlgebra, (self._commutative_ring,) + return FreeAlgebra, (self._commutative_ring, None, None, None, + None, None, None, None, self._degrees) + # Small methods def ngens(self): """ @@ -307,10 +307,10 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: F. = FreeAlgebra(QQ, implementation='letterplace') sage: F.ngens() 3 - """ - return self.__ngens-self._nb_slackvars - def gen(self,i): + return self.__ngens - self._nb_slackvars + + def gen(self, i): """ Return the `i`-th generator. @@ -329,21 +329,21 @@ cdef class FreeAlgebra_letterplace(Algebra): True sage: F.gen(2) c - """ - if i>=self.__ngens-self._nb_slackvars: + if i >= self.__ngens - self._nb_slackvars: raise ValueError("this free algebra only has %d generators" % (self.__ngens - self._nb_slackvars)) if self._gens is not None: return self._gens[i] deg = self._degrees[i] - #self.set_degbound(deg) + # self.set_degbound(deg) p = self._current_ring.gen(i) cdef int n - cdef int j = self.__ngens-1 - for n from 1<=n = FreeAlgebra(QQ, implementation='letterplace',order='lex') sage: L.term_order_of_block() Lexicographic term order - """ return self._commutative_ring.term_order() @@ -416,27 +415,25 @@ cdef class FreeAlgebra_letterplace(Algebra): False sage: FreeAlgebra(QQ, implementation='letterplace', names=['x']).is_commutative() True - """ - return self.__ngens-self._nb_slackvars <= 1 + return self.__ngens - self._nb_slackvars <= 1 def is_field(self, proof=True): """ Tell whether this free algebra is a field. - NOTE: + .. NOTE:: - This would only be the case in the degenerate case of no generators. - But such an example cannot be constructed in this implementation. + This would only be the case in the degenerate case of no generators. + But such an example cannot be constructed in this implementation. TESTS:: sage: F. = FreeAlgebra(QQ, implementation='letterplace') sage: F.is_field() False - """ - return (not (self.__ngens-self._nb_slackvars)) and self._base.is_field(proof=proof) + return (not (self.__ngens - self._nb_slackvars)) and self._base.is_field(proof=proof) def _repr_(self): """ @@ -451,10 +448,8 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: F. = FreeAlgebra(QQ, implementation='letterplace', degrees=[2,1,3]) sage: F Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field - - """ - return "Free Associative Unital Algebra on %d generators %s over %s"%(self.__ngens-self._nb_slackvars,self.gens(),self._base) + return "Free Associative Unital Algebra on %d generators %s over %s" % (self.__ngens - self._nb_slackvars, self.gens(), self._base) def _latex_(self): r""" @@ -467,17 +462,17 @@ cdef class FreeAlgebra_letterplace(Algebra): \Bold{Q}\langle \mathit{bla}, \alpha, z\rangle """ from sage.misc.latex import latex - return "%s\\langle %s\\rangle"%(latex(self.base_ring()),', '.join(self.latex_variable_names())) + return "%s\\langle %s\\rangle" % (latex(self.base_ring()), ', '.join(self.latex_variable_names())) def degbound(self): """ Return the degree bound that is currently used. - NOTE: + .. NOTE:: - When multiplying two elements of this free algebra, the degree - bound will be dynamically adapted. It can also be set by - :meth:`set_degbound`. + When multiplying two elements of this free algebra, the degree + bound will be dynamically adapted. It can also be set by + :meth:`set_degbound`. EXAMPLES: @@ -495,16 +490,16 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: F.set_degbound(4) sage: F.degbound() 4 - """ return self._degbound - def set_degbound(self,d): + + def set_degbound(self, d): """ Increase the degree bound that is currently in place. - NOTE: + .. NOTE:: - The degree bound cannot be decreased. + The degree bound cannot be decreased. EXAMPLES: @@ -525,19 +520,18 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: F.set_degbound(2) sage: F.degbound() 4 - """ - if d<=self._degbound: + if d <= self._degbound: return self._degbound = d - self._current_ring = make_letterplace_ring(self._commutative_ring,d) + self._current_ring = make_letterplace_ring(self._commutative_ring, d) # def base_extend(self, R): # if self._base.has_coerce_map_from(R): # return self ################################################ - ## Ideals + # Ideals def _ideal_class_(self, n=0): """ @@ -551,7 +545,6 @@ cdef class FreeAlgebra_letterplace(Algebra): Right Ideal (x*y + y*z, x*x + x*y - y*x - y*y) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field sage: type(I) is F._ideal_class_() True - """ from sage.algebras.letterplace.letterplace_ideal import LetterplaceIdeal return LetterplaceIdeal @@ -567,7 +560,6 @@ cdef class FreeAlgebra_letterplace(Algebra): Monoid of ideals of Free Associative Unital Algebra on 2 generators (x, y) over Finite Field of size 2 sage: F.ideal_monoid() is F.ideal_monoid() True - """ if self.__monoid is None: self.__monoid = IdealMonoid_nc(self) @@ -591,16 +583,15 @@ cdef class FreeAlgebra_letterplace(Algebra): sage: from sage.algebras.letterplace.free_algebra_element_letterplace import FreeAlgebraElement_letterplace sage: P = F.commutative_ring() sage: FreeAlgebraElement_letterplace(F, P.0*P.1^2+P.1^3) # indirect doctest - ) failed: NotImplementedError: + ) failed: NotImplementedError: Apparently you tried to view the letterplace algebra with shift-multiplication as the free algebra over a finitely generated free abelian monoid. In principle, this is correct, but it is not implemented, yet.> - """ cdef int ngens = self.__ngens - cdef int nblocks = len(E)/ngens - cdef int i,j,base, exp, var_ind + cdef int nblocks = len(E) // ngens + cdef int i, j, base, exp, var_ind cdef list out = [] cdef list tmp for i from 0<=i1 or exp>1: + if len(tmp) > 1 or exp > 1: raise NotImplementedError("\n Apparently you tried to view the letterplace algebra with\n shift-multiplication as the free algebra over a finitely\n generated free abelian monoid.\n In principle, this is correct, but it is not implemented, yet.") out.append(self._names[var_ind]) @@ -631,8 +622,8 @@ cdef class FreeAlgebra_letterplace(Algebra): \left(2 z + 1\right) a b a b + \left(z + 1\right) a b c + \left(z + 1\right) c a b - c c """ cdef int ngens = self.__ngens - cdef int nblocks = len(E)/ngens - cdef int i,j,base, exp, var_ind + cdef int nblocks = len(E) // ngens + cdef int i, j, base, exp, var_ind cdef list out = [] cdef list tmp cdef list names = self.latex_variable_names() @@ -642,11 +633,11 @@ cdef class FreeAlgebra_letterplace(Algebra): if not tmp: continue var_ind, exp = tmp[0] - if len(tmp)>1 or exp>1: + if len(tmp) > 1 or exp > 1: raise NotImplementedError("\n Apparently you tried to view the letterplace algebra with\n shift-multiplication as the free algebra over a finitely\n generated free abelian monoid.\n In principle, this is correct, but it is not implemented, yet.") out.append(names[var_ind]) - i += (self._degrees[var_ind]-1) + i += (self._degrees[var_ind] - 1) return ' '.join(out) def _reductor_(self, g, d): @@ -686,7 +677,6 @@ cdef class FreeAlgebra_letterplace(Algebra): y*y_1*y_2 - y*y_1*z_2 + y*z_1*y_2 - y*z_1*z_2 sage: p.reduce(I).letterplace_polynomial() == q True - """ cdef list out = [] C = self.current_ring() @@ -697,12 +687,13 @@ cdef class FreeAlgebra_letterplace(Algebra): from sage.groups.perm_gps.all import CyclicPermutationGroup CG = CyclicPermutationGroup(C.ngens()) for y in G: - out.extend([y]+[y * CG[ngens*(n+1)] for n in xrange(d-y.degree())]) + out.extend([y] + [y * CG[ngens * (n + 1)] + for n in range(d - y.degree())]) return C.ideal(out) ########################### - ## Coercion - cpdef _coerce_map_from_(self,S): + # Coercion + cpdef _coerce_map_from_(self, S): """ A ring ``R`` coerces into self, if @@ -729,7 +720,7 @@ cdef class FreeAlgebra_letterplace(Algebra): t*x """ - if self==S or self._current_ring.has_coerce_map_from(S): + if self == S or self._current_ring.has_coerce_map_from(S): return True cdef int i # Do we have another letterplace algebra? @@ -747,7 +738,7 @@ cdef class FreeAlgebra_letterplace(Algebra): # Do the degrees match degs = self._degrees Sdegs = (S)._degrees - for i from 0<=i = FreeAlgebra(QQ, implementation='letterplace') sage: F.an_element() # indirect doctest x - """ return FreeAlgebraElement_letterplace(self, self._current_ring.an_element(), check=False) @@ -825,11 +815,11 @@ cdef class FreeAlgebra_letterplace(Algebra): l = len(e) break cdef dict out = {} - self.set_degbound(l/self.__ngens) + self.set_degbound(l // self.__ngens) cdef Py_ssize_t n = self._current_ring.ngens() for e, c in D.iteritems(): - out[tuple(e) + (0,)*(n-l)] = c - return FreeAlgebraElement_letterplace(self,self._current_ring(out), + out[tuple(e) + (0,) * (n - l)] = c + return FreeAlgebraElement_letterplace(self, self._current_ring(out), check=check) def _element_constructor_(self, x): @@ -875,7 +865,7 @@ cdef class FreeAlgebra_letterplace(Algebra): """ if isinstance(x, basestring): from sage.misc.sage_eval import sage_eval - return sage_eval(x,locals=self.gens_dict()) + return sage_eval(x, locals=self.gens_dict()) try: P = x.parent() except AttributeError: @@ -890,9 +880,10 @@ cdef class FreeAlgebra_letterplace(Algebra): Names = self._current_ring.variable_names() PNames = list(Ppoly.variable_names()) # translate the slack variables - PNames[P.ngens(): len(PNames): P.ngens()+1] = list(Names[self.ngens(): len(Names): self.ngens()+1])[:P.degbound()] + PNames[P.ngens(): len(PNames): P.ngens() + 1] = list(Names[self.ngens(): len(Names): self.ngens() + 1])[:P.degbound()] x = Ppoly.hom([Gens[Names.index(asdf)] for asdf in PNames])(x.letterplace_polynomial()) - return FreeAlgebraElement_letterplace(self,self._current_ring(x)) + return FreeAlgebraElement_letterplace(self, self._current_ring(x)) + cdef class FreeAlgebra_letterplace_libsingular(): """ diff --git a/src/sage/algebras/letterplace/letterplace_ideal.pyx b/src/sage/algebras/letterplace/letterplace_ideal.pyx index 56ec1c3d399..747ba2ca6e0 100644 --- a/src/sage/algebras/letterplace/letterplace_ideal.pyx +++ b/src/sage/algebras/letterplace/letterplace_ideal.pyx @@ -1,9 +1,8 @@ """ Homogeneous ideals of free algebras -For twosided ideals and when the base ring is a field, this -implementation also provides Groebner bases and ideal containment -tests. +For twosided ideals and when the base ring is a field, this implementation +also provides Groebner bases and ideal containment tests. EXAMPLES:: @@ -31,9 +30,7 @@ forms and can test containment in the ideal:: AUTHOR: - Simon King (2011-03-22): See :trac:`7797`. - """ - # **************************************************************************** # Copyright (C) 2011 Simon King # @@ -43,7 +40,6 @@ AUTHOR: # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.rings.noncommutative_ideals import Ideal_nc from sage.libs.singular.function import lib, singular_function from sage.algebras.letterplace.free_algebra_letterplace cimport FreeAlgebra_letterplace, FreeAlgebra_letterplace_libsingular @@ -53,8 +49,9 @@ from sage.rings.infinity import Infinity ##################### # Define some singular functions lib("freegb.lib") -singular_twostd=singular_function("twostd") -poly_reduce=singular_function("NF") +singular_twostd = singular_function("twostd") +poly_reduce = singular_function("NF") + class LetterplaceIdeal(Ideal_nc): """ @@ -159,7 +156,6 @@ class LetterplaceIdeal(Ideal_nc): 0 sage: (z*I.0-x*y*z).normal_form(I) -y*x*z + z*z - """ def __init__(self, ring, gens, coerce=True, side="twosided"): """ @@ -198,6 +194,7 @@ class LetterplaceIdeal(Ideal_nc): Ideal_nc.__init__(self, ring, gens, coerce=coerce, side=side) self.__GB = self self.__uptodeg = 0 + def groebner_basis(self, degbound=None): """ Twosided Groebner basis with degree bound. @@ -287,17 +284,18 @@ class LetterplaceIdeal(Ideal_nc): return self.__GB if not A.base().is_field(): raise TypeError("Currently, we can only compute Groebner bases if the ring of coefficients is a field") - if self.side()!='twosided': + if self.side() != 'twosided': raise TypeError("This ideal is not two-sided. We can only compute two-sided Groebner bases") if degbound == Infinity: - while self.__uptodeg= 2*max([x._poly.degree() for x in out]): + self.__GB = A.ideal(out, side='twosided', coerce=False) + if degbound >= 2 * max([x._poly.degree() for x in out]): degbound = Infinity self.__uptodeg = degbound self.__GB.__uptodeg = degbound return self.__GB - def __contains__(self,x): + def __contains__(self, x): """ The containment test is based on a normal form computation. @@ -349,7 +347,6 @@ class LetterplaceIdeal(Ideal_nc): True sage: 1 in I False - """ R = self.ring() return (x in R) and R(x).normal_form(self).is_zero() @@ -384,25 +381,26 @@ class LetterplaceIdeal(Ideal_nc): Twosided Ideal (y*z, x*x - y*x - y*y) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field sage: I.reduce(F*[x^2+x*y,y^2+y*z]*F) Twosided Ideal (x*y + y*z, -y*x + y*z) of Free Associative Unital Algebra on 3 generators (x, y, z) over Rational Field - """ P = self.ring() - if not isinstance(G,(list,tuple)): - if G==P: + if not isinstance(G, (list, tuple)): + if G == P: return P.ideal([P.zero()]) if G in P: return G.normal_form(self) G = G.gens() C = P.current_ring() - sI = C.ideal([C(X.letterplace_polynomial()) for X in self.gens()], coerce=False) + sI = C.ideal([C(X.letterplace_polynomial()) for X in self.gens()], + coerce=False) selfdeg = max([x.degree() for x in sI.gens()]) gI = P._reductor_(G, selfdeg) from sage.libs.singular.option import LibSingularOptions libsingular_options = LibSingularOptions() - bck = (libsingular_options['redTail'],libsingular_options['redSB']) + bck = (libsingular_options['redTail'], libsingular_options['redSB']) libsingular_options['redTail'] = True libsingular_options['redSB'] = True - sI = poly_reduce(sI,gI, ring=C, attributes={gI:{"isSB":1}}) + sI = poly_reduce(sI, gI, ring=C, attributes={gI: {"isSB": 1}}) libsingular_options['redTail'] = bck[0] libsingular_options['redSB'] = bck[1] - return P.ideal([FreeAlgebraElement_letterplace(P,x,check=False) for x in sI], coerce=False) + return P.ideal([FreeAlgebraElement_letterplace(P, x, check=False) + for x in sI], coerce=False) diff --git a/src/sage/algebras/lie_algebras/classical_lie_algebra.py b/src/sage/algebras/lie_algebras/classical_lie_algebra.py index 1ae47fa7a31..39f7be6c856 100644 --- a/src/sage/algebras/lie_algebras/classical_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/classical_lie_algebra.py @@ -1332,7 +1332,7 @@ def _unicode_art_(self): from sage.typeset.unicode_art import unicode_art return unicode_art(self._combined_matrix()) - def __bool__(self): + def __bool__(self) -> bool: r""" Return if ``self`` is nonzero. @@ -1346,8 +1346,6 @@ def __bool__(self): """ return bool(self._real) or bool(self._imag) - - def __hash__(self): r""" Return the hash of ``self``. diff --git a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx index bb2859ba6bd..ffe27c69797 100644 --- a/src/sage/algebras/lie_algebras/lie_algebra_element.pyx +++ b/src/sage/algebras/lie_algebras/lie_algebra_element.pyx @@ -1997,4 +1997,3 @@ cdef class LyndonBracket(GradedLieBracket): if self._hash == -1: self._hash = hash(self._index_word) return self._hash - 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/quatalg/quaternion_algebra_cython.pyx b/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx index 88f65813eac..0d110aad7e3 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx +++ b/src/sage/algebras/quatalg/quaternion_algebra_cython.pyx @@ -260,5 +260,3 @@ def rational_quaternions_from_integral_matrix_and_denom(A, Matrix_integer_dense v.append(x) mpz_clear(tmp) return v - - 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/calculus/calculus.py b/src/sage/calculus/calculus.py index 76cd8986123..00da3f9d4af 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -2252,7 +2252,6 @@ def symbolic_expression_from_maxima_string(x, equals_sub=False, maxima=maxima): sage: sefms("x # 3") == SR(x != 3) True sage: solve([x != 5], x) - #0: solve_rat_ineq(ineq=_SAGE_VAR_x # 5) [[x - 5 != 0]] sage: solve([2*x==3, x != 5], x) [[x == (3/2), (-7/2) != 0]] diff --git a/src/sage/categories/additive_magmas.py b/src/sage/categories/additive_magmas.py index e81dcf9d4b9..8d2c46d0771 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:: @@ -730,7 +730,7 @@ def is_empty(self): TESTS: - We check that the method `is_empty` is inherited from this + We check that the method ``is_empty`` is inherited from this category in both examples above:: sage: A.is_empty.__module__ 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/category.py b/src/sage/categories/category.py index eef5e7acc70..02f4b292f42 100644 --- a/src/sage/categories/category.py +++ b/src/sage/categories/category.py @@ -2236,7 +2236,7 @@ def _sort(categories): .. NOTE:: - The auxiliary function `_flatten_categories` used in the test + The auxiliary function ``_flatten_categories`` used in the test below expects a second argument, which is a type such that instances of that type will be replaced by its super categories. Usually, this type is :class:`JoinCategory`. 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/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 0aacd2aeda5..c4f4cdab349 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -668,7 +668,7 @@ def _test_reduced_word(self, **options): def simple_projection(self, i, side='right', length_increasing=True): r""" - Return the simple projection `\pi_i` (or `\overline\pi_i` if `length_increasing` is ``False``). + Return the simple projection `\pi_i` (or `\overline\pi_i` if ``length_increasing`` is ``False``). INPUT: diff --git a/src/sage/categories/crystals.py b/src/sage/categories/crystals.py index 1cfbf9175ab..980bebc9f84 100644 --- a/src/sage/categories/crystals.py +++ b/src/sage/categories/crystals.py @@ -1563,7 +1563,9 @@ def to_highest_weight(self, index_set=None): r""" Return the highest weight element `u` and a list `[i_1,...,i_k]` such that `self = f_{i_1} ... f_{i_k} u`, where `i_1,...,i_k` are - elements in `index_set`. By default the index set is assumed to be + elements in ``index_set``. + + By default the index set is assumed to be the full index set of self. EXAMPLES:: @@ -1602,8 +1604,10 @@ def to_lowest_weight(self, index_set=None): r""" Return the lowest weight element `u` and a list `[i_1,...,i_k]` such that `self = e_{i_1} ... e_{i_k} u`, where `i_1,...,i_k` are - elements in `index_set`. By default the index set is assumed to be - the full index set of self. + elements in ``index_set``. + + By default the index set is assumed to be the full index + set of self. EXAMPLES:: @@ -1642,7 +1646,7 @@ def to_lowest_weight(self, index_set=None): def all_paths_to_highest_weight(self, index_set=None): r""" Iterate over all paths to the highest weight from ``self`` - with respect to `index_set`. + with respect to ``index_set``. INPUT: @@ -2183,7 +2187,7 @@ def _call_(self, x): cur = cur.e_string(s) return cur - def __bool__(self): + def __bool__(self) -> bool: """ Return if ``self`` is a non-zero morphism. @@ -2200,8 +2204,6 @@ def __bool__(self): """ return any(self._on_gens(mg) is not None for mg in self._gens) - - # TODO: Does this belong in the element_class of the Crystals() category? def to_module_generator(self, x): """ diff --git a/src/sage/categories/examples/commutative_additive_monoids.py b/src/sage/categories/examples/commutative_additive_monoids.py index c0930bec5d5..945826c22a5 100644 --- a/src/sage/categories/examples/commutative_additive_monoids.py +++ b/src/sage/categories/examples/commutative_additive_monoids.py @@ -112,7 +112,7 @@ def zero(self): return self(()) class Element(FreeCommutativeAdditiveSemigroup.Element): - def __bool__(self): + def __bool__(self) -> bool: """ Check if ``self`` is not the zero of the monoid @@ -126,6 +126,5 @@ def __bool__(self): """ return any(x for x in self.value.values()) - Example = FreeCommutativeAdditiveMonoid diff --git a/src/sage/categories/examples/lie_algebras.py b/src/sage/categories/examples/lie_algebras.py index cdde62e6760..3eafe0787f3 100644 --- a/src/sage/categories/examples/lie_algebras.py +++ b/src/sage/categories/examples/lie_algebras.py @@ -193,7 +193,7 @@ def __ne__(self, rhs): """ return not self.__eq__(rhs) - def __bool__(self): + def __bool__(self) -> bool: """ Check non-zero. @@ -207,8 +207,6 @@ def __bool__(self): """ return bool(self.value) - - def _add_(self, rhs): """ Add ``self`` and ``rhs``. diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index 2edc78c26e3..bfe0de224b2 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -837,7 +837,7 @@ def derived_subalgebra(self): the 0-dimensional abelian Lie algebra over Rational Field with basis matrix: [] - + If ``self`` is semisimple, then the derived subalgebra is ``self``:: sage: sl3 = LieAlgebra(QQ, cartan_type=['A',2]) @@ -1107,8 +1107,8 @@ def chevalley_eilenberg_complex(self, M=None, dual=False, sparse=True, ncpus=Non sage: E,F,H = g.basis() sage: n = g.subalgebra([F,H]) sage: ascii_art(n.chevalley_eilenberg_complex()) - [0] - [0 0] [2] + [0] + [0 0] [2] 0 <-- C_0 <------ C_1 <---- C_2 <-- 0 REFERENCES: diff --git a/src/sage/categories/finite_permutation_groups.py b/src/sage/categories/finite_permutation_groups.py index 9269bc8ac1c..59c00471e3f 100644 --- a/src/sage/categories/finite_permutation_groups.py +++ b/src/sage/categories/finite_permutation_groups.py @@ -232,7 +232,6 @@ def cycle_index(self, parent=None): return parent.sum_of_terms([C.an_element().cycle_type(), base_ring(C.cardinality())] for C in self.conjugacy_classes() ) / self.cardinality() - @cached_method def profile_series(self, variable='z'): diff --git a/src/sage/categories/functor.pyx b/src/sage/categories/functor.pyx index 77b95f0718c..ccf01cc9177 100644 --- a/src/sage/categories/functor.pyx +++ b/src/sage/categories/functor.pyx @@ -681,11 +681,9 @@ def ForgetfulFunctor(domain, codomain): sage: ForgetfulFunctor(abgrps, abgrps) == IdentityFunctor(abgrps) True - """ if domain == codomain: return IdentityFunctor(domain) if not domain.is_subcategory(codomain): raise ValueError("Forgetful functor not supported for domain %s" % domain) return ForgetfulFunctor_generic(domain, codomain) - diff --git a/src/sage/categories/highest_weight_crystals.py b/src/sage/categories/highest_weight_crystals.py index e063e388998..b8afdee2117 100644 --- a/src/sage/categories/highest_weight_crystals.py +++ b/src/sage/categories/highest_weight_crystals.py @@ -322,14 +322,9 @@ def q_dimension(self, q=None, prec=None, use_product=False): 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 + 9*q^7 + 13*q^8 + 16*q^9 + O(q^10) sage: qdim = C.q_dimension(); qdim - 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 - + 9*q^7 + 13*q^8 + 16*q^9 + 22*q^10 + O(x^11) - sage: qdim.compute_coefficients(15) - sage: qdim - 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 - + 9*q^7 + 13*q^8 + 16*q^9 + 22*q^10 + 27*q^11 - + 36*q^12 + 44*q^13 + 57*q^14 + 70*q^15 + O(x^16) - + 1 + q + 2*q^2 + 2*q^3 + 4*q^4 + 5*q^5 + 7*q^6 + O(q^7) + sage: qdim[:16] + [1, 1, 2, 2, 4, 5, 7, 9, 13, 16, 22, 27, 36, 44, 57, 70] """ from sage.rings.integer_ring import ZZ WLR = self.weight_lattice_realization() @@ -375,7 +370,7 @@ def iter_by_deg(gens): elif prec is None: # If we're here, we may not be a finite crystal. # In fact, we're probably infinite. - from sage.combinat.species.series import LazyPowerSeriesRing + from sage.rings.lazy_series_ring import LazyPowerSeriesRing if q is None: P = LazyPowerSeriesRing(ZZ, names='q') else: @@ -383,14 +378,13 @@ def iter_by_deg(gens): if not isinstance(P, LazyPowerSeriesRing): raise TypeError("the parent of q must be a lazy power series ring") ret = P(iter_by_deg(mg)) - ret.compute_coefficients(10) return ret from sage.rings.power_series_ring import PowerSeriesRing, PowerSeriesRing_generic if q is None: q = PowerSeriesRing(ZZ, 'q', default_prec=prec).gen(0) P = q.parent() - ret = P.sum(c * q**deg for deg,c in enumerate(iter_by_deg(mg))) + ret = P.sum(c * q**deg for deg, c in enumerate(iter_by_deg(mg))) if ret.degree() == max_deg and isinstance(P, PowerSeriesRing_generic): ret = P(ret, prec) return ret diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index 4fe021b86ca..1c954e76201 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -47,8 +47,10 @@ - Simon King (2013-02): added examples """ + # **************************************************************************** -# Copyright (C) 2005 David Kohel , William Stein +# Copyright (C) 2005 David Kohel , +# William Stein # # Distributed under the terms of the GNU General Public License (GPL) # @@ -62,7 +64,6 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - from sage.categories.category import Category, JoinCategory from . import morphism from sage.structure.parent import Parent, Set_generic @@ -86,7 +87,6 @@ def Hom(X, Y, category=None, check=True): INPUT: - - ``X`` -- an object of a category - ``Y`` -- an object of a category @@ -734,7 +734,7 @@ def __hash__(self): """ return hash((self._domain, self._codomain, self.base())) - def __bool__(self): + def __bool__(self) -> bool: """ TESTS:: @@ -743,8 +743,6 @@ def __bool__(self): """ return True - - def homset_category(self): """ Return the category that this is a Hom in, i.e., this is typically @@ -1083,7 +1081,7 @@ def __ne__(self, other): True """ return not (self == other) - + def __contains__(self, x): """ Test whether the parent of the argument is ``self``. 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/magmas.py b/src/sage/categories/magmas.py index c1f255a6eb9..801d3700707 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -774,12 +774,13 @@ def product(self, x, y): def __init_extra__(self): """ + EXAMPLES:: + sage: S = Semigroups().example("free") sage: S('a') * S('b') # indirect doctest 'ab' sage: S('a').__class__._mul_ == S('a').__class__._mul_parent True - """ # This should instead register the multiplication to the coercion model # But this is not yet implemented in the coercion model 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/poor_man_map.py b/src/sage/categories/poor_man_map.py index 507705fb9f9..e9829c98fab 100644 --- a/src/sage/categories/poor_man_map.py +++ b/src/sage/categories/poor_man_map.py @@ -200,12 +200,12 @@ def __mul__(self, other): Note that the compatibility of the domains and codomains is for performance reasons only checked for proper parents. For example, the incompatibility is not detected here:: - + sage: f*g A map from (2, 3, 4) to (2, 3, 4) - + But it is detected here:: - + sage: g = PoorManMap(factorial, domain = ZZ, codomain = ZZ) sage: h = PoorManMap(sqrt, domain = RR, codomain = CC) sage: g*h @@ -214,7 +214,6 @@ def __mul__(self, other): ValueError: the codomain Complex Field with 53 bits of precision does not coerce into the domain Integer Ring sage: h*g A map from Integer Ring to Complex Field with 53 bits of precision - """ self_domain = self.domain() @@ -227,7 +226,7 @@ def __mul__(self, other): from sage.structure.parent import is_Parent if is_Parent(self_domain) and is_Parent(other_codomain): if not self_domain.has_coerce_map_from(other_codomain): - raise ValueError("the codomain %r does not coerce into the domain %r"%(other_codomain, self_domain)) + raise ValueError("the codomain %r does not coerce into the domain %r" % (other_codomain, self_domain)) codomain = self.codomain() try: diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 3136160f39d..760f97a3c4f 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -2851,7 +2851,7 @@ def __init__(self, I, names=None, as_field=False, domain=None, if codomain is None: codomain = Rings() Functor.__init__(self, domain, codomain) - + self.I = I if names is None: self.names = None 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/categories/sets_with_grading.py b/src/sage/categories/sets_with_grading.py index 8ef7b8b0256..5d01bfab999 100644 --- a/src/sage/categories/sets_with_grading.py +++ b/src/sage/categories/sets_with_grading.py @@ -212,11 +212,21 @@ def generating_series(self): Non negative integers sage: N.generating_series() 1/(-z + 1) + + sage: Permutations().generating_series() + 1 + z + 2*z^2 + 6*z^3 + 24*z^4 + 120*z^5 + 720*z^6 + O(z^7) + + .. TODO:: + + - Very likely, this should always return a lazy power series. """ - from sage.combinat.species.series import LazyPowerSeriesRing + from sage.sets.non_negative_integers import NonNegativeIntegers + from sage.rings.lazy_series_ring import LazyPowerSeriesRing from sage.rings.integer_ring import ZZ - R = LazyPowerSeriesRing(ZZ) - R(self.graded_component(grade).cardinality() for grade in self.grading_set()) + if isinstance(self.grading_set(), NonNegativeIntegers): + R = LazyPowerSeriesRing(ZZ, names="z") + return R(lambda n: self.graded_component(n).cardinality()) + raise NotImplementedError # TODO: # * asymptotic behavior: we need an object for asymptotic behavior and diff --git a/src/sage/categories/super_lie_conformal_algebras.py b/src/sage/categories/super_lie_conformal_algebras.py index cc6167d6830..849a0fbdb13 100644 --- a/src/sage/categories/super_lie_conformal_algebras.py +++ b/src/sage/categories/super_lie_conformal_algebras.py @@ -47,7 +47,7 @@ def extra_super_categories(self): sage: LieConformalAlgebras(QQ).Super().super_categories() [Category of super modules over Rational Field, - Category of Lambda bracket algebras over Rational Field] + Category of Lambda bracket algebras over Rational Field] """ return [LambdaBracketAlgebras(self.base_ring())] diff --git a/src/sage/categories/unique_factorization_domains.py b/src/sage/categories/unique_factorization_domains.py index 49a41b97098..ccc96acbf80 100644 --- a/src/sage/categories/unique_factorization_domains.py +++ b/src/sage/categories/unique_factorization_domains.py @@ -16,9 +16,11 @@ class UniqueFactorizationDomains(Category_singleton): """ - The category of unique factorization domains - constructive unique factorization domains, i.e. where one can constructively - factor members into a product of a finite number of irreducible elements + The category of (constructive) unique factorization domains. + + In a constructive unique factorization domain we can + constructively factor members into a product of a finite number + of irreducible elements. EXAMPLES:: @@ -30,6 +32,7 @@ class UniqueFactorizationDomains(Category_singleton): TESTS:: sage: TestSuite(UniqueFactorizationDomains()).run() + """ def super_categories(self): diff --git a/src/sage/categories/weyl_groups.py b/src/sage/categories/weyl_groups.py index 47ca72306f0..c6b0338e441 100644 --- a/src/sage/categories/weyl_groups.py +++ b/src/sage/categories/weyl_groups.py @@ -1,10 +1,5 @@ r""" Weyl Groups - -REFERENCES: - -.. [Dye] Dyer. *Bruhat intervals, polyhedral cones and Kazhdan-Lusztig-Stanley polynomials*. Math.Z., 215(2):223-236, 1994. -.. [JahStu] Jahn and Stump. *Bruhat intervals, subword complexes and brick polyhedra for finite Coxeter groups*. Preprint, available at :arxiv:`2103.03715`, 2021. """ #***************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery @@ -155,7 +150,7 @@ def pieri_factors(self, *args, **keywords): if hasattr(ct, "PieriFactors"): return ct.PieriFactors(self, *args, **keywords) raise NotImplementedError("Pieri factors for type {}".format(ct)) - + def bruhat_cone(self, x, y, side='upper', backend='cdd'): r""" Return the (upper or lower) Bruhat cone associated to the interval ``[x,y]``. @@ -207,8 +202,8 @@ def bruhat_cone(self, x, y, side='upper', backend='cdd'): REFERENCES: - - [Dye]_ - - [JahStu]_ + - [Dy1994]_ + - [JS2021]_ """ from sage.modules.free_module_element import vector if side == 'upper': diff --git a/src/sage/coding/cyclic_code.py b/src/sage/coding/cyclic_code.py index a5c3a4c88fb..93ce9730f49 100644 --- a/src/sage/coding/cyclic_code.py +++ b/src/sage/coding/cyclic_code.py @@ -47,6 +47,7 @@ from sage.misc.cachefunc import cached_method from sage.rings.all import Zmod + def find_generator_polynomial(code, check=True): r""" Returns a possible generator polynomial for ``code``. @@ -334,7 +335,7 @@ def __init__(self, generator_pol=None, length=None, code=None, check=True, ... ValueError: The code is not cyclic. - If the `primitive_root` does not lie in an extension of `field`, + If the ``primitive_root`` does not lie in an extension of ``field``, or is not a primitive `n`-th root of unity, then an exception is raised:: @@ -1321,7 +1322,7 @@ def decoding_radius(self): return self._bch_decoder.decoding_radius() -####################### registration ############################### +# ###################### registration ############################## CyclicCode._registered_encoders["Polynomial"] = CyclicCodePolynomialEncoder CyclicCode._registered_encoders["Vector"] = CyclicCodeVectorEncoder diff --git a/src/sage/combinat/chas/wqsym.py b/src/sage/combinat/chas/wqsym.py index 238d0281030..99659ab154a 100644 --- a/src/sage/combinat/chas/wqsym.py +++ b/src/sage/combinat/chas/wqsym.py @@ -69,9 +69,12 @@ def __init__(self, alg, graded=True): sage: M = algebras.WQSym(QQ).M() sage: TestSuite(M).run() # long time """ + def sorting_key(X): + return (sum(map(len, X)), X) CombinatorialFreeModule.__init__(self, alg.base_ring(), OrderedSetPartitions(), category=WQSymBases(alg, graded), + sorting_key=sorting_key, bracket="", prefix=self._prefix) def _repr_term(self, osp): @@ -574,7 +577,7 @@ class Monomial(WQSymBasis_abstract): sage: M = WQSym.M(); M Word Quasi-symmetric functions over Rational Field in the Monomial basis sage: sorted(M.basis(2)) - [M[{1, 2}], M[{2}, {1}], M[{1}, {2}]] + [M[{1}, {2}], M[{2}, {1}], M[{1, 2}]] """ _prefix = "M" _basis_name = "Monomial" @@ -625,6 +628,7 @@ def product_on_basis(self, x, y): def union(X, Y): return X.union(Y) + return self.sum_of_monomials(ShuffleProduct_overlapping(x, yshift, K, union)) @@ -975,12 +979,15 @@ def _C_to_X(self, P): temp = temp[:j] break + def union(X, Y): + return X.union(Y) + # Perform the quasi-shuffle product cur = {data[0]: 1} for B in data[1:]: ret = {} for A in cur: - for C in ShuffleProduct_overlapping(A, B, element_constructor=OSP): + for C in ShuffleProduct_overlapping(A, B, element_constructor=OSP, add=union): if C in ret: ret[C] += cur[A] else: diff --git a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py index e65d605fad1..d7c4d849e0c 100644 --- a/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py +++ b/src/sage/combinat/cluster_algebra_quiver/cluster_seed.py @@ -1062,7 +1062,7 @@ def interact(self, fig_size=1, circular=True): sage: S = ClusterSeed(['A',4]) sage: S.interact() - VBox(children=... + ...VBox(children=... """ return cluster_interact(self, fig_size, circular, kind='seed') diff --git a/src/sage/combinat/cluster_algebra_quiver/interact.py b/src/sage/combinat/cluster_algebra_quiver/interact.py index 4e54c64e179..1c88e613b4c 100644 --- a/src/sage/combinat/cluster_algebra_quiver/interact.py +++ b/src/sage/combinat/cluster_algebra_quiver/interact.py @@ -27,7 +27,7 @@ def cluster_interact(self, fig_size=1, circular=True, kind='seed'): sage: S = ClusterSeed(['A',4]) sage: S.interact() # indirect doctest - VBox(children=... + ...VBox(children=... """ if kind not in ['seed', 'quiver']: raise ValueError('kind must be "seed" or "quiver"') @@ -107,7 +107,7 @@ def do_mutation(*args, **kwds): show_lastmutation.observe(refresh, 'value') which_plot.observe(refresh, 'value') - mut_buttons.on_displayed(refresh) + mut_buttons.on_widget_constructed(refresh) if kind == 'seed': top = widgets.HBox([show_seq, show_vars]) diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver.py b/src/sage/combinat/cluster_algebra_quiver/quiver.py index 4f6e16bf0fe..14a176c479a 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver.py @@ -699,7 +699,7 @@ def interact(self, fig_size=1, circular=True): sage: S = ClusterQuiver(['A',4]) sage: S.interact() - VBox(children=... + ...VBox(children=... """ return cluster_interact(self, fig_size, circular, kind="quiver") 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/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index a59d6b0fb9b..d9144a80539 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -166,11 +166,13 @@ def planar_diagrams(k): EXAMPLES:: sage: import sage.combinat.diagram_algebras as da - sage: all_diagrams = da.partition_diagrams(2) - sage: [SetPartition(p) for p in all_diagrams if p not in da.planar_diagrams(2)] + sage: all_diagrams = [SetPartition(p) for p in da.partition_diagrams(2)] + sage: da2 = [SetPartition(p) for p in da.planar_diagrams(2)] + sage: [p for p in all_diagrams if p not in da2] [{{-2, 1}, {-1, 2}}] - sage: all_diagrams = da.partition_diagrams(5/2) - sage: [SetPartition(p) for p in all_diagrams if p not in da.planar_diagrams(5/2)] + sage: all_diagrams = [SetPartition(p) for p in da.partition_diagrams(5/2)] + sage: da5o2 = [SetPartition(p) for p in da.planar_diagrams(5/2)] + sage: [p for p in all_diagrams if p not in da5o2] [{{-3, -1, 3}, {-2, 1, 2}}, {{-3, -2, 1, 3}, {-1, 2}}, {{-3, -1, 1, 3}, {-2, 2}}, @@ -182,9 +184,73 @@ def planar_diagrams(k): {{-3, -1, 3}, {-2, 1}, {2}}, {{-3, -1, 3}, {-2, 2}, {1}}] """ - for i in partition_diagrams(k): - if is_planar(i): - yield i + if k in ZZ: + X = list(range(1,k+1)) + list(range(-k,0)) + yield from planar_partitions_rec(X) + elif k + ZZ(1)/ZZ(2) in ZZ: # Else k in 1/2 ZZ + k = ZZ(k + ZZ(1) / ZZ(2)) + X = list(range(1,k+1)) + list(range(-k+1,0)) + for Y in planar_partitions_rec(X): + Y = list(Y) + for part in Y: + if k in part: + part.append(-k) + break + yield Y + else: + raise ValueError("argument %s must be a half-integer" % k) + +def planar_partitions_rec(X): + r""" + Iterate over all planar set partitions of ``X`` by using a + recursive algorithm. + + ALGORITHM: + + To construct the set partition `\rho = \{\rho_1, \ldots, \rho_k\}` of + `[n]`, we remove the part of the set partition containing the last + element of ``X``, which, we consider to be `\rho_k = \{i_1, \ldots, i_m\}` + without loss of generality. The remaining parts come from the planar set + partitions of `\{1, \ldots, i_1-1\}, \{i_1+1, \ldots, i_2-1\}, \ldots, + \{i_m+1, \ldots, n\}`. + + EXAMPLES:: + + sage: import sage.combinat.diagram_algebras as da + sage: list(da.planar_partitions_rec([1,2,3])) + [([1, 2], [3]), ([1], [2], [3]), ([2], [1, 3]), ([1], [2, 3]), ([1, 2, 3],)] + """ + if not X: + return + if len(X) <= 2: + # Direct implementation of small cases + yield (X,) + if len(X) > 1: + yield ([X[0]], [X[1]]) + return + from sage.misc.misc import powerset + from itertools import product + for S in powerset(range(len(X)-1)): + if not S: + for Y in planar_partitions_rec(X[:-1]): + yield Y + ([X[-1]],) + continue + last = [X[i] for i in S] + last.append(X[-1]) + pt = [] + if S[0] != 0: + pt += [X[:S[0]]] + pt = [X[S[i]+1:S[i+1]] for i in range(len(S)-1) if S[i]+1 != S[i+1]] + if S[-1] + 1 != len(X) - 1: + pt += [X[S[-1]+1:-1]] + parts = [planar_partitions_rec(X[S[i]+1:S[i+1]]) for i in range(len(S)-1) + if S[i] + 1 != S[i+1]] + if S[0] != 0: + parts.append(planar_partitions_rec(X[:S[0]])) + if S[-1] + 1 != len(X) - 1: + parts.append(planar_partitions_rec(X[S[-1]+1:-1])) + for Y in product(*parts): + yield sum(Y, ()) + (last,) def ideal_diagrams(k): r""" @@ -606,20 +672,20 @@ class PlanarDiagram(AbstractPartitionDiagram): sage: PlanarDiagrams(2) Planar diagrams of order 2 sage: PlanarDiagrams(2).list() - [{{-2, -1, 1, 2}}, - {{-2, 1, 2}, {-1}}, - {{-2}, {-1, 1, 2}}, - {{-2, -1}, {1, 2}}, - {{-2}, {-1}, {1, 2}}, - {{-2, -1, 1}, {2}}, + [{{-2}, {-1}, {1, 2}}, + {{-2}, {-1}, {1}, {2}}, {{-2, 1}, {-1}, {2}}, - {{-2, 2}, {-1, 1}}, - {{-2, -1, 2}, {1}}, {{-2, 2}, {-1}, {1}}, + {{-2, 1, 2}, {-1}}, + {{-2, 2}, {-1, 1}}, {{-2}, {-1, 1}, {2}}, {{-2}, {-1, 2}, {1}}, + {{-2}, {-1, 1, 2}}, + {{-2, -1}, {1, 2}}, {{-2, -1}, {1}, {2}}, - {{-2}, {-1}, {1}, {2}}] + {{-2, -1, 1}, {2}}, + {{-2, -1, 2}, {1}}, + {{-2, -1, 1, 2}}] """ @staticmethod def __classcall_private__(cls, diag): @@ -1183,27 +1249,27 @@ def __iter__(self): [{{-2, -1}, {1, 2}}, {{-2, 2}, {-1, 1}}] sage: list(da.PlanarDiagrams(3/2)) - [{{-2, -1, 1, 2}}, - {{-2, 1, 2}, {-1}}, + [{{-2, 1, 2}, {-1}}, + {{-2, 2}, {-1}, {1}}, {{-2, 2}, {-1, 1}}, {{-2, -1, 2}, {1}}, - {{-2, 2}, {-1}, {1}}] + {{-2, -1, 1, 2}}] sage: list(da.PlanarDiagrams(2)) - [{{-2, -1, 1, 2}}, - {{-2, 1, 2}, {-1}}, - {{-2}, {-1, 1, 2}}, - {{-2, -1}, {1, 2}}, - {{-2}, {-1}, {1, 2}}, - {{-2, -1, 1}, {2}}, + [{{-2}, {-1}, {1, 2}}, + {{-2}, {-1}, {1}, {2}}, {{-2, 1}, {-1}, {2}}, - {{-2, 2}, {-1, 1}}, - {{-2, -1, 2}, {1}}, {{-2, 2}, {-1}, {1}}, + {{-2, 1, 2}, {-1}}, + {{-2, 2}, {-1, 1}}, {{-2}, {-1, 1}, {2}}, {{-2}, {-1, 2}, {1}}, + {{-2}, {-1, 1, 2}}, + {{-2, -1}, {1, 2}}, {{-2, -1}, {1}, {2}}, - {{-2}, {-1}, {1}, {2}}] + {{-2, -1, 1}, {2}}, + {{-2, -1, 2}, {1}}, + {{-2, -1, 1, 2}}] sage: list(da.IdealDiagrams(3/2)) [{{-2, -1, 1, 2}}, @@ -1654,11 +1720,11 @@ class PlanarDiagrams(AbstractPartitionDiagrams): sage: pld = da.PlanarDiagrams(3/2); pld Planar diagrams of order 3/2 sage: pld.list() - [{{-2, -1, 1, 2}}, - {{-2, 1, 2}, {-1}}, + [{{-2, 1, 2}, {-1}}, + {{-2, 2}, {-1}, {1}}, {{-2, 2}, {-1, 1}}, {{-2, -1, 2}, {1}}, - {{-2, 2}, {-1}, {1}}] + {{-2, -1, 1, 2}}] TESTS:: @@ -3967,20 +4033,20 @@ class PlanarAlgebra(SubPartitionAlgebra, UnitDiagramMixin): sage: Pl.basis().keys()([[-1, 1], [2, -2]]) {{-2, 2}, {-1, 1}} sage: Pl.basis().list() - [Pl{{-2, -1, 1, 2}}, - Pl{{-2, 1, 2}, {-1}}, - Pl{{-2}, {-1, 1, 2}}, - Pl{{-2, -1}, {1, 2}}, - Pl{{-2}, {-1}, {1, 2}}, - Pl{{-2, -1, 1}, {2}}, + [Pl{{-2}, {-1}, {1, 2}}, + Pl{{-2}, {-1}, {1}, {2}}, Pl{{-2, 1}, {-1}, {2}}, - Pl{{-2, 2}, {-1, 1}}, - Pl{{-2, -1, 2}, {1}}, Pl{{-2, 2}, {-1}, {1}}, + Pl{{-2, 1, 2}, {-1}}, + Pl{{-2, 2}, {-1, 1}}, Pl{{-2}, {-1, 1}, {2}}, Pl{{-2}, {-1, 2}, {1}}, + Pl{{-2}, {-1, 1, 2}}, + Pl{{-2, -1}, {1, 2}}, Pl{{-2, -1}, {1}, {2}}, - Pl{{-2}, {-1}, {1}, {2}}] + Pl{{-2, -1, 1}, {2}}, + Pl{{-2, -1, 2}, {1}}, + Pl{{-2, -1, 1, 2}}] sage: E = Pl([[1,2],[-1,-2]]) sage: E^2 == x*E True 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/partition.py b/src/sage/combinat/partition.py index 7ac1ad6c4a6..b7d3bf3c8b3 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -543,7 +543,6 @@ def __init__(self, parent, mu): Traceback (most recent call last): ... ValueError: [3, 1, 7] is not an element of Partitions - """ if isinstance(mu, Partition): # since we are (suppose to be) immutable, we can share the underlying data @@ -738,9 +737,9 @@ def _repr_exp_high(self): if not self._list: return '-' exp = self.to_exp()[::-1] # reversed list of exponents - M=max(self) - return '%s' % ', '.join('%s%s' % (M-m, '' if e==1 else '^%s'%e) - for (m,e) in enumerate(exp) if e>0) + M = max(self) + return ', '.join('%s%s' % (M - m, '' if e == 1 else '^%s' % e) + for m, e in enumerate(exp) if e > 0) def _repr_compact_low(self): """ @@ -1051,13 +1050,26 @@ def __truediv__(self, p): sage: p/[2,2,2] Traceback (most recent call last): ... - ValueError: To form a skew partition p/q, q must be contained in p. + ValueError: to form a skew partition p/q, q must be contained in p """ if not self.contains(p): - raise ValueError("To form a skew partition p/q, q must be contained in p.") + raise ValueError("to form a skew partition p/q, q must be contained in p") return SkewPartition([self[:], p]) + def stretch(self, k): + """ + Return the partition obtained by multiplying each part with the + given number. + + EXAMPLES:: + + sage: p = Partition([4,2,2,1,1]) + sage: p.stretch(3) + [12, 6, 6, 3, 3] + """ + return _Partitions([k * p for p in self]) + def power(self, k): r""" Return the cycle type of the `k`-th power of any permutation @@ -2251,7 +2263,7 @@ def t_completion(self, t): ValueError: 5-completion is not defined """ if self._list and t < self.size() + self._list[0]: - raise ValueError("{}-completion is not defined".format(t)) + raise ValueError(f"{t}-completion is not defined") return Partition([t - self.size()] + self._list) def larger_lex(self, rhs): @@ -3026,14 +3038,15 @@ def arm_length(self, i, j): p = self if i < len(p) and j < p[i]: return p[i]-(j+1) - else: - raise ValueError("The cell is not in the diagram") + raise ValueError("the cell is not in the diagram") def arm_lengths(self, flat=False): """ Return a tableau of shape ``self`` where each cell is filled with - its arm length. The optional boolean parameter ``flat`` provides - the option of returning a flat list. + its arm length. + + The optional boolean parameter ``flat`` provides the option of + returning a flat list. EXAMPLES:: @@ -3077,15 +3090,12 @@ def arm_cells(self, i, j): sage: Partition([]).arm_cells(0,0) Traceback (most recent call last): ... - ValueError: The cell is not in the diagram - + ValueError: the cell is not in the diagram """ p = self if i < len(p) and j < p[i]: - return [ (i, x) for x in range(j+1, p[i]) ] - else: - raise ValueError("The cell is not in the diagram") - + return [(i, x) for x in range(j + 1, p[i])] + raise ValueError("the cell is not in the diagram") def leg_length(self, i, j): """ @@ -3119,12 +3129,10 @@ def leg_length(self, i, j): sage: cell = [0,0]; Partition([3,3]).leg_length(*cell) 1 """ - conj = self.conjugate() if j < len(conj) and i < conj[j]: - return conj[j]-(i+1) - else: - raise ValueError("The cell is not in the diagram") + return conj[j] - (i + 1) + raise ValueError("the cell is not in the diagram") def leg_lengths(self, flat=False): """ @@ -3179,10 +3187,10 @@ def leg_cells(self, i, j): sage: Partition([]).leg_cells(0,0) Traceback (most recent call last): ... - ValueError: The cell is not in the diagram + ValueError: the cell is not in the diagram """ l = self.leg_length(i, j) - return [(x, j) for x in range(i+1, i+l+1)] + return [(x, j) for x in range(i + 1, i + l + 1)] def attacking_pairs(self): """ @@ -3501,8 +3509,8 @@ def lower_hook_lengths(self, alpha): """ p = self conj = p.conjugate() - return [[conj[j] - i + alpha*(p[i]-(j+1)) for j in range(p[i])] for i in range(len(p))] - + return [[conj[j] - i + alpha*(p[i] - (j + 1)) for j in range(p[i])] + for i in range(len(p))] def weighted_size(self): r""" @@ -4418,10 +4426,9 @@ def add_cell(self, i, j = None): pl[i] += 1 return Partition(pl) - raise ValueError("[%s, %s] is not an addable cell"%(i,j)) - + raise ValueError(f"[{i}, {j}] is not an addable cell") - def remove_cell(self, i, j = None): + def remove_cell(self, i, j=None): """ Return the partition obtained by removing a cell at the end of row ``i`` of ``self``. @@ -4514,7 +4521,7 @@ def k_skew(self, k): return SkewPartition([[],[]]) if self[0] > k: - raise ValueError("the partition must be %d-bounded" % k) + raise ValueError(f"the partition must be {k}-bounded") #Find the k-skew diagram of the partition formed #by removing the first row @@ -4765,7 +4772,7 @@ def vertical_border_strip_cells(self, k): sage: list(Partition([]).vertical_border_strip_cells(2)) [[(0, 0), (1, 0)]] sage: list(Partition([2,2]).vertical_border_strip_cells(2)) - [[(0, 2), (1, 2)], + [[(0, 2), (1, 2)], [(0, 2), (2, 0)], [(2, 0), (3, 0)]] sage: list(Partition([3,2,2]).vertical_border_strip_cells(2)) @@ -4806,7 +4813,7 @@ def vertical_border_strip_cells(self, k): for _ in range(iv[t]): current_strip.append((j, tmp[j])) j += 1 - j = sum(shelf[:t+1]) + j = sum(shelf[:t+1]) yield current_strip def horizontal_border_strip_cells(self, k): @@ -4900,13 +4907,13 @@ def remove_horizontal_border_strip(self, k): sage: Partition([]).remove_horizontal_border_strip(6).list() [] """ - return Partitions_with_constraints(n = self.size()-k, - min_length = len(self)-1, - max_length = len(self), - floor = self[1:]+[0], - ceiling = self[:], - max_slope = 0, - name = "The subpartitions of {} obtained by removing an horizontal border strip of length {}".format(self,k)) + return Partitions_with_constraints(n=self.size() - k, + min_length=len(self) - 1, + max_length=len(self), + floor=self[1:] + [0], + ceiling=self[:], + max_slope=0, + name=f"The subpartitions of {self} obtained by removing an horizontal border strip of length {k}") def k_conjugate(self, k): r""" @@ -5073,11 +5080,9 @@ def jacobi_trudi(self): """ return SkewPartition([ self, [] ]).jacobi_trudi() - def character_polynomial(self): r""" - Return the character polynomial associated to the partition - ``self``. + Return the character polynomial associated to the partition ``self``. The character polynomial `q_\mu` associated to a partition `\mu` is defined by @@ -5108,8 +5113,7 @@ def character_polynomial(self): sage: Partition([2,1]).character_polynomial() 1/3*x0^3 - 2*x0^2 + 8/3*x0 - x2 """ - - #Create the polynomial ring we will use + # Create the polynomial ring we will use k = self.size() P = PolynomialRing(QQ, k, 'x') x = P.gens() @@ -5201,7 +5205,7 @@ def dimension(self, smaller=None, k=1): Checks that the dimension satisfies the obvious recursion relation:: sage: test = lambda larger, smaller: larger.dimension(smaller) == sum(mu.dimension(smaller) for mu in larger.down()) - sage: all(test(larger,smaller) for l in range(1,10) for s in range(10) + sage: all(test(larger,smaller) for l in range(1,8) for s in range(8) ....: for larger in Partitions(l) for smaller in Partitions(s) if smaller != larger) True @@ -5477,6 +5481,7 @@ def coloring(i): immutable=True, multiedges=True) return self.dual_equivalence_graph(directed, coloring) + ############## # Partitions # ############## @@ -5734,15 +5739,15 @@ class Partitions(UniqueRepresentation, Parent): sage: Partitions(5,parts_in=[1,2,3,4], length=4) Traceback (most recent call last): ... - ValueError: The parameters 'parts_in', 'starting' and 'ending' cannot be combined with anything else. + ValueError: the parameters 'parts_in', 'starting' and 'ending' cannot be combined with anything else sage: Partitions(5,starting=[3,2], length=2) Traceback (most recent call last): ... - ValueError: The parameters 'parts_in', 'starting' and 'ending' cannot be combined with anything else. + ValueError: the parameters 'parts_in', 'starting' and 'ending' cannot be combined with anything else sage: Partitions(5,ending=[3,2], length=2) Traceback (most recent call last): ... - ValueError: The parameters 'parts_in', 'starting' and 'ending' cannot be combined with anything else. + ValueError: the parameters 'parts_in', 'starting' and 'ending' cannot be combined with anything else sage: Partitions(NN, length=2) Traceback (most recent call last): ... @@ -5835,8 +5840,8 @@ def __classcall_private__(cls, n=None, **kwargs): ('parts_in' in kwargs or 'starting' in kwargs or 'ending' in kwargs)): - raise ValueError("The parameters 'parts_in', 'starting' and "+ - "'ending' cannot be combined with anything else.") + raise ValueError("the parameters 'parts_in', 'starting' and "+ + "'ending' cannot be combined with anything else") if 'parts_in' in kwargs: return Partitions_parts_in(n, kwargs['parts_in']) @@ -5853,10 +5858,10 @@ def __classcall_private__(cls, n=None, **kwargs): kwargs['name'] = "Partitions of the integer %s satisfying constraints %s"%(n, ", ".join( ["%s=%s"%(key, kwargs[key]) for key in sorted(kwargs)] )) # min_part is at least 1, and it is 1 by default - kwargs['min_part'] = max(1,kwargs.get('min_part',1)) + kwargs['min_part'] = max(1, kwargs.get('min_part', 1)) # max_slope is at most 0, and it is 0 by default - kwargs['max_slope'] = min(0,kwargs.get('max_slope',0)) + kwargs['max_slope'] = min(0, kwargs.get('max_slope', 0)) if kwargs.get('min_slope', -float('inf')) > 0: raise ValueError("the minimum slope must be non-negative") @@ -6041,7 +6046,7 @@ def _element_constructor_(self, lst): """ if isinstance(lst, PartitionTuple): if lst.level() != 1: - raise ValueError('%s is not an element of %s' % (lst, self)) + raise ValueError(f'{lst} is not an element of {self}') lst = lst[0] if lst.parent() is self: return lst @@ -6115,12 +6120,13 @@ def subset(self, *args, **kwargs): sage: P.subset(ending=[3,1]) Traceback (most recent call last): ... - ValueError: Invalid combination of arguments + ValueError: invalid combination of arguments """ if len(args) != 0 or len(kwargs) != 0: - raise ValueError("Invalid combination of arguments") + raise ValueError("invalid combination of arguments") return self + class Partitions_all(Partitions): """ Class of all partitions. @@ -6224,12 +6230,12 @@ def from_frobenius_coordinates(self, frobenius_coordinates): [7, 5, 5, 1, 1] """ if len(frobenius_coordinates) != 2: - raise ValueError('%s is not a valid partition, two sequences of coordinates are needed'%str(frobenius_coordinates)) + raise ValueError('%s is not a valid partition, two sequences of coordinates are needed' % str(frobenius_coordinates)) else: a = frobenius_coordinates[0] b = frobenius_coordinates[1] if len(a) != len(b): - raise ValueError('%s is not a valid partition, the sequences of coordinates need to be the same length'%str(frobenius_coordinates)) + raise ValueError('%s is not a valid partition, the sequences of coordinates need to be the same length' % str(frobenius_coordinates)) # should add tests to see if a and b are sorted down, nonnegative and strictly decreasing r = len(a) if r == 0: @@ -6237,16 +6243,16 @@ def from_frobenius_coordinates(self, frobenius_coordinates): tmp = [a[i]+i+1 for i in range(r)] # should check that a is strictly decreasing if a[-1] < 0: - raise ValueError('%s is not a partition, no coordinate can be negative'%str(frobenius_coordinates)) + raise ValueError('%s is not a partition, no coordinate can be negative' % str(frobenius_coordinates)) if b[-1] >= 0: tmp.extend([r]*b[r-1]) else: - raise ValueError('%s is not a partition, no coordinate can be negative'%str(frobenius_coordinates)) - for i in range(r-1,0,-1): + raise ValueError('%s is not a partition, no coordinate can be negative' % str(frobenius_coordinates)) + for i in range(r - 1, 0, -1): if b[i-1]-b[i] > 0: tmp.extend([i]*(b[i-1]-b[i]-1)) else: - raise ValueError('%s is not a partition, the coordinates need to be strictly decreasing'%str(frobenius_coordinates)) + raise ValueError('%s is not a partition, the coordinates need to be strictly decreasing' % str(frobenius_coordinates)) return self.element_class(self, tmp) def from_beta_numbers(self, beta): @@ -6391,6 +6397,7 @@ def from_core_and_quotient(self, core, quotient): new_w.sort(reverse=True) return self.element_class(self, [new_w[i]+i for i in range(len(new_w))]) + class Partitions_all_bounded(Partitions): def __init__(self, k): """ @@ -6450,6 +6457,7 @@ def __iter__(self): yield self.element_class(self, p) n += 1 + class Partitions_n(Partitions): """ Partitions of the integer `n`. @@ -6830,6 +6838,7 @@ def subset(self, **kwargs): """ return Partitions(self.n, **kwargs) + class Partitions_nk(Partitions): """ Partitions of the integer `n` of length equal to `k`. @@ -7044,6 +7053,7 @@ def subset(self, **kwargs): """ return Partitions(self.n, length=self.k, **kwargs) + class Partitions_parts_in(Partitions): """ Partitions of `n` with parts in a given set `S`. @@ -7070,7 +7080,7 @@ def __classcall_private__(cls, n, parts): True """ parts = tuple(sorted(parts)) - return super(Partitions_parts_in, cls).__classcall__(cls, Integer(n), parts) + return super().__classcall__(cls, Integer(n), parts) def __init__(self, n, parts): """ @@ -7379,8 +7389,8 @@ def __classcall_private__(cls, n, starting_partition): True """ starting_partition = Partition(starting_partition) - return super(Partitions_starting, cls).__classcall__(cls, Integer(n), - starting_partition) + return super().__classcall__(cls, Integer(n), + starting_partition) def __init__(self, n, starting_partition): """ @@ -7453,6 +7463,7 @@ def next(self, part): """ return next(part) + class Partitions_ending(Partitions): """ All partitions with a given ending. @@ -7471,8 +7482,8 @@ def __classcall_private__(cls, n, ending_partition): True """ ending_partition = Partition(ending_partition) - return super(Partitions_ending, cls).__classcall__(cls, Integer(n), - ending_partition) + return super().__classcall__(cls, Integer(n), + ending_partition) def __init__(self, n, ending_partition): """ @@ -7547,8 +7558,8 @@ def next(self, part): """ if part == self._ending: return None - else: - return next(part) + return next(part) + class PartitionsInBox(Partitions): r""" @@ -7669,6 +7680,7 @@ def cardinality(self): """ return binomial(self.h + self.w, self.w) + class Partitions_constraints(IntegerListsLex): """ For unpickling old constrained ``Partitions_constraints`` objects created @@ -7721,6 +7733,7 @@ class Partitions_with_constraints(IntegerListsLex): Element = Partition options = Partitions.options + ###################### # Regular Partitions # ###################### @@ -7819,11 +7832,12 @@ def _fast_iterator(self, n, max_part): max_part = n bdry = self._ell - 1 - for i in reversed(range(1, max_part+1)): - for p in self._fast_iterator(n-i, i): + for i in reversed(range(1, max_part + 1)): + for p in self._fast_iterator(n - i, i): if p.count(i) < bdry: yield [i] + p + class RegularPartitions_all(RegularPartitions): r""" The class of all `\ell`-regular partitions. @@ -7891,6 +7905,7 @@ def __iter__(self): yield self.element_class(self, p) n += 1 + class RegularPartitions_truncated(RegularPartitions): r""" The class of `\ell`-regular partitions with max length `k`. @@ -8007,11 +8022,12 @@ def _fast_iterator(self, n, max_part, depth=0): max_part = n bdry = self._ell - 1 - for i in reversed(range(1, max_part+1)): - for p in self._fast_iterator(n-i, i, depth+1): + for i in reversed(range(1, max_part + 1)): + for p in self._fast_iterator(n - i, i, depth + 1): if p.count(i) < bdry: yield [i] + p + class RegularPartitions_bounded(RegularPartitions): r""" The class of `\ell`-regular `k`-bounded partitions. @@ -8089,6 +8105,7 @@ def __iter__(self): for p in self._fast_iterator(n, k): yield self.element_class(self, p) + class RegularPartitions_n(RegularPartitions, Partitions_n): r""" The class of `\ell`-regular partitions of `n`. @@ -8216,6 +8233,7 @@ def _an_element_(self): raise EmptySetError return Partitions_n._an_element_(self) + ###################### # Ordered Partitions # ###################### @@ -8266,7 +8284,7 @@ def __classcall_private__(cls, n, k=None): """ if k is not None: k = Integer(k) - return super(OrderedPartitions, cls).__classcall__(cls, Integer(n), k) + return super().__classcall__(cls, Integer(n), k) def __init__(self, n, k): """ @@ -8363,6 +8381,7 @@ def cardinality(self): ans = libgap.NrOrderedPartitions(n, k) return ZZ(ans) + ########################## # Partitions Greatest LE # ########################## @@ -8440,6 +8459,7 @@ def cardinality(self): Element = Partition options = Partitions.options + ########################## # Partitions Greatest EQ # ########################## @@ -8531,6 +8551,7 @@ def cardinality(self): Element = Partition options = Partitions.options + ######################### # Restricted Partitions # ######################### @@ -8652,6 +8673,7 @@ def _fast_iterator(self, n, max_part): break yield [i] + p + class RestrictedPartitions_all(RestrictedPartitions_generic): r""" The class of all `\ell`-restricted partitions. @@ -8703,6 +8725,7 @@ def __iter__(self): yield self.element_class(self, p) n += 1 + class RestrictedPartitions_n(RestrictedPartitions_generic, Partitions_n): r""" The class of `\ell`-restricted partitions of `n`. @@ -8911,7 +8934,7 @@ def number_of_partitions(n, algorithm='default'): """ n = ZZ(n) if n < 0: - raise ValueError("n (=%s) must be a nonnegative integer"%n) + raise ValueError("n (=%s) must be a nonnegative integer" % n) elif n == 0: return ZZ.one() @@ -8921,7 +8944,7 @@ def number_of_partitions(n, algorithm='default'): if algorithm == 'flint': return cached_number_of_partitions(n) - raise ValueError("unknown algorithm '%s'"%algorithm) + raise ValueError("unknown algorithm '%s'" % algorithm) def number_of_partitions_length(n, k, algorithm='hybrid'): @@ -8989,7 +9012,7 @@ def number_of_partitions_length(n, k, algorithm='hybrid'): # Rather than caching an under-used function I have cached the default # number_of_partitions functions which is currently using FLINT. # AM trac #13072 -cached_number_of_partitions = cached_function( flint_number_of_partitions ) +cached_number_of_partitions = cached_function(flint_number_of_partitions) # October 2012: fixing outdated pickles which use classes being deprecated from sage.misc.persist import register_unpickle_override diff --git a/src/sage/combinat/path_tableaux/catalog.py b/src/sage/combinat/path_tableaux/catalog.py index 8cb7f2d322d..0605c6da583 100644 --- a/src/sage/combinat/path_tableaux/catalog.py +++ b/src/sage/combinat/path_tableaux/catalog.py @@ -6,7 +6,7 @@ object is an easy way to discover and quickly create the path tableaux that are available (as listed here). -Let ```` indicate pressing the tab key. So begin by typing +Let ```` indicate pressing the :kbd:`Tab` key. So begin by typing ``path_tableaux.`` to the see the currently implemented path tableaux. - :class:`~sage.combinat.path_tableaux.path_tableau.CylindricalDiagram` diff --git a/src/sage/combinat/permutation.py b/src/sage/combinat/permutation.py index f6d802e2beb..7794a7e204b 100644 --- a/src/sage/combinat/permutation.py +++ b/src/sage/combinat/permutation.py @@ -2216,8 +2216,8 @@ def longest_increasing_subsequence_length(self) -> Integer: def longest_increasing_subsequences(self): r""" - Return the list of the longest increasing subsequences of ``self`` - + Return the list of the longest increasing subsequences of ``self``. + A theorem of Schensted ([Sch1961]_) states that an increasing subsequence of length `i` ends with the value entered in the `i`-th column of the p-tableau. The algorithm records which column of the @@ -2247,9 +2247,9 @@ def longest_increasing_subsequences(self): # getting the column in which each element is inserted first_row_p_tableau = [] columns = [] - D = DiGraph(n+2) + D = DiGraph(n + 2) for x in self._list: - j = bisect(first_row_p_tableau, x) + j = bisect(first_row_p_tableau, x) if j == len(first_row_p_tableau): if columns: for k in columns[-1]: @@ -7552,6 +7552,32 @@ def from_lehmer_code(lehmer, parent=None): parent = Permutations() return parent(p) +def from_lehmer_cocode(lehmer, parent=Permutations()): + r""" + Return the permutation with Lehmer cocode ``lehmer``. + + The Lehmer cocode of a permutation `p` is defined as the + list `(c_1, c_2, \ldots, c_n)`, where `c_i` is the number + of `j < i` such that `p(j) > p(i)`. + + EXAMPLES:: + + sage: import sage.combinat.permutation as permutation + sage: lcc = Permutation([2,1,5,4,3]).to_lehmer_cocode(); lcc + [0, 1, 0, 1, 2] + sage: permutation.from_lehmer_cocode(lcc) + [2, 1, 5, 4, 3] + """ + p = [] + ell = len(lehmer) + i = ell-1 + open_spots = list(range(1, ell+1)) + for ivi in reversed(lehmer): + p.append(open_spots.pop(i-ivi)) + i -= 1 + p.reverse() + return parent(p) + def from_reduced_word(rw, parent=None): r""" Return the permutation corresponding to the reduced word ``rw``. diff --git a/src/sage/combinat/plane_partition.py b/src/sage/combinat/plane_partition.py index 49edf8abdea..c8b29e06294 100644 --- a/src/sage/combinat/plane_partition.py +++ b/src/sage/combinat/plane_partition.py @@ -25,21 +25,22 @@ from __future__ import annotations from typing import Iterator -from sage.structure.list_clone import ClonableArray -from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.combinat.posets.posets import Poset -from sage.rings.integer import Integer -from sage.misc.misc_c import prod from sage.combinat.tableau import Tableau +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.misc.lazy_import import lazy_import +from sage.misc.misc_c import prod +from sage.modules.free_module_element import vector +from sage.rings.integer import Integer +from sage.structure.list_clone import ClonableArray +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation lazy_import("sage.plot.plot3d.platonic", "cube") class PlanePartition(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): + metaclass=InheritComparisonClasscallMetaclass): r""" A plane partition. @@ -396,6 +397,70 @@ def pp(self, show_box=False): """ print(self._repr_diagram(show_box)) + def _repr_svg_(self) -> str: + """ + Return the svg picture of a plane partition. + + This can be displayed by Jupyter. + + EXAMPLES:: + + sage: PP = PlanePartition([[2, 1, 1], [1, 1]]) + sage: PP._repr_svg_() + '' + """ + colors = ["snow", "tomato", "steelblue"] + + resu = '' + resu += '' + resu += '' + resu1 += '' + resu1 += '' + resu1 += '' + def _latex_(self, show_box=False, colors=["white", "lightgray", "darkgray"]) -> str: r""" @@ -622,8 +687,8 @@ def is_SPP(self) -> bool: for j in range(c2): T[i][j] = Z[i][j] return all(T[r][c] == T[c][r] - for r in range(size) - for c in range(r, size)) + for r in range(size) + for c in range(r, size)) def is_CSPP(self) -> bool: r""" 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/combinat/ribbon_tableau.py b/src/sage/combinat/ribbon_tableau.py index 8b703ee721b..dd4e179574b 100644 --- a/src/sage/combinat/ribbon_tableau.py +++ b/src/sage/combinat/ribbon_tableau.py @@ -15,6 +15,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** +import functools from sage.structure.parent import Parent from sage.structure.element import parent @@ -22,17 +23,15 @@ from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.sets_cat import Sets from sage.rings.integer_ring import ZZ -from sage.rings.rational_field import QQ from sage.rings.integer import Integer from sage.combinat.combinat import CombinatorialElement from sage.combinat.skew_partition import SkewPartition, SkewPartitions from sage.combinat.skew_tableau import SkewTableau, SkewTableaux, SemistandardSkewTableaux from sage.combinat.tableau import Tableaux from sage.combinat.partition import Partition, _Partitions -from . import permutation -import functools - from sage.combinat.permutation import to_standard +from sage.misc.persist import register_unpickle_override +from . import permutation class RibbonTableau(SkewTableau): @@ -76,8 +75,8 @@ class RibbonTableau(SkewTableau): sage: RibbonTableau([[0, 0, 3, 0], [1, 1, 0], [2, 0, 4]]).evaluation() [2, 1, 1, 1] """ - #The following method is private and will only get called - #when calling RibbonTableau() directly, and not via element_class + # The following method is private and will only get called + # when calling RibbonTableau() directly, and not via element_class @staticmethod def __classcall_private__(cls, rt=None, expr=None): """ @@ -98,7 +97,7 @@ def __classcall_private__(cls, rt=None, expr=None): raise TypeError("each element of the ribbon tableau must be an iterable") if not all(row for row in rt): raise TypeError("a ribbon tableau cannot have empty rows") - #calls the inherited __init__ method (of SkewTableau ) + # calls the inherited __init__ method (of SkewTableau ) return RibbonTableaux()(rt) def length(self): @@ -146,9 +145,9 @@ def to_word(self): from sage.combinat.words.word import Word return Word([letter for row in reversed(self) for letter in row]) -##################### -# Ribbon Tableaux # -##################### +# =================== +# Ribbon Tableaux +# =================== class RibbonTableaux(UniqueRepresentation, Parent): @@ -213,7 +212,7 @@ def __classcall_private__(cls, shape=None, weight=None, length=None): True """ if shape is None and weight is None and length is None: - return super(RibbonTableaux, cls).__classcall__(cls) + return super().__classcall__(cls) return RibbonTableaux_shape_weight_length(shape, weight, length) @@ -293,10 +292,10 @@ def __classcall_private__(cls, shape, weight, length): else: shape = SkewPartition(shape) - if shape.size() != length*sum(weight): - raise ValueError("Incompatible shape and weight") + if shape.size() != length * sum(weight): + raise ValueError("incompatible shape and weight") - return super(RibbonTableaux, cls).__classcall__(cls, shape, tuple(weight), length) + return super().__classcall__(cls, shape, tuple(weight), length) def __init__(self, shape, weight, length): """ @@ -305,7 +304,7 @@ def __init__(self, shape, weight, length): sage: R = RibbonTableaux([[2,1],[]],[1,1,1],1) sage: TestSuite(R).run() """ - self._shape = shape + self._shape = shape self._weight = weight self._length = length Parent.__init__(self, category=FiniteEnumeratedSets()) @@ -355,8 +354,8 @@ def __contains__(self, x): return False return x in self.list() - #return x.is_ribbon() and x.shape() == self._shape \ - #and tuple(x.weight()) == self._weight and x in list(self) + # return x.is_ribbon() and x.shape() == self._shape \ + # and tuple(x.weight()) == self._weight and x in list(self) def cardinality(self): """ @@ -449,14 +448,14 @@ def insertion_tableau(skp, perm, evaluation, tableau, length): [[1], [[1, 0], [0]]] """ psave = Partition(skp[1]) - partc = skp[1] + [0]*(len(skp[0])-len(skp[1])) + partc = skp[1] + [0] * (len(skp[0]) - len(skp[1])) tableau = SkewTableau(expr=tableau).to_expr()[1] for k in range(len(tableau)): - tableau[-(k+1)] += [0] * ( skp[0][k] - partc[k] - len(tableau[-(k+1)])) + tableau[-(k + 1)] += [0] * (skp[0][k] - partc[k] - len(tableau[-(k + 1)])) - ## We construct a tableau from the southwest corner to the northeast one + # We construct a tableau from the southwest corner to the northeast one tableau = [[0] * (skp[0][k] - partc[k]) for k in reversed(range(len(tableau), len(skp[0])))] + tableau @@ -464,16 +463,17 @@ def insertion_tableau(skp, perm, evaluation, tableau, length): tableau = tableau.to_expr()[1] skp = SkewPartition(skp).conjugate().to_list() - skp[1].extend( [0]*(len(skp[0])-len(skp[1])) ) + skp[1].extend([0] * (len(skp[0]) - len(skp[1]))) if len(perm) > len(skp[0]): return None - for k in range(len(perm)): - if perm[ -(k+1) ] !=0: - tableau[len(tableau)-len(perm)+k][ skp[0][len(perm)-(k+1)] - skp[1][ len(perm)-(k+1) ] - 1 ] = evaluation + lp = len(perm) + for k in range(lp): + if perm[-(k + 1)] != 0: + tableau[len(tableau) - lp + k][skp[0][lp - (k + 1)] - skp[1][lp - (k + 1)] - 1] = evaluation - return SkewTableau(expr=[psave.conjugate(),tableau]).conjugate().to_expr() + return SkewTableau(expr=[psave.conjugate(), tableau]).conjugate().to_expr() def count_rec(nexts, current, part, weight, length): @@ -547,30 +547,28 @@ def list_rec(nexts, current, part, weight, length): [[[], [[2, 2], [1, 1]]]] """ if current == [] and nexts == [] and weight == []: - return [[part[1],[]]] + return [[part[1], []]] - ## Test if the current nodes is not an empty node + # Test if the current nodes is not an empty node if not current: return [] - ## Test if the current nodes drive us to new solutions + # Test if the current nodes drive us to new solutions if nexts: - res = [] - for i in range(len(current)): - for j in range(len(nexts[i])): - res.append( insertion_tableau(part, current[i][1], len(weight), nexts[i][j], length) ) - return res - else: - ## The current nodes are at the bottom of the tree - res = [] - for i in range(len(current)): - res.append( insertion_tableau(part, current[i][1], len(weight), [[],[]], length) ) - return res + return [insertion_tableau(part, curr_i[1], len(weight), + nexts_ij, length) + for nexts_i, curr_i in zip(nexts, current) + for nexts_ij in nexts_i] + + # The current nodes are at the bottom of the tree + return [insertion_tableau(part, curr_i[1], + len(weight), [[], []], length) + for curr_i in current] -############################# -#Spin and Cospin Polynomials# -############################# +# =============================== +# Spin and Cospin Polynomials +# =============================== def spin_rec(t, nexts, current, part, weight, length): """ Routine used for constructing the spin polynomial. @@ -606,19 +604,18 @@ def spin_rec(t, nexts, current, part, weight, length): partp = part[0].conjugate() ell = len(partp) - #compute the contribution of the ribbons added at - #the current node + # compute the contribution of the ribbons added at + # the current node for val in current: perms = val[1] perm = [partp[i] + ell - (i + 1) - perms[i] for i in reversed(range(ell))] perm = to_standard(perm) - tmp.append( weight[-1]*(length-1) - perm.number_of_inversions() ) + tmp.append(weight[-1] * (length - 1) - perm.number_of_inversions()) if nexts: - return [ sum(sum(t**tval * nval for nval in nexts[i]) - for i, tval in enumerate(tmp)) ] - else: - return [ sum(t**val for val in tmp) ] + return [sum(sum(t**tval * nval for nval in nexts[i]) + for i, tval in enumerate(tmp))] + return [sum(t**val for val in tmp)] def spin_polynomial_square(part, weight, length): @@ -647,15 +644,16 @@ def spin_polynomial_square(part, weight, length): R = ZZ['t'] if part in _Partitions: - part = SkewPartition([part,_Partitions([])]) + part = SkewPartition([part, _Partitions([])]) elif part in SkewPartitions(): part = SkewPartition(part) - if part == [[],[]] and weight == []: + if part == [[], []] and not weight: return R.one() t = R.gen() - return R(graph_implementation_rec(part, weight, length, functools.partial(spin_rec,t))[0]) + return R(graph_implementation_rec(part, weight, length, + functools.partial(spin_rec, t))[0]) def spin_polynomial(part, weight, length): @@ -685,7 +683,7 @@ def spin_polynomial(part, weight, length): sp = spin_polynomial_square(part, weight, length) t = SR.var('t') coeffs = sp.list() - return sum(c * t**(QQ(i)/2) for i,c in enumerate(coeffs)) + return sum(c * t**(ZZ(i) / 2) for i, c in enumerate(coeffs)) def cospin_polynomial(part, weight, length): @@ -720,22 +718,22 @@ def cospin_polynomial(part, weight, length): if sp == 0: return R.zero() - coeffs = [c for c in sp.list() if c != 0] + coeffs = [c for c in sp.list() if c] d = len(coeffs) - 1 t = R.gen() - return R( sum(c * t**(d-i) for i,c in enumerate(coeffs)) ) + return R(sum(c * t**(d - i) for i, c in enumerate(coeffs))) -## ////////////////////////////////////////////////////////////////////////////////////////// -## // Generic function for driving into the graph of partitions coding all ribbons -## // tableaux of a given shape and weight -## ////////////////////////////////////////////////////////////////////////////////////////// -## //This function construct the graph of the set of k-ribbon tableaux -## //of a given skew shape and a given weight. -## //The first argument is always a skew partition. -## //In the case where the inner partition is empty there is no branch without solutions -## //In the other cases there is in average a lot of branches without solutions -## ///////////////////////////////////////////////////////////////////////////////////////// +# ////////////////////////////////////////////////////////////////////////////////////////// +# // Generic function for driving into the graph of partitions coding all ribbons +# // tableaux of a given shape and weight +# ////////////////////////////////////////////////////////////////////////////////////////// +# // This function constructs the graph of the set of k-ribbon tableaux +# // of a given skew shape and a given weight. +# // The first argument is always a skew partition. +# // In the case where the inner partition is empty, there is no branch without solutions. +# // In the other cases, there is in average a lot of branches without solutions. +# ///////////////////////////////////////////////////////////////////////////////////////// def graph_implementation_rec(skp, weight, length, function): @@ -760,16 +758,16 @@ def graph_implementation_rec(skp, weight, length, function): # Some tests in order to know if the shape and the weight are compatible. if weight and weight[-1] <= len(partp): - perms = permutation.Permutations([0]*(len(partp)-weight[-1]) + [length]*(weight[-1])).list() + perms = permutation.Permutations([0] * (len(partp) - weight[-1]) + [length] * (weight[-1])).list() else: return function([], [], skp, weight, length) selection = [] for j in range(len(perms)): - retire = [(val + ell - (i+1) - perms[j][i]) for i,val in enumerate(partp)] + retire = [(val + ell - (i + 1) - perms[j][i]) for i, val in enumerate(partp)] retire.sort(reverse=True) - retire = [val - ell + (i+1) for i,val in enumerate(retire)] + retire = [val - ell + (i + 1) for i, val in enumerate(retire)] if retire[-1] >= 0 and retire == sorted(retire, reverse=True): retire = Partition(retire).conjugate() @@ -784,19 +782,17 @@ def graph_implementation_rec(skp, weight, length, function): if append: selection.append([retire, perms[j]]) - #selection contains the list of current nodes + # selection contains the list of current nodes if len(weight) == 1: return function([], selection, skp, weight, length) else: - #The recursive calls permit us to construct the list of the sons - #of all current nodes in selection + # The recursive calls permit us to construct the list of the sons + # of all current nodes in selection a = [graph_implementation_rec([p[0], outer], weight[:-1], length, function) for p in selection] return function(a, selection, skp, weight, length) -############################################################## - class MultiSkewTableau(CombinatorialElement): """ @@ -828,12 +824,13 @@ def __classcall_private__(cls, x): """ if isinstance(x, MultiSkewTableau): return x - - return MultiSkewTableaux()([SkewTableau(i) for i in x] ) + return MultiSkewTableaux()([SkewTableau(i) for i in x]) def size(self): """ - Return the size of ``self``, which is the sum of the sizes of the skew + Return the size of ``self``. + + This is the sum of the sizes of the skew tableaux in ``self``. EXAMPLES:: @@ -858,7 +855,7 @@ def weight(self): """ weights = [x.weight() for x in self] m = max([len(x) for x in weights]) - weight = [0]*m + weight = [0] * m for w in weights: for i in range(len(w)): weight[i] += w[i] @@ -896,7 +893,7 @@ def inversion_pairs(self): inv = [] for k in range(len(self)): for b in self[k].cells(): - inv += self._inversion_pairs_from_position(k,b) + inv += self._inversion_pairs_from_position(k, b) return inv def inversions(self): @@ -937,25 +934,25 @@ def _inversion_pairs_from_position(self, k, ij): [((1, (0, 1)), (2, (0, 0)))] """ pk = k - pi,pj = ij + pi, pj = ij c = pi - pj value = self[pk][pi][pj] pk_cells = self[pk].cells_by_content(c) - same_diagonal = [ t.cells_by_content(c) for t in self[pk+1:] ] - above_diagonal = [ t.cells_by_content(c+1) for t in self[pk+1:] ] + same_diagonal = [t.cells_by_content(c) for t in self[pk + 1:]] + above_diagonal = [t.cells_by_content(c + 1) for t in self[pk + 1:]] res = [] - for i,j in pk_cells: + for i, j in pk_cells: if pi < i and value > self[pk][i][j]: - res.append( ((pk,(pi,pj)), (pk,(i,j))) ) + res.append(((pk, (pi, pj)), (pk, (i, j)))) for k in range(len(same_diagonal)): - for i,j in same_diagonal[k]: - if value > self[pk+k+1][i][j]: - res.append( ((pk,(pi,pj)), (pk+k+1,(i,j))) ) + for i, j in same_diagonal[k]: + if value > self[pk + k + 1][i][j]: + res.append(((pk, (pi, pj)), (pk + k + 1, (i, j)))) for k in range(len(above_diagonal)): - for i,j in above_diagonal[k]: - if value < self[pk+k+1][i][j]: - res.append( ((pk,(pi,pj)), (pk+k+1,(i,j))) ) + for i, j in above_diagonal[k]: + if value < self[pk + k + 1][i][j]: + res.append(((pk, (pi, pj)), (pk + k + 1, (i, j)))) return res @@ -1042,7 +1039,7 @@ def __classcall_private__(cls, shape, weight): if sum(weight) != sum(s.size() for s in shape): raise ValueError("the sum of weight must be the sum of the sizes of shape") - return super(SemistandardMultiSkewTableaux, cls).__classcall__(cls, shape, weight) + return super().__classcall__(cls, shape, weight) def __init__(self, shape, weight): """ @@ -1051,7 +1048,7 @@ def __init__(self, shape, weight): sage: S = SemistandardMultiSkewTableaux([ [[2,1],[]], [[2,2],[1]] ], [2,2,2]) sage: TestSuite(S).run() """ - self._shape = shape + self._shape = shape self._weight = weight MultiSkewTableaux.__init__(self, category=FiniteEnumeratedSets()) @@ -1080,14 +1077,9 @@ def __contains__(self, x): return False if x.weight() != list(self._weight): return False - if x.shape() != list(self._shape): return False - - if not all( x[i].is_semistandard() for i in range(len(x)) ): - return False - - return True + return all(xi.is_semistandard() for xi in x) def __iter__(self): """ @@ -1097,8 +1089,6 @@ def __iter__(self): sage: SemistandardMultiSkewTableaux([SkewPartition([[1, 1, 1], []]), SkewPartition([[3], []])],[2,2,2]).list() [[[[1], [2], [3]], [[1, 2, 3]]]] - :: - sage: a = SkewPartition([[8,7,6,5,1,1],[2,1,1]]) sage: weight = [3,3,2] sage: k = 3 @@ -1120,21 +1110,21 @@ def __iter__(self): for i in range(1, len(parts)): trans = parttmp[0][0] current_part = parts[i] - current_part[1] += [0]*(len(current_part[0])-len(current_part[1])) - inner_current = [ trans + j for j in current_part[1] ] - outer_current = [ trans + j for j in current_part[0] ] - parttmp = [ outer_current + parttmp[0], inner_current + parttmp[1] ] + current_part[1] += [0] * (len(current_part[0]) - len(current_part[1])) + inner_current = [trans + j for j in current_part[1]] + outer_current = [trans + j for j in current_part[0]] + parttmp = [outer_current + parttmp[0], inner_current + parttmp[1]] # List the corresponding skew tableaux - l = [ st.to_word() for st in SemistandardSkewTableaux(parttmp, mu) ] + l = (st.to_word() for st in SemistandardSkewTableaux(parttmp, mu)) S = SkewTableaux() - for k in range(len(l)): - pos = 0 #Double check this - restmp = [ S.from_shape_and_word(parts[0], [l[k][j] for j in range(s[0])]) ] + for lk in l: + pos = 0 # Double check this + restmp = [S.from_shape_and_word(parts[0], [lk[j] for j in range(s[0])])] for i in range(1, len(parts)): - w = [l[k][j] for j in range(pos+s[i-1], pos+s[i-1]+s[i])] - restmp.append( S.from_shape_and_word(parts[i], w) ) + w = [lk[j] for j in range(pos + s[i - 1], pos + s[i - 1] + s[i])] + restmp.append(S.from_shape_and_word(parts[i], w)) yield self.element_class(self, restmp) @@ -1156,7 +1146,7 @@ def __setstate__(self, state): self.__class__ = RibbonTableau self.__init__(RibbonTableaux(), state['_list']) -from sage.misc.persist import register_unpickle_override + register_unpickle_override('sage.combinat.ribbon_tableau', 'RibbonTableau_class', RibbonTableau_class) register_unpickle_override('sage.combinat.ribbon_tableau', 'RibbonTableaux_shapeweightlength', RibbonTableaux) register_unpickle_override('sage.combinat.ribbon_tableau', 'SemistandardMultiSkewTtableaux_shapeweight', SemistandardMultiSkewTableaux) diff --git a/src/sage/combinat/root_system/reflection_group_real.py b/src/sage/combinat/root_system/reflection_group_real.py index 9e5c2e2c1b0..7420f03d24a 100644 --- a/src/sage/combinat/root_system/reflection_group_real.py +++ b/src/sage/combinat/root_system/reflection_group_real.py @@ -706,7 +706,7 @@ def simple_root_index(self, i): [0, 1, 2] """ return self._index_set_inverse[i] - + def bruhat_cone(self, x, y, side='upper', backend='cdd'): r""" Return the (upper or lower) Bruhat cone associated to the interval ``[x,y]``. diff --git a/src/sage/combinat/root_system/weyl_group.py b/src/sage/combinat/root_system/weyl_group.py index 42aa218115c..efcdce97384 100644 --- a/src/sage/combinat/root_system/weyl_group.py +++ b/src/sage/combinat/root_system/weyl_group.py @@ -6,13 +6,11 @@ - Daniel Bump (2008): initial version - Mike Hansen (2008): initial version - Anne Schilling (2008): initial version -- Nicolas Thiery (2008): initial version +- Nicolas Thiéry (2008): initial version - Volker Braun (2013): LibGAP-based matrix groups EXAMPLES: -More examples on Weyl Groups should be added here... - The Cayley graph of the Weyl Group of type ['A', 3]:: sage: w = WeylGroup(['A',3]) @@ -26,8 +24,12 @@ sage: d = w.cayley_graph(); d Digraph on 192 vertices sage: d.show3d(color_by_label=True, edge_size=0.01, vertex_size=0.03) #long time (less than one minute) + +.. TODO:: + + More examples on Weyl Groups should be added here. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Daniel Bump , # Mike Hansen # Anne Schilling @@ -35,8 +37,8 @@ # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.groups.matrix_gps.finitely_generated import FinitelyGeneratedMatrixGroup_gap from sage.groups.matrix_gps.group_element import MatrixGroupElement_gap from sage.groups.perm_gps.permgroup import PermutationGroup_generic @@ -59,12 +61,12 @@ def WeylGroup(x, prefix=None, implementation='matrix'): """ - Returns the Weyl group of the root system defined by the Cartan + Return the Weyl group of the root system defined by the Cartan type (or matrix) ``ct``. INPUT: - - ``x`` - a root system or a Cartan type (or matrix) + - ``x`` -- a root system or a Cartan type (or matrix) OPTIONAL: @@ -236,7 +238,7 @@ def __init__(self, domain, prefix): category = WeylGroups() if self.cartan_type().is_irreducible(): category = category.Irreducible() - self.n = domain.dimension() # Really needed? + self.n = domain.dimension() # Really needed? self._prefix = prefix # FinitelyGeneratedMatrixGroup_gap takes plain matrices as input @@ -252,7 +254,7 @@ def __init__(self, domain, prefix): @cached_method def cartan_type(self): """ - Returns the CartanType associated to self. + Return the ``CartanType`` associated to ``self``. EXAMPLES:: @@ -265,7 +267,7 @@ def cartan_type(self): @cached_method def index_set(self): """ - Returns the index set of self. + Return the index set of ``self``. EXAMPLES:: @@ -289,7 +291,7 @@ def from_morphism(self, f): @cached_method def simple_reflections(self): """ - Returns the simple reflections of self, as a family. + Return the simple reflections of ``self``, as a family. EXAMPLES: @@ -393,13 +395,13 @@ def _repr_(self): Weyl Group of type ['A', 3, 1] (as a matrix group acting on the root space) """ return "Weyl Group of type %s (as a matrix group acting on the %s)" % (self.cartan_type(), - self._domain._name_string(capitalize=False, - base_ring=False, - type=False)) + self._domain._name_string(capitalize=False, + base_ring=False, + type=False)) def character_table(self): """ - Returns the character table as a matrix + Return the character table as a matrix. Each row is an irreducible character. For larger tables you may preface this with a command such as @@ -421,14 +423,14 @@ def character_table(self): X.4 3 -1 1 . -1 X.5 1 1 1 1 1 """ - gens_str = ', '.join(str(g.gap()) for g in self.gens()) + gens_str = ', '.join(str(g.gap()) for g in self.gens()) ctbl = gap('CharacterTable(Group({0}))'.format(gens_str)) return ctbl.Display() @cached_method def one(self): """ - Returns the unit element of the Weyl group + Return the unit element of the Weyl group. EXAMPLES:: @@ -441,13 +443,13 @@ def one(self): sage: type(e) == W.element_class True """ - return self._element_constructor_(matrix(QQ,self.n,self.n,1)) + return self._element_constructor_(matrix(QQ, self.n, self.n, 1)) - unit = one # For backward compatibility + unit = one # For backward compatibility def domain(self): """ - Returns the domain of the element of ``self``, that is the + Return the domain of the element of ``self``, that is the root lattice realization on which they act. EXAMPLES:: @@ -463,7 +465,7 @@ def domain(self): def simple_reflection(self, i): """ - Returns the `i^{th}` simple reflection. + Return the `i^{th}` simple reflection. EXAMPLES:: @@ -485,7 +487,7 @@ def simple_reflection(self, i): def long_element_hardcoded(self): """ - Returns the long Weyl group element (hardcoded data) + Return the long Weyl group element (hardcoded data). Do we really want to keep it? There is a generic implementation which works in all cases. The hardcoded should @@ -497,22 +499,22 @@ def long_element_hardcoded(self): sage: types = [ ['A',5],['B',3],['C',3],['D',4],['G',2],['F',4],['E',6] ] sage: [WeylGroup(t).long_element().length() for t in types] [15, 9, 9, 12, 6, 24, 36] - sage: all( WeylGroup(t).long_element() == WeylGroup(t).long_element_hardcoded() for t in types ) # long time (17s on sage.math, 2011) + sage: all(WeylGroup(t).long_element() == WeylGroup(t).long_element_hardcoded() for t in types) # long time (17s on sage.math, 2011) True """ type = self.cartan_type() - if type[0] == 'D' and type[1]%2 == 1: - l = [-1 for i in range(self.n-1)] + if type[0] == 'D' and type[1] % 2: + l = [-1 for i in range(self.n - 1)] l.append(1) - m = diagonal_matrix(QQ,l) + m = diagonal_matrix(QQ, l) elif type[0] == 'A': l = [0 for k in range((self.n)**2)] - for k in range(self.n-1, (self.n)**2-1, self.n-1): + for k in range(self.n - 1, (self.n)**2 - 1, self.n - 1): l[k] = 1 m = matrix(QQ, self.n, l) elif type[0] == 'E': if type[1] == 6: - half = ZZ(1)/ZZ(2) + half = ZZ(1) / ZZ(2) l = [[-half, -half, -half, half, 0, 0, 0, 0], [-half, -half, half, -half, 0, 0, 0, 0], [-half, half, -half, -half, 0, 0, 0, 0], @@ -523,10 +525,10 @@ def long_element_hardcoded(self): [0, 0, 0, 0, -half, half, half, half]] m = matrix(QQ, 8, l) else: - raise NotImplementedError("Not implemented yet for this type") + raise NotImplementedError("not implemented yet for this type") elif type[0] == 'G': - third = ZZ(1)/ZZ(3) - twothirds = ZZ(2)/ZZ(3) + third = ZZ(1) / ZZ(3) + twothirds = ZZ(2) / ZZ(3) l = [[-third, twothirds, twothirds], [twothirds, -third, twothirds], [twothirds, twothirds, -third]] @@ -559,6 +561,7 @@ def classical(self): raise ValueError("classical subgroup only defined for affine types") return ClassicalWeylSubgroup(self._domain, prefix=self._prefix) + class ClassicalWeylSubgroup(WeylGroup_gens): """ A class for Classical Weyl Subgroup of an affine Weyl Group @@ -638,9 +641,9 @@ def __repr__(self): Parabolic Subgroup of the Weyl Group of type ['C', 4, 1]^* (as a matrix group acting on the coweight lattice) """ return "Parabolic Subgroup of the Weyl Group of type %s (as a matrix group acting on the %s)" % (self.domain().cartan_type(), - self._domain._name_string(capitalize=False, - base_ring=False, - type=False)) + self._domain._name_string(capitalize=False, + base_ring=False, + type=False)) def weyl_group(self, prefix="hereditary"): """ @@ -672,6 +675,7 @@ def _test_is_finite(self, **options): tester.assertTrue(not self.weyl_group(self._prefix).is_finite()) tester.assertTrue(self.is_finite()) + class WeylGroupElement(MatrixGroupElement_gap): """ Class for a Weyl Group elements @@ -705,7 +709,7 @@ def to_matrix(self): def domain(self): """ - Returns the ambient lattice associated with self. + Return the ambient lattice associated with ``self``. EXAMPLES:: @@ -789,8 +793,8 @@ def __eq__(self, other): purposes. """ return (self.__class__ == other.__class__ and - self._parent == other._parent and - self.matrix() == other.matrix()) + self._parent == other._parent and + self.matrix() == other.matrix()) def _richcmp_(self, other, op): """ @@ -835,15 +839,14 @@ def action(self, v): alpha[0] + alpha[1] """ if v not in self.domain(): - raise ValueError("{} is not in the domain".format(v)) - return self.domain().from_vector(self.matrix()*v.to_vector()) + raise ValueError(f"{v} is not in the domain") + return self.domain().from_vector(self.matrix() * v.to_vector()) - - ########################################################################## + # ####################################################################### # Descents - ########################################################################## + # ####################################################################### - def has_descent(self, i, positive=False, side = "right"): + def has_descent(self, i, positive=False, side="right"): """ Test if ``self`` has a descent at position ``i``. @@ -934,7 +937,7 @@ def has_left_descent(self, i): sage: [(s[3]*s[2]).has_left_descent(i) for i in W.domain().index_set()] [False, False, True] """ - return self.has_descent(i, side = "left") + return self.has_descent(i, side="left") def has_right_descent(self, i): """ @@ -957,13 +960,14 @@ def has_right_descent(self, i): """ return self.has_descent(i, side="right") - def apply_simple_reflection(self, i, side = "right"): + def apply_simple_reflection(self, i, side="right"): s = self.parent().simple_reflections() if side == "right": return self * s[i] else: return s[i] * self +# TODO # The methods first_descent, descents, reduced_word appear almost verbatim in # root_lattice_realizations and need to be factored out! @@ -978,9 +982,8 @@ def to_permutation(self): """ W = self.parent() e = W.domain().basis() - return tuple( c*(j+1) - for i in e.keys() - for (j,c) in self.action(e[i]) ) + return tuple(c * (j + 1) for i in e.keys() + for (j, c) in self.action(e[i])) def to_permutation_string(self): """ @@ -993,6 +996,7 @@ def to_permutation_string(self): """ return "".join(str(i) for i in self.to_permutation()) + WeylGroup_gens.Element = WeylGroupElement @@ -1025,13 +1029,12 @@ def __init__(self, cartan_type, prefix): """ self._cartan_type = cartan_type self._index_set = cartan_type.index_set() - self._index_set_inverse = {ii: i for i,ii in enumerate(cartan_type.index_set())} + self._index_set_inverse = {ii: i for i, ii in enumerate(cartan_type.index_set())} self._reflection_representation = None self._prefix = prefix - #from sage.libs.gap.libgap import libgap Q = cartan_type.root_system().root_lattice() Phi = list(Q.positive_roots()) + [-x for x in Q.positive_roots()] - p = [[Phi.index(x.weyl_action([i]))+1 for x in Phi] + p = [[Phi.index(x.weyl_action([i])) + 1 for x in Phi] for i in self._cartan_type.index_set()] cat = FiniteWeylGroups() if self._cartan_type.is_irreducible(): @@ -1207,7 +1210,7 @@ def reflection_index_set(self): sage: W.reflection_index_set() (1, 2, 3, 4, 5, 6) """ - return tuple(range(1, self.number_of_reflections()+1)) + return tuple(range(1, self.number_of_reflections() + 1)) def cartan_type(self): """ @@ -1301,9 +1304,9 @@ def distinguished_reflections(self): def build_elt(index): r = pos_roots[index] - perm = [Phi.index(x.reflection(r))+1 for x in Phi] + perm = [Phi.index(x.reflection(r)) + 1 for x in Phi] return self.element_class(perm, self, check=False) - return Family(self.reflection_index_set(), lambda i: build_elt(i-1)) + return Family(self.reflection_index_set(), lambda i: build_elt(i - 1)) reflections = distinguished_reflections diff --git a/src/sage/combinat/schubert_polynomial.py b/src/sage/combinat/schubert_polynomial.py index 794dc7ee2c6..07d679ac65d 100644 --- a/src/sage/combinat/schubert_polynomial.py +++ b/src/sage/combinat/schubert_polynomial.py @@ -2,7 +2,7 @@ Schubert Polynomials -See :wikipedia:`Schubert_polynomial` and +See :wikipedia:`Schubert_polynomial` and `SymmetricFunctions.com `_. Schubert polynomials are representatives of cohomology classes in flag varieties. In `n` variables, they are indexed by permutations `w \in S_n`. They also form diff --git a/src/sage/combinat/set_partition_ordered.py b/src/sage/combinat/set_partition_ordered.py index f2f201eb7f2..3bb081310ea 100644 --- a/src/sage/combinat/set_partition_ordered.py +++ b/src/sage/combinat/set_partition_ordered.py @@ -25,36 +25,36 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from sage.arith.all import factorial, multinomial -from sage.sets.set import Set, Set_generic +from sage.categories.cartesian_product import cartesian_product from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets -from sage.sets.finite_enumerated_set import FiniteEnumeratedSet -from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass -from sage.structure.parent import Parent -from sage.structure.element import parent -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.list_clone import ClonableArray -from sage.structure.richcmp import richcmp -from sage.rings.integer import Integer -from sage.rings.integer_ring import ZZ -from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.combinat import stirling_number2 +from sage.combinat.combinatorial_map import combinatorial_map from sage.combinat.composition import Composition, Compositions -from sage.combinat.words.words import Words from sage.combinat.words.finite_word import FiniteWord_class -import sage.combinat.permutation as permutation -from functools import reduce -from sage.categories.cartesian_product import cartesian_product +from sage.combinat.words.words import Words +from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass +from sage.misc.persist import register_unpickle_override +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ +from sage.sets.finite_enumerated_set import FiniteEnumeratedSet +from sage.sets.set import Set, Set_generic +from sage.structure.list_clone import ClonableArray +from sage.structure.element import parent +from sage.structure.parent import Parent +from sage.structure.richcmp import richcmp +from sage.structure.unique_representation import UniqueRepresentation class OrderedSetPartition(ClonableArray, - metaclass=InheritComparisonClasscallMetaclass): + metaclass=InheritComparisonClasscallMetaclass): r""" An ordered partition of a set. An ordered set partition `p` of a set `s` is a list of pairwise disjoint nonempty subsets of `s` such that the union of these subsets is `s`. These subsets are called the parts of the partition. + We represent an ordered set partition as a list of sets. By extension, an ordered set partition of a nonnegative integer `n` is the set partition of the integers from `1` to `n`. The number of @@ -146,12 +146,16 @@ class OrderedSetPartition(ClonableArray, sage: OrderedSetPartition(from_word='bdab') [{3}, {1, 4}, {2}] + .. WARNING:: + + The elements of the underlying set should be hashable. + REFERENCES: :wikipedia:`Ordered_partition_of_a_set` """ @staticmethod - def __classcall_private__(cls, parts=None, from_word=None): + def __classcall_private__(cls, parts=None, from_word=None, check=True): """ Create a set partition from ``parts`` with the appropriate parent. @@ -179,17 +183,16 @@ def __classcall_private__(cls, parts=None, from_word=None): if parts is None and from_word is None: P = OrderedSetPartitions([]) return P.element_class(P, []) + W = Words(infinite=False) if from_word: - return OrderedSetPartitions().from_finite_word(Words()(from_word)) + return OrderedSetPartitions().from_finite_word(W(from_word)) # if `parts` looks like a sequence of "letters" then treat it like a word. - if parts in Words() or (parts and (parts[0] in ZZ or isinstance(parts[0], str))): - return OrderedSetPartitions().from_finite_word(Words()(parts)) - else: - P = OrderedSetPartitions(reduce(lambda x, y: x.union(y), - parts, frozenset())) - return P.element_class(P, parts) + if parts in W or (parts and (parts[0] in ZZ or isinstance(parts[0], str))): + return OrderedSetPartitions().from_finite_word(W(parts)) + P = OrderedSetPartitions(set(x for p in parts for x in p)) + return P.element_class(P, parts, check=check) - def __init__(self, parent, s): + def __init__(self, parent, s, check=True): """ Initialize ``self``. @@ -199,8 +202,8 @@ def __init__(self, parent, s): sage: s = OS([[1, 3], [2, 4]]) sage: TestSuite(s).run() """ - self._base_set = reduce(lambda x, y: x.union(y), map(Set, s), Set([])) - ClonableArray.__init__(self, parent, [Set(elt) for elt in s]) + ClonableArray.__init__(self, parent, + [frozenset(part) for part in s], check=check) def _repr_(self): """ @@ -228,7 +231,8 @@ def check(self): sage: s = OS([[1, 3], [2, 4]]) sage: s.check() """ - assert self in self.parent(), "%s not in %s" % (self, self.parent()) + par = parent(self) + assert self in par, "%s not in %s" % (self, par) def _hash_(self): """ @@ -246,24 +250,36 @@ def _hash_(self): def base_set(self): """ - Return the base set of ``self``, which is the union of all parts - of ``self``. + Return the base set of ``self``. + + This is the union of all parts of ``self``. EXAMPLES:: sage: OrderedSetPartition([[1], [2,3], [4]]).base_set() - {1, 2, 3, 4} + frozenset({1, 2, 3, 4}) sage: OrderedSetPartition([[1,2,3,4]]).base_set() - {1, 2, 3, 4} + frozenset({1, 2, 3, 4}) sage: OrderedSetPartition([]).base_set() - {} + frozenset() + + TESTS:: + + sage: S = OrderedSetPartitions() + sage: x = S([['a', 'c', 'e'], ['b', 'd']]) + sage: x.base_set() + frozenset({'a', 'b', 'c', 'd', 'e'}) """ - return Set([e for p in self for e in p]) + try: + return parent(self)._set + except AttributeError: # in OrderedSetPartitions_all + return frozenset(x for part in self for x in part) def base_set_cardinality(self): """ - Return the cardinality of the base set of ``self``, which is the sum - of the sizes of the parts of ``self``. + Return the cardinality of the base set of ``self``. + + This is the sum of the sizes of the parts of ``self``. This is also known as the *size* (sometimes the *weight*) of an ordered set partition. @@ -274,8 +290,17 @@ def base_set_cardinality(self): 4 sage: OrderedSetPartition([[1,2,3,4]]).base_set_cardinality() 4 + + TESTS:: + + sage: S = OrderedSetPartitions() + sage: S([[1,4],[3],[2]]).base_set_cardinality() + 4 """ - return sum(len(x) for x in self) + try: + return len(parent(self)._set) + except AttributeError: # in OrderedSetPartitions_all + return sum(len(part) for part in self) size = base_set_cardinality @@ -327,7 +352,7 @@ def sum(osps): Any iterable can be provided as input:: - sage: Composition.sum([OrderedSetPartition([[2*i,2*i+1]]) for i in [4,1,3]]) + sage: OrderedSetPartition.sum([OrderedSetPartition([[2*i,2*i+1]]) for i in [4,1,3]]) [{8, 9}, {2, 3}, {6, 7}] Empty inputs are handled gracefully:: @@ -342,9 +367,10 @@ def sum(osps): sage: C = OrderedSetPartition.sum([A, B]); C [{2}, {1, 3}, {5}] sage: C.parent() - Ordered set partitions + Ordered set partitions of {1, 2, 3, 5} """ - return OrderedSetPartitions()(sum((list(i) for i in osps), [])) + lset = set(x for osp in osps for x in osp.base_set()) + return OrderedSetPartitions(lset)(sum((list(i) for i in osps), [])) def reversed(self): r""" @@ -403,7 +429,8 @@ def complement(self): m = min(base_set) M = max(base_set) mM = m + M - return OrderedSetPartitions()([[mM - i for i in part] for part in self]) + par = parent(self) + return par([[mM - i for i in part] for part in self]) def finer(self): """ @@ -438,9 +465,8 @@ def finer(self): par = parent(self) if not self: return FiniteEnumeratedSet([self]) - else: - return FiniteEnumeratedSet([par(sum((list(i) for i in C), [])) - for C in cartesian_product([OrderedSetPartitions(X) for X in self])]) + return FiniteEnumeratedSet([par(sum((list(i) for i in C), [])) + for C in cartesian_product([OrderedSetPartitions(X) for X in self])]) def is_finer(self, co2): """ @@ -480,9 +506,9 @@ def is_finer(self, co2): i1 = 0 for j2 in co2: - sum1 = Set([]) + sum1 = set() while len(sum1) < len(j2): - sum1 += co1[i1] + sum1 = sum1.union(co1[i1]) i1 += 1 if not sum1.issubset(j2): return False @@ -536,7 +562,7 @@ def fatten(self, grouping): result = [None] * len(grouping) j = 0 for i in range(len(grouping)): - result[i] = sum(self[j:j+grouping[i]], Set([])) + result[i] = set().union(*self[j:j+grouping[i]]) j += grouping[i] return parent(self)(result) @@ -553,10 +579,10 @@ def fatter(self): sage: C.cardinality() 4 sage: sorted(C) - [[{1, 2, 3, 4, 5}], - [{1, 2, 5}, {3, 4}], + [[{2, 5}, {1}, {3, 4}], [{2, 5}, {1, 3, 4}], - [{2, 5}, {1}, {3, 4}]] + [{1, 2, 5}, {3, 4}], + [{1, 2, 3, 4, 5}]] sage: OrderedSetPartition([[4, 9], [-1, 2]]).fatter().list() [[{4, 9}, {-1, 2}], [{-1, 2, 4, 9}]] @@ -568,14 +594,14 @@ def fatter(self): sage: list(Composition([]).fatter()) [[]] sage: sorted(OrderedSetPartition([[1], [2], [3], [4]]).fatter()) - [[{1, 2, 3, 4}], - [{1, 2, 3}, {4}], - [{1, 2}, {3, 4}], - [{1, 2}, {3}, {4}], - [{1}, {2, 3, 4}], - [{1}, {2, 3}, {4}], + [[{1}, {2}, {3}, {4}], [{1}, {2}, {3, 4}], - [{1}, {2}, {3}, {4}]] + [{1}, {2, 3}, {4}], + [{1}, {2, 3, 4}], + [{1, 2}, {3}, {4}], + [{1, 2}, {3, 4}], + [{1, 2, 3}, {4}], + [{1, 2, 3, 4}]] """ return Compositions(len(self)).map(self.fatten) @@ -614,7 +640,7 @@ def bottom_up_osp(X, comp): sage: buo = OrderedSetPartition.bottom_up_osp sage: parent(buo(Set([1, 4, 7, 9]), [2, 1, 1])) - Ordered set partitions + Ordered set partitions of {1, 4, 9, 7} sage: buo((3, 5, 6), (2, 1)) [{3, 5}, {6}] sage: buo([3, 5, 6], Composition([1, 2])) @@ -624,9 +650,9 @@ def bottom_up_osp(X, comp): result = [None] * len(comp) j = 0 for i in range(len(comp)): - result[i] = Set(xs[j:j+comp[i]]) + result[i] = set(xs[j:j+comp[i]]) j += comp[i] - return OrderedSetPartitions()(result) + return OrderedSetPartitions(X)(result) def strongly_finer(self): """ @@ -657,10 +683,9 @@ def strongly_finer(self): par = parent(self) if not self: return FiniteEnumeratedSet([self]) - else: - buo = OrderedSetPartition.bottom_up_osp - return FiniteEnumeratedSet([par(sum((list(P) for P in C), [])) - for C in cartesian_product([[buo(X, comp) for comp in Compositions(len(X))] for X in self])]) + buo = OrderedSetPartition.bottom_up_osp + return FiniteEnumeratedSet([par(sum((list(P) for P in C), [])) + for C in cartesian_product([[buo(X, comp) for comp in Compositions(len(X))] for X in self])]) def is_strongly_finer(self, co2): r""" @@ -703,12 +728,12 @@ def is_strongly_finer(self, co2): i1 = 0 for j2 in co2: - sum1 = Set([]) + sum1 = set() while len(sum1) < len(j2): next = co1[i1] if sum1 and max(sum1) >= min(next): return False - sum1 += next + sum1 = sum1.union(next) i1 += 1 if not sum1.issubset(j2): return False @@ -728,8 +753,7 @@ def strongly_fatter(self): sage: C.cardinality() 2 sage: sorted(C) - [[{2, 5}, {1, 3, 4}], - [{2, 5}, {1}, {3, 4}]] + [[{2, 5}, {1}, {3, 4}], [{2, 5}, {1, 3, 4}]] sage: OrderedSetPartition([[4, 9], [-1, 2]]).strongly_fatter().list() [[{4, 9}, {-1, 2}]] @@ -741,21 +765,21 @@ def strongly_fatter(self): sage: list(OrderedSetPartition([]).strongly_fatter()) [[]] sage: sorted(OrderedSetPartition([[1], [2], [3], [4]]).strongly_fatter()) - [[{1, 2, 3, 4}], - [{1, 2, 3}, {4}], - [{1, 2}, {3, 4}], - [{1, 2}, {3}, {4}], - [{1}, {2, 3, 4}], - [{1}, {2, 3}, {4}], + [[{1}, {2}, {3}, {4}], [{1}, {2}, {3, 4}], - [{1}, {2}, {3}, {4}]] + [{1}, {2, 3}, {4}], + [{1}, {2, 3, 4}], + [{1, 2}, {3}, {4}], + [{1, 2}, {3, 4}], + [{1, 2, 3}, {4}], + [{1, 2, 3, 4}]] sage: sorted(OrderedSetPartition([[1], [3], [2], [4]]).strongly_fatter()) - [[{1, 3}, {2, 4}], - [{1, 3}, {2}, {4}], + [[{1}, {3}, {2}, {4}], [{1}, {3}, {2, 4}], - [{1}, {3}, {2}, {4}]] + [{1, 3}, {2}, {4}], + [{1, 3}, {2, 4}]] sage: sorted(OrderedSetPartition([[4], [1], [5], [3]]).strongly_fatter()) - [[{4}, {1, 5}, {3}], [{4}, {1}, {5}, {3}]] + [[{4}, {1}, {5}, {3}], [{4}, {1, 5}, {3}]] """ c = [sorted(X) for X in self] l = len(c) - 1 @@ -791,7 +815,7 @@ def to_packed_word(self): .. WARNING:: This assumes there is a total order on the underlying - set (``self._base_set``). + set. EXAMPLES:: @@ -799,16 +823,18 @@ def to_packed_word(self): sage: x = S([[3,5], [2], [1,4,6]]) sage: x.to_packed_word() word: 321313 + sage: x = S([['a', 'c', 'e'], ['b', 'd']]) sage: x.to_packed_word() word: 12121 """ - X = sorted(self._base_set) + X = sorted(self.base_set()) out = {} for i in range(len(self)): for letter in self[i]: out[letter] = i - return Words()([out[letter] + 1 for letter in X]) + W = Words(infinite=False) + return W([out[letter] + 1 for letter in X]) def number_of_inversions(self): r""" @@ -841,6 +867,7 @@ def number_of_inversions(self): num_invs += sum(1 for j in self[ell] if i < j) return ZZ(num_invs) + class OrderedSetPartitions(UniqueRepresentation, Parent): """ Return the combinatorial class of ordered set partitions of ``s``. @@ -898,6 +925,13 @@ class OrderedSetPartitions(UniqueRepresentation, Parent): [{'t'}, {'a', 'c'}], [{'t'}, {'a'}, {'c'}], [{'t'}, {'c'}, {'a'}]] + + TESTS:: + + sage: S = OrderedSetPartitions() + sage: x = S([[3,5], [2], [1,4,6]]) + sage: x.parent() + Ordered set partitions """ @staticmethod def __classcall_private__(cls, s=None, c=None): @@ -918,7 +952,7 @@ def __classcall_private__(cls, s=None, c=None): if isinstance(s, (int, Integer)): if s < 0: raise ValueError("s must be non-negative") - s = frozenset(range(1, s+1)) + s = frozenset(range(1, s + 1)) else: s = frozenset(s) @@ -950,12 +984,14 @@ def _element_constructor_(self, s): EXAMPLES:: sage: OS = OrderedSetPartitions(4) - sage: OS([[1,3],[2,4]]) + sage: x = OS([[1,3],[2,4]]); x [{1, 3}, {2, 4}] + sage: x.parent() + Ordered set partitions of {1, 2, 3, 4} """ if isinstance(s, OrderedSetPartition): raise ValueError("cannot convert %s into an element of %s" % (s, self)) - return self.element_class(self, list(s)) + return self.element_class(self, list(s)) # HERE the parent "self" is not good Element = OrderedSetPartition @@ -971,11 +1007,9 @@ def __contains__(self, x): sage: [Set([1,2]), Set([3,4])] in OS True sage: [set([1,2]), set([3,4])] in OS - Traceback (most recent call last): - ... - TypeError: X (=...1, 2...) must be a Set + True """ - #x must be a list + # x must be a list if not isinstance(x, (OrderedSetPartition, list, tuple)): return False @@ -986,7 +1020,7 @@ def __contains__(self, x): # Check to make sure each element of the list # is a nonempty set - u = Set([]) + u = set() for s in x: if not s or not isinstance(s, (set, frozenset, Set_generic)): return False @@ -994,12 +1028,9 @@ def __contains__(self, x): # Make sure that the union of all the # sets is the original set - if u != Set(self._set): - return False + return len(u) == len(self._set) - return True - - def from_finite_word(self, w): + def from_finite_word(self, w, check=True): r""" Return the unique ordered set partition of `\{1, 2, \ldots, n\}` corresponding to a word `w` of length `n`. @@ -1015,13 +1046,31 @@ def from_finite_word(self, w): sage: B = OrderedSetPartitions().from_finite_word([1,2,3,1,2,3,1,2,4]) sage: A == B True + + TESTS:: + + sage: A = OrderedSetPartitions().from_finite_word('abcabca') + sage: A.parent() + Ordered set partitions + + sage: A = OrderedSetPartitions(7).from_finite_word('abcabca') + sage: A.parent() + Ordered set partitions of {1, 2, 3, 4, 5, 6, 7} """ # TODO: fix this if statement. # In fact, what we need is for the underlying alphabet to be sortable. if isinstance(w, (list, tuple, str, FiniteWord_class)): - return self.element_class(self, Words()(w).to_ordered_set_partition()) - else: - raise ValueError("Something is wrong: `from_finite_word` expects an object of type list/tuple/str/Word representing a finite word, received {}.".format(str(w))) + W = Words(infinite=False) + if check: + try: + X = self._set + if len(X) != len(w) or X != frozenset(range(1, len(w) + 1)): + raise ValueError(f"result not in {self}") + except AttributeError: + pass + return self.element_class(self, W(w).to_ordered_set_partition()) + raise TypeError(f"`from_finite_word` expects an object of type list/tuple/str/Word " + f"representing a finite word, received {w}") class OrderedSetPartitions_s(OrderedSetPartitions): @@ -1056,14 +1105,15 @@ def cardinality(self): sage: OrderedSetPartitions(5).cardinality() 541 """ - return sum([factorial(k)*stirling_number2(len(self._set), k) - for k in range(len(self._set)+1)]) + N = len(self._set) + return sum(factorial(k) * stirling_number2(N, k) + for k in range(N + 1)) def __iter__(self): """ EXAMPLES:: - sage: [ p for p in OrderedSetPartitions([1,2,3]) ] + sage: list(OrderedSetPartitions([1,2,3])) [[{1}, {2}, {3}], [{1}, {3}, {2}], [{2}, {1}, {3}], @@ -1080,7 +1130,7 @@ def __iter__(self): """ for x in Compositions(len(self._set)): for z in OrderedSetPartitions(self._set, x): - yield self.element_class(self, z) + yield self.element_class(self, z, check=False) class OrderedSetPartitions_sn(OrderedSetPartitions): @@ -1158,7 +1208,7 @@ def __iter__(self): """ for x in Compositions(len(self._set), length=self.n): for z in OrderedSetPartitions_scomp(self._set, x): - yield self.element_class(self, z) + yield self.element_class(self, z, check=False) class OrderedSetPartitions_scomp(OrderedSetPartitions): @@ -1262,21 +1312,98 @@ def __iter__(self): {13}, {14}, {15}, {16}, {17}, {18}, {19}, {20}, {21}, {22}, {23}, {24}, {25}, {26}, {27}, {28}, {29}, {30}, {31}, {32}, {33}, {34}, {35}, {36}, {37}, {38}, {39}, {40}, {41}, {42}] + + EXAMPLES:: + + sage: list(OrderedSetPartitions(range(5), [2,1,2])) + [[{0, 1}, {2}, {3, 4}], + [{0, 1}, {3}, {2, 4}], + ... + [{2, 4}, {3}, {0, 1}], + [{3, 4}, {2}, {0, 1}]] """ - comp = self.c - lset = [x for x in self._set] - l = len(self.c) - dcomp = [-1] + comp.descents(final_descent=True) + part_sizes = self.c + N = len(part_sizes) + if not N: + yield self.element_class(self, [], check=False) + return + + l = [] + lset = list(self._set) + for i, j in enumerate(part_sizes): + l.extend([i] * j) + + pi = multiset_permutation_to_ordered_set_partition(l, N) + converted = [frozenset(lset[i] for i in part) for part in pi] + yield self.element_class(self, converted, check=False) + + while multiset_permutation_next_lex(l): + pi = multiset_permutation_to_ordered_set_partition(l, N) + converted = [frozenset(lset[i] for i in part) for part in pi] + yield self.element_class(self, converted, check=False) + + +def multiset_permutation_to_ordered_set_partition(l, m): + r""" + Convert a multiset permutation to an ordered set partition. + + INPUT: + + - ``l`` -- a multiset permutation + - ``m`` -- number of parts + + EXAMPLES:: + + sage: from sage.combinat.set_partition_ordered import multiset_permutation_to_ordered_set_partition + sage: l = [0, 0, 1, 1, 2] + sage: multiset_permutation_to_ordered_set_partition(l, 3) + [[0, 1], [2, 3], [4]] + """ + p = [[] for _ in range(m)] + for i, j in enumerate(l): + p[j].append(i) + return p - p = [] - for j in range(l): - p += [j + 1] * comp[j] - for x in permutation.Permutations_mset(p): - res = permutation.to_standard(x).inverse() - res = [lset[x - 1] for x in res] - yield self.element_class(self, [Set(res[dcomp[i]+1:dcomp[i+1]+1]) - for i in range(l)]) +def multiset_permutation_next_lex(l): + r""" + Return the next multiset permutation after ``l``. + + EXAMPLES:: + + sage: from sage.combinat.set_partition_ordered import multiset_permutation_next_lex + sage: l = [0, 0, 1, 1, 2] + sage: while multiset_permutation_next_lex(l): + ....: print(l) + [0, 0, 1, 2, 1] + [0, 0, 2, 1, 1] + [0, 1, 0, 1, 2] + [0, 1, 0, 2, 1] + [0, 1, 1, 0, 2] + [0, 1, 1, 2, 0] + ... + [1, 1, 2, 0, 0] + [1, 2, 0, 0, 1] + [1, 2, 0, 1, 0] + [1, 2, 1, 0, 0] + [2, 0, 0, 1, 1] + [2, 0, 1, 0, 1] + [2, 0, 1, 1, 0] + [2, 1, 0, 0, 1] + [2, 1, 0, 1, 0] + [2, 1, 1, 0, 0] + """ + i = len(l) - 2 + while i >= 0 and l[i] >= l[i + 1]: + i -= 1 + if i == -1: + return 0 + j = len(l) - 1 + while l[j] <= l[i]: + j -= 1 + l[i], l[j] = l[j], l[i] + l[i + 1:] = l[:i:-1] + return 1 class OrderedSetPartitions_all(OrderedSetPartitions): @@ -1325,7 +1452,7 @@ def __iter__(self): n = 0 while True: for X in OrderedSetPartitions(n): - yield self.element_class(self, list(X)) + yield self.element_class(self, list(X), check=False) n += 1 def _element_constructor_(self, s): @@ -1368,7 +1495,7 @@ def __contains__(self, x): if x.parent() is self: return True gset = x.parent()._set - return gset == frozenset(range(1, len(gset)+1)) + return gset == frozenset(range(1, len(gset) + 1)) # x must be a list or a tuple if not isinstance(x, (list, tuple)): @@ -1380,8 +1507,8 @@ def __contains__(self, x): if not all(isinstance(s, (set, frozenset, Set_generic)) or len(s) == len(set(s)) for s in x): return False - X = set(reduce(lambda A,B: A.union(B), x, set())) - return len(X) == sum(len(s) for s in x) and X == set(range(1,len(X)+1)) + X = set(y for p in x for y in p) + return len(X) == sum(len(s) for s in x) and X == frozenset(range(1, len(X) + 1)) def _coerce_map_from_(self, X): """ @@ -1448,8 +1575,7 @@ def __setstate__(self, state): self.__class__ = OrderedSetPartitions_scomp n = state['_n'] k = state['_k'] - OrderedSetPartitions_scomp.__init__(self, range(state['_n']), (k, n-k)) + OrderedSetPartitions_scomp.__init__(self, range(state['_n']), (k, n - k)) -from sage.misc.persist import register_unpickle_override register_unpickle_override("sage.combinat.split_nk", "SplitNK_nk", SplitNK) diff --git a/src/sage/combinat/sf/classical.py b/src/sage/combinat/sf/classical.py index ea77ed7c8a3..0477629f3d1 100644 --- a/src/sage/combinat/sf/classical.py +++ b/src/sage/combinat/sf/classical.py @@ -119,6 +119,24 @@ def _element_constructor_(self, x): Traceback (most recent call last): ... TypeError: do not know how to make x (= [[2, 1], [1]]) an element of self + + Check that :trac:`34576` is fixed:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: f = s(0/2); f + 0 + sage: f == 0 + True + sage: f._monomial_coefficients + {} + + sage: s2 = SymmetricFunctions(GF(2)).s() + sage: f = s2(2*s[2,1]); f + 0 + sage: f == 0 + True + sage: f._monomial_coefficients + {} """ R = self.base_ring() @@ -126,7 +144,6 @@ def _element_constructor_(self, x): if isinstance(x, int): x = Integer(x) - ############## # Partitions # ############## @@ -140,9 +157,9 @@ def _element_constructor_(self, x): # Dual bases # ############## elif sfa.is_SymmetricFunction(x) and hasattr(x, 'dual'): - #Check to see if it is the dual of some other basis - #If it is, try to coerce its corresponding element - #in the other basis + # Check to see if it is the dual of some other basis + # If it is, try to coerce its corresponding element + # in the other basis return self(x.dual()) ################################################################## @@ -161,105 +178,97 @@ def _element_constructor_(self, x): elif isinstance(x, self.Element): P = x.parent() - #same base ring + # same base ring if P is self: return x - #different base ring + # different base ring else: - return eclass(self, dict([ (e1,R(e2)) for e1,e2 in x._monomial_coefficients.items()])) + return eclass(self, {la: rc for la, c in x._monomial_coefficients.items() + if (rc := R(c))}) ################################################## # Classical Symmetric Functions, different basis # ################################################## elif isinstance(x, SymmetricFunctionAlgebra_classical.Element): + P = x.parent() + m = x.monomial_coefficients() - R = self.base_ring() - xP = x.parent() - xm = x.monomial_coefficients() - - #determine the conversion function. + # determine the conversion function. try: - t = conversion_functions[(xP.basis_name(),self.basis_name())] + t = conversion_functions[(P.basis_name(), self.basis_name())] except AttributeError: - raise TypeError("do not know how to convert from %s to %s"%(xP.basis_name(), self.basis_name())) - - if R == QQ and xP.base_ring() == QQ: - if xm: - return self._from_dict(t(xm)._monomial_coefficients, coerce=True) - else: - return self.zero() + raise TypeError("do not know how to convert from %s to %s" + % (P.basis_name(), self.basis_name())) + + if R == QQ and P.base_ring() == QQ: + if m: + return self._from_dict(t(m)._monomial_coefficients, + coerce=True) + return self.zero() else: - f = lambda part: self._from_dict(t( {part: ZZ.one()} )._monomial_coefficients) + f = lambda part: self._from_dict(t({part: ZZ.one()})._monomial_coefficients) return self._apply_module_endomorphism(x, f) - ############################### # Hall-Littlewood Polynomials # ############################### elif isinstance(x, hall_littlewood.HallLittlewood_generic.Element): # - #Qp: Convert to Schur basis and then convert to self - # - if isinstance(x, hall_littlewood.HallLittlewood_qp.Element): - Qp = x.parent() - sx = Qp._s._from_cache(x, Qp._s_cache, Qp._self_to_s_cache, t=Qp.t) - return self(sx) - # - #P: Convert to Schur basis and then convert to self + # Qp: Convert to Schur basis and then convert to self # - elif isinstance(x, hall_littlewood.HallLittlewood_p.Element): + if isinstance(x, (hall_littlewood.HallLittlewood_qp.Element, + hall_littlewood.HallLittlewood_p.Element)): P = x.parent() sx = P._s._from_cache(x, P._s_cache, P._self_to_s_cache, t=P.t) return self(sx) # - #Q: Convert to P basis and then convert to self + # Q: Convert to P basis and then convert to self # elif isinstance(x, hall_littlewood.HallLittlewood_q.Element): - return self( x.parent()._P( x ) ) + return self(x.parent()._P(x)) ####### # LLT # ####### - #Convert to m and then to self. + # Convert to m and then to self. elif isinstance(x, llt.LLT_generic.Element): P = x.parent() - BR = self.base_ring() - zero = BR.zero() - PBR = P.base_ring() - if not BR.has_coerce_map_from(PBR): - raise TypeError("no coerce map from x's parent's base ring (= %s) to self's base ring (= %s)"%(PBR, self.base_ring())) + Rx = P.base_ring() + zero = R.zero() + if not R.has_coerce_map_from(Rx): + raise TypeError("no coerce map from x's parent's base ring (= %s) to self's base ring (= %s)" + % (Rx, R)) z_elt = {} for m, c in x._monomial_coefficients.items(): n = sum(m) P._m_cache(n) for part in P._self_to_m_cache[n][m]: - z_elt[part] = z_elt.get(part, zero) + BR(c*P._self_to_m_cache[n][m][part].subs(t=P.t)) + z_elt[part] = z_elt.get(part, zero) + R(c*P._self_to_m_cache[n][m][part].subs(t=P.t)) m = P._sym.monomial() - return self( m._from_dict(z_elt) ) + return self(m._from_dict(z_elt)) ######################### # Macdonald Polynomials # ######################### elif isinstance(x, macdonald.MacdonaldPolynomials_generic.Element): - if isinstance(x, macdonald.MacdonaldPolynomials_j.Element): - J = x.parent() - sx = J._s._from_cache(x, J._s_cache, J._self_to_s_cache, q=J.q, t=J.t) + if isinstance(x, (macdonald.MacdonaldPolynomials_j.Element, + macdonald.MacdonaldPolynomials_s.Element)): + P = x.parent() + sx = P._s._from_cache(x, P._s_cache, P._self_to_s_cache, q=P.q, t=P.t) return self(sx) - elif isinstance(x, (macdonald.MacdonaldPolynomials_q.Element, macdonald.MacdonaldPolynomials_p.Element)): + elif isinstance(x, (macdonald.MacdonaldPolynomials_q.Element, + macdonald.MacdonaldPolynomials_p.Element)): J = x.parent()._J jx = J(x) sx = J._s._from_cache(jx, J._s_cache, J._self_to_s_cache, q=J.q, t=J.t) return self(sx) - elif isinstance(x, (macdonald.MacdonaldPolynomials_h.Element,macdonald.MacdonaldPolynomials_ht.Element)): - H = x.parent() - sx = H._self_to_s(x) - return self(sx) - elif isinstance(x, macdonald.MacdonaldPolynomials_s.Element): - S = x.parent() - sx = S._s._from_cache(x, S._s_cache, S._self_to_s_cache, q=S.q, t=S.t) + elif isinstance(x, (macdonald.MacdonaldPolynomials_h.Element, + macdonald.MacdonaldPolynomials_ht.Element)): + P = x.parent() + sx = P._self_to_s(x) return self(sx) else: raise TypeError @@ -272,8 +281,9 @@ def _element_constructor_(self, x): P = x.parent() mx = P._m._from_cache(x, P._m_cache, P._self_to_m_cache, t=P.t) return self(mx) - if isinstance(x, (jack.JackPolynomials_j.Element, jack.JackPolynomials_q.Element)): - return self( x.parent()._P(x) ) + if isinstance(x, (jack.JackPolynomials_j.Element, + jack.JackPolynomials_q.Element)): + return self(x.parent()._P(x)) else: raise TypeError @@ -281,21 +291,25 @@ def _element_constructor_(self, x): # Bases defined by orthogonality and triangularity # #################################################### elif isinstance(x, orthotriang.SymmetricFunctionAlgebra_orthotriang.Element): - #Convert to its base and then to self - xp = x.parent() - if self is xp._sf_base: - return xp._sf_base._from_cache(x, xp._base_cache, xp._self_to_base_cache) + # Convert to its base and then to self + P = x.parent() + if self is P._sf_base: + return P._sf_base._from_cache(x, P._base_cache, P._self_to_base_cache) else: - return self( xp._sf_base(x) ) + return self( P._sf_base(x) ) ################################# # Last shot -- try calling R(x) # ################################# else: try: - return eclass(self, {_Partitions([]): R(x)}) + c = R(x) except Exception: raise TypeError("do not know how to make x (= {}) an element of self".format(x)) + else: + if not c: + return self.zero() + return eclass(self, {_Partitions([]): c}) # This subclass is currently needed for the test above: # isinstance(x, SymmetricFunctionAlgebra_classical.Element): diff --git a/src/sage/combinat/sf/powersum.py b/src/sage/combinat/sf/powersum.py index f7542d7929e..f7019407840 100644 --- a/src/sage/combinat/sf/powersum.py +++ b/src/sage/combinat/sf/powersum.py @@ -476,8 +476,8 @@ def frobenius(self, n): :meth:`~sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic_Element.plethysm` """ - dct = {Partition([n * i for i in lam]): coeff - for (lam, coeff) in self.monomial_coefficients().items()} + dct = {lam.stretch(n): coeff + for lam, coeff in self.monomial_coefficients().items()} return self.parent()._from_dict(dct) adams_operation = frobenius diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index f18f6fb75a2..a686dfef513 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -1605,6 +1605,8 @@ def __init__(self, t, domain, codomain): def __call__(self, partition): """ + EXAMPLES:: + sage: Sym = SymmetricFunctions(QQ['x']) sage: p = Sym.p(); s = Sym.s() sage: p[1] + s[1] # indirect doctest diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 7eac828fa4b..f0fc9bf5860 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -1722,6 +1722,24 @@ def degree_zero_coefficient(self): """ return self.coefficient([]) + def is_unit(self): + """ + Return whether this element is a unit in the ring. + + EXAMPLES:: + + sage: m = SymmetricFunctions(ZZ).monomial() + sage: (2*m[2,1] + m[[]]).is_unit() + False + + sage: m = SymmetricFunctions(QQ).monomial() + sage: (3/2*m([])).is_unit() + True + """ + m = self.monomial_coefficients(copy=False) + return len(m) <= 1 and self.coefficient([]).is_unit() + + #SymmetricFunctionsBases.Filtered = FilteredSymmetricFunctionsBases #SymmetricFunctionsBases.Graded = GradedSymmetricFunctionsBases @@ -3072,6 +3090,31 @@ def plethysm(self, x, include=None, exclude=None): sage: sum(s[mu](X)*s[mu.conjugate()](Y) for mu in P5) == sum(m[mu](X)*e[mu](Y) for mu in P5) True + Sage can also do the plethysm with an element in the completion:: + + sage: L = LazySymmetricFunctions(s) + sage: f = s[2,1] + sage: g = L(s[1]) / (1 - L(s[1])); g + s[1] + (s[1,1]+s[2]) + (s[1,1,1]+2*s[2,1]+s[3]) + + (s[1,1,1,1]+3*s[2,1,1]+2*s[2,2]+3*s[3,1]+s[4]) + + (s[1,1,1,1,1]+4*s[2,1,1,1]+5*s[2,2,1]+6*s[3,1,1]+5*s[3,2]+4*s[4,1]+s[5]) + + ... + O^8 + sage: fog = f(g) + sage: fog[:8] + [s[2, 1], + s[1, 1, 1, 1] + 3*s[2, 1, 1] + 2*s[2, 2] + 3*s[3, 1] + s[4], + 2*s[1, 1, 1, 1, 1] + 8*s[2, 1, 1, 1] + 10*s[2, 2, 1] + + 12*s[3, 1, 1] + 10*s[3, 2] + 8*s[4, 1] + 2*s[5], + 3*s[1, 1, 1, 1, 1, 1] + 17*s[2, 1, 1, 1, 1] + 30*s[2, 2, 1, 1] + + 16*s[2, 2, 2] + 33*s[3, 1, 1, 1] + 54*s[3, 2, 1] + 16*s[3, 3] + + 33*s[4, 1, 1] + 30*s[4, 2] + 17*s[5, 1] + 3*s[6], + 5*s[1, 1, 1, 1, 1, 1, 1] + 30*s[2, 1, 1, 1, 1, 1] + 70*s[2, 2, 1, 1, 1] + + 70*s[2, 2, 2, 1] + 75*s[3, 1, 1, 1, 1] + 175*s[3, 2, 1, 1] + + 105*s[3, 2, 2] + 105*s[3, 3, 1] + 100*s[4, 1, 1, 1] + 175*s[4, 2, 1] + + 70*s[4, 3] + 75*s[5, 1, 1] + 70*s[5, 2] + 30*s[6, 1] + 5*s[7]] + sage: parent(fog) + Lazy completion of Symmetric Functions over Rational Field in the Schur basis + .. SEEALSO:: :meth:`frobenius` @@ -3080,66 +3123,100 @@ def plethysm(self, x, include=None, exclude=None): sage: (1+p[2]).plethysm(p[2]) p[] + p[4] + + Check that degree one elements are treated in the correct way:: + + sage: R. = QQ[] + sage: p = SymmetricFunctions(R).p() + sage: f = a1*p[1] + a2*p[2] + a11*p[1,1] + sage: g = b1*p[1] + b21*p[2,1] + b111*p[1,1,1] + sage: r = f(g); r + a1*b1*p[1] + a11*b1^2*p[1, 1] + a1*b111*p[1, 1, 1] + + 2*a11*b1*b111*p[1, 1, 1, 1] + a11*b111^2*p[1, 1, 1, 1, 1, 1] + + a2*b1^2*p[2] + a1*b21*p[2, 1] + 2*a11*b1*b21*p[2, 1, 1] + + 2*a11*b21*b111*p[2, 1, 1, 1, 1] + a11*b21^2*p[2, 2, 1, 1] + + a2*b111^2*p[2, 2, 2] + a2*b21^2*p[4, 2] + sage: r - f(g, include=[]) + (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] + + Check that we can compute the plethysm with a constant:: + + sage: p[2,2,1](2) + 8*p[] + + sage: p[2,2,1](int(2)) + 8*p[] + + sage: p[2,2,1](a1) + a1^5*p[] + + sage: X = algebras.Shuffle(QQ, 'ab') + sage: Y = algebras.Shuffle(QQ, 'bc') + sage: T = tensor([X,Y]) + sage: s = SymmetricFunctions(T).s() + sage: s(2*T.one()) + (2*B[]#B[])*s[] + + .. TODO:: + + The implementation of plethysm in + :class:`sage.data_structures.stream.Stream_plethysm` seems + to be faster. This should be investigated. """ parent = self.parent() - R = parent.base_ring() - tHA = HopfAlgebrasWithBasis(R).TensorProducts() - tensorflag = tHA in x.parent().categories() - if not (is_SymmetricFunction(x) or tensorflag): - raise TypeError("only know how to compute plethysms " - "between symmetric functions or tensors " - "of symmetric functions") - p = parent.realization_of().power() - if self == parent.zero(): + if not self: return self - # Handle degree one elements - if include is not None and exclude is not None: - raise RuntimeError("include and exclude cannot both be specified") - - try: - degree_one = [R(g) for g in R.variable_names_recursive()] - except AttributeError: - try: - degree_one = R.gens() - except NotImplementedError: - degree_one = [] - - if include: - degree_one = [R(g) for g in include] - if exclude: - degree_one = [g for g in degree_one if g not in exclude] + R = parent.base_ring() + tHA = HopfAlgebrasWithBasis(R).TensorProducts() + from sage.structure.element import parent as get_parent + Px = get_parent(x) + tensorflag = Px in tHA + if not is_SymmetricFunction(x): + if Px is R: # Handle stuff that is directly in the base ring + x = parent(x) + elif (not tensorflag or any(not isinstance(factor, SymmetricFunctionAlgebra_generic) + for factor in Px._sets)): + from sage.rings.lazy_series import LazySymmetricFunction + if isinstance(x, LazySymmetricFunction): + from sage.rings.lazy_series_ring import LazySymmetricFunctions + L = LazySymmetricFunctions(parent) + return L(self)(x) + + # Try to coerce into a symmetric function + phi = parent.coerce_map_from(Px) + if phi is not None: + x = phi(x) + elif not tensorflag: + raise TypeError("only know how to compute plethysms " + "between symmetric functions or tensors " + "of symmetric functions") - degree_one = [g for g in degree_one if g != R.one()] + p = parent.realization_of().power() - def raise_c(n): - return lambda c: c.subs(**{str(g): g ** n for g in degree_one}) + degree_one = _variables_recursive(R, include=include, exclude=exclude) if tensorflag: - tparents = x.parent()._sets - return tensor([parent]*len(tparents))(sum(d*prod(sum(raise_c(r)(c) - * tensor([p[r].plethysm(base(la)) - for (base,la) in zip(tparents,trm)]) - for (trm,c) in x) - for r in mu) - for (mu, d) in p(self))) - - # Takes in n, and returns a function which takes in a partition and - # scales all of the parts of that partition by n - def scale_part(n): - return lambda m: m.__class__(m.parent(), [i * n for i in m]) - - # Takes n an symmetric function f, and an n and returns the + tparents = Px._sets + s = sum(d * prod(sum(_raise_variables(c, r, degree_one) + * tensor([p[r].plethysm(base(la)) + for base, la in zip(tparents, trm)]) + for trm, c in x) + for r in mu) + for mu, d in p(self)) + return tensor([parent]*len(tparents))(s) + + # Takes a symmetric function f, and an n and returns the # symmetric function with all of its basis partitions scaled # by n def pn_pleth(f, n): - return f.map_support(scale_part(n)) + return f.map_support(lambda mu: mu.stretch(n)) # Takes in a partition and applies p_x = p(x) def f(part): - return p.prod(pn_pleth(p_x.map_coefficients(raise_c(i)), i) + return p.prod(pn_pleth(p_x.map_coefficients(lambda c: _raise_variables(c, i, degree_one)), i) for i in part) return parent(p._apply_module_morphism(p(self), f, codomain=p)) @@ -4917,9 +4994,7 @@ def frobenius(self, n): # then convert back. parent = self.parent() m = parent.realization_of().monomial() - from sage.combinat.partition import Partition - dct = {Partition([n * i for i in lam]): coeff - for (lam, coeff) in m(self)} + dct = {lam.stretch(n): coeff for lam, coeff in m(self)} result_in_m_basis = m._from_dict(dct) return parent(result_in_m_basis) @@ -6125,3 +6200,82 @@ def _nonnegative_coefficients(x): return all(c >= 0 for c in x.coefficients(sparse=False)) else: return x >= 0 + +def _variables_recursive(R, include=None, exclude=None): + """ + Return all variables appearing in the ring ``R``. + + INPUT: + + - ``R`` -- a :class:`Ring` + - ``include``, ``exclude`` (optional, default ``None``) -- + iterables of variables in ``R`` + + OUTPUT: + + - If ``include`` is specified, only these variables are returned + as elements of ``R``. Otherwise, all variables in ``R`` + (recursively) with the exception of those in ``exclude`` are + returned. + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import _variables_recursive + sage: R. = QQ[] + sage: S. = R[] + sage: _variables_recursive(S) + [a, b, t] + + sage: _variables_recursive(S, exclude=[b]) + [a, t] + + sage: _variables_recursive(S, include=[b]) + [b] + + TESTS:: + + sage: _variables_recursive(R.fraction_field(), exclude=[b]) + [a] + + sage: _variables_recursive(S.fraction_field(), exclude=[b]) # known bug + [a, t] + """ + if include is not None and exclude is not None: + raise RuntimeError("include and exclude cannot both be specified") + + if include is not None: + degree_one = [R(g) for g in include] + else: + try: + degree_one = [R(g) for g in R.variable_names_recursive()] + except AttributeError: + try: + degree_one = R.gens() + except NotImplementedError: + degree_one = [] + if exclude is not None: + degree_one = [g for g in degree_one if g not in exclude] + + return [g for g in degree_one if g != R.one()] + +def _raise_variables(c, n, variables): + """ + Replace the given variables in the ring element ``c`` with their + ``n``-th power. + + INPUT: + + - ``c`` -- an element of a ring + - ``n`` -- the power to raise the given variables to + - ``variables`` -- the variables to raise + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import _raise_variables + sage: R. = QQ[] + sage: S. = R[] + sage: _raise_variables(2*a + 3*b*t, 2, [a, t]) + 3*b*t^2 + 2*a^2 + + """ + return c.subs(**{str(g): g ** n for g in variables}) diff --git a/src/sage/combinat/similarity_class_type.py b/src/sage/combinat/similarity_class_type.py index 88515bb3cfe..e7c3f972ac3 100644 --- a/src/sage/combinat/similarity_class_type.py +++ b/src/sage/combinat/similarity_class_type.py @@ -156,7 +156,7 @@ class type, it is also possible to compute the number of classes of that type .. [PSS13] Prasad, A., Singla, P., and Spallone, S., *Similarity of matrices over local rings of length two*. :arxiv:`1212.6157` -.. [PR22] Prasad, A., Ram, S., *Splitting subspaces and a finite field +.. [PR22] Prasad, A., Ram, S., *Splitting subspaces and a finite field interpretation of the Touchard-Riordan formula*. :arxiv:`2205.11076` .. [R17] Ramaré, O., *Rationality of the zeta function of the subgroups of @@ -170,7 +170,7 @@ class type, it is also possible to compute the number of classes of that type - Amritanshu Prasad (2013-09-09): added functions for similarity classes over rings of length two -- Amritanshu Prasad (2022-07-31): added computation of similarity class type of +- Amritanshu Prasad (2022-07-31): added computation of similarity class type of a given matrix and invariant subspace generating function """ # **************************************************************************** @@ -387,7 +387,7 @@ def invariant_subspace_generating_function(la, q=None, t=None): u = invariant_subspace_generating_function(la[1:], q=q, t=t) return R((t**(la[0]+1) * q**(sum(la[1:])) * u.substitute(t=t/q) - u.substitute(t=t*q)) / (t - 1)) - + class PrimarySimilarityClassType(Element, metaclass=InheritComparisonClasscallMetaclass): r""" @@ -1068,7 +1068,7 @@ def invariant_subspace_generating_function(self, q=None, t=None): .. MATH:: \sum_{j\geq 0} a_j(q) t^j, - + where `a_j(q)` denotes the number of `j`-dimensional invariant subspaces of dimensiona `j` for any matrix with the similarity class type ``self`` with entries in a field of order `q`. diff --git a/src/sage/combinat/species/all.py b/src/sage/combinat/species/all.py index 65e18ade5d2..6bda0eab5db 100644 --- a/src/sage/combinat/species/all.py +++ b/src/sage/combinat/species/all.py @@ -11,14 +11,6 @@ - :ref:`section-examples-catalan` - :ref:`section-generic-species` -Lazy Power Series ------------------ - -- :ref:`sage.combinat.species.stream` -- :ref:`sage.combinat.species.series_order` -- :ref:`sage.combinat.species.series` -- :ref:`sage.combinat.species.generating_series` - Basic Species ------------- @@ -52,6 +44,7 @@ from sage.misc.namespace_package import install_doc install_doc(__package__, __doc__) -from .series import LazyPowerSeriesRing -from .recursive_species import CombinatorialSpecies -from . import library as species +from sage.misc.lazy_import import lazy_import +lazy_import("sage.combinat.species.recursive_species", "CombinatorialSpecies") +lazy_import("sage.combinat.species", "library", as_="species") +del lazy_import diff --git a/src/sage/combinat/species/characteristic_species.py b/src/sage/combinat/species/characteristic_species.py index dbb1d5c262a..2bd5a50ff00 100644 --- a/src/sage/combinat/species/characteristic_species.py +++ b/src/sage/combinat/species/characteristic_species.py @@ -109,15 +109,15 @@ def __init__(self, n, min=None, max=None, weight=None): [1] sage: X.structures([1,2]).list() [] - sage: X.generating_series().coefficients(4) + sage: X.generating_series()[0:4] [0, 1, 0, 0] - sage: X.isotype_generating_series().coefficients(4) + sage: X.isotype_generating_series()[0:4] [0, 1, 0, 0] - sage: X.cycle_index_series().coefficients(4) + sage: X.cycle_index_series()[0:4] [0, p[1], 0, 0] sage: F = species.CharacteristicSpecies(3) - sage: c = F.generating_series().coefficients(4) + sage: c = F.generating_series()[0:4] sage: F._check() True sage: F == loads(dumps(F)) @@ -163,7 +163,7 @@ def _gs_term(self, base_ring): EXAMPLES:: sage: F = species.CharacteristicSpecies(2) - sage: F.generating_series().coefficients(5) + sage: F.generating_series()[0:5] [0, 0, 1/2, 0, 0] sage: F.generating_series().count(2) 1 @@ -187,7 +187,7 @@ def _itgs_term(self, base_ring): EXAMPLES:: sage: F = species.CharacteristicSpecies(2) - sage: F.isotype_generating_series().coefficients(5) + sage: F.isotype_generating_series()[0:5] [0, 0, 1, 0, 0] Here we test out weighting each structure by q. @@ -196,7 +196,7 @@ def _itgs_term(self, base_ring): sage: R. = ZZ[] sage: Fq = species.CharacteristicSpecies(2, weight=q) - sage: Fq.isotype_generating_series().coefficients(5) + sage: Fq.isotype_generating_series()[0:5] [0, 0, q, 0, 0] """ return base_ring(self._weight) @@ -207,7 +207,7 @@ def _cis_term(self, base_ring): sage: F = species.CharacteristicSpecies(2) sage: g = F.cycle_index_series() - sage: g.coefficients(5) + sage: g[0:5] [0, 0, 1/2*p[1, 1] + 1/2*p[2], 0, 0] """ cis = SetSpecies(weight=self._weight).cycle_index_series(base_ring) @@ -248,11 +248,11 @@ def __init__(self, min=None, max=None, weight=None): [{}] sage: X.structures([1,2]).list() [] - sage: X.generating_series().coefficients(4) + sage: X.generating_series()[0:4] [1, 0, 0, 0] - sage: X.isotype_generating_series().coefficients(4) + sage: X.isotype_generating_series()[0:4] [1, 0, 0, 0] - sage: X.cycle_index_series().coefficients(4) + sage: X.cycle_index_series()[0:4] [p[], 0, 0, 0] TESTS:: @@ -290,11 +290,11 @@ def __init__(self, min=None, max=None, weight=None): [1] sage: X.structures([1,2]).list() [] - sage: X.generating_series().coefficients(4) + sage: X.generating_series()[0:4] [0, 1, 0, 0] - sage: X.isotype_generating_series().coefficients(4) + sage: X.isotype_generating_series()[0:4] [0, 1, 0, 0] - sage: X.cycle_index_series().coefficients(4) + sage: X.cycle_index_series()[0:4] [0, p[1], 0, 0] TESTS:: diff --git a/src/sage/combinat/species/composition_species.py b/src/sage/combinat/species/composition_species.py index efc77ce508b..9e80e25c00f 100644 --- a/src/sage/combinat/species/composition_species.py +++ b/src/sage/combinat/species/composition_species.py @@ -62,7 +62,7 @@ def transport(self, perm): f, gs = self._list pi = self._partition.transport(perm) f = f.change_labels(pi._list) - g = [g.change_labels(part) for g, part in zip(gs, pi)] # BUG HERE ? + _ = [g.change_labels(part) for g, part in zip(gs, pi)] # TODO: BUG HERE ? return self.__class__(self, self._labels, pi, f, gs) def change_labels(self, labels): @@ -105,7 +105,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: E = species.SetSpecies() sage: C = species.CycleSpecies() sage: S = E(C) - sage: S.generating_series().coefficients(5) + sage: S.generating_series()[:5] [1, 1, 1, 1, 1] sage: E(C) is S True @@ -114,7 +114,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: c = L.generating_series().coefficients(3) + sage: c = L.generating_series()[:3] sage: L._check() #False due to isomorphism types not being implemented False sage: L == loads(dumps(L)) @@ -193,7 +193,7 @@ def _gs(self, series_ring, base_ring): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.generating_series().coefficients(5) + sage: L.generating_series()[:5] [1, 1, 1, 1, 1] """ return self._F.generating_series(base_ring)(self._G.generating_series(base_ring)) @@ -204,7 +204,7 @@ def _itgs(self, series_ring, base_ring): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.isotype_generating_series().coefficients(10) + sage: L.isotype_generating_series()[:10] [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ cis = self.cycle_index_series(base_ring) @@ -216,7 +216,7 @@ def _cis(self, series_ring, base_ring): sage: E = species.SetSpecies(); C = species.CycleSpecies() sage: L = E(C) - sage: L.cycle_index_series().coefficients(5) + sage: L.cycle_index_series()[:5] [p[], p[1], p[1, 1] + p[2], @@ -233,7 +233,7 @@ def _cis(self, series_ring, base_ring): sage: E = species.SetSpecies() sage: C = species.CycleSpecies(weight=t) sage: S = E(C) - sage: S.isotype_generating_series().coefficients(5) #indirect + sage: S.isotype_generating_series()[:5] #indirect [1, t, t^2 + t, t^3 + t^2 + t, t^4 + t^3 + 2*t^2 + t] We do the same thing with set partitions weighted by the number of @@ -245,17 +245,11 @@ def _cis(self, series_ring, base_ring): sage: E = species.SetSpecies() sage: E_t = species.SetSpecies(min=1,weight=t) sage: Par = E(E_t) - sage: Par.isotype_generating_series().coefficients(5) + sage: Par.isotype_generating_series()[:5] [1, t, t^2 + t, t^3 + t^2 + t, t^4 + t^3 + 2*t^2 + t] """ f_cis = self._F.cycle_index_series(base_ring) g_cis = self._G.cycle_index_series(base_ring) - - #If G is a weighted species, then we can't use the default - #algorithm for the composition of the cycle index series - #since we must raise the weighting to the power. - if self._G.is_weighted(): - return f_cis.weighted_composition(self._G) return f_cis(g_cis) def weight_ring(self): diff --git a/src/sage/combinat/species/cycle_species.py b/src/sage/combinat/species/cycle_species.py index 83c82fc44a3..7878a028265 100644 --- a/src/sage/combinat/species/cycle_species.py +++ b/src/sage/combinat/species/cycle_species.py @@ -14,9 +14,7 @@ from .species import GenericCombinatorialSpecies from .structure import GenericSpeciesStructure -from .generating_series import _integers_from from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.integer_ring import ZZ from sage.arith.all import divisors, euler_phi from sage.combinat.species.misc import accept_size @@ -142,7 +140,7 @@ def __init__(self, min=None, max=None, weight=None): True sage: P = species.CycleSpecies() - sage: c = P.generating_series().coefficients(3) + sage: c = P.generating_series()[:3] sage: P._check() True sage: P == loads(dumps(P)) @@ -177,7 +175,7 @@ def _isotypes(self, structure_class, labels): if len(labels) != 0: yield structure_class(self, labels, range(1, len(labels)+1)) - def _gs_iterator(self, base_ring): + def _gs_callable(self, base_ring, n): r""" The generating series for cyclic permutations is `-\log(1-x) = \sum_{n=1}^\infty x^n/n`. @@ -186,20 +184,19 @@ def _gs_iterator(self, base_ring): sage: P = species.CycleSpecies() sage: g = P.generating_series() - sage: g.coefficients(10) + sage: g[0:10] [0, 1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9] TESTS:: sage: P = species.CycleSpecies() sage: g = P.generating_series(RR) - sage: g.coefficients(3) + sage: g[0:3] [0.000000000000000, 1.00000000000000, 0.500000000000000] """ - one = base_ring(1) - yield base_ring(0) - for n in _integers_from(ZZ(1)): - yield self._weight*one/n + if n: + return self._weight * base_ring.one() / n + return base_ring.zero() def _order(self): """ @@ -213,7 +210,7 @@ def _order(self): """ return 1 - def _itgs_list(self, base_ring): + def _itgs_list(self, base_ring, n): """ The isomorphism type generating series for cyclic permutations is given by `x/(1-x)`. @@ -222,19 +219,21 @@ def _itgs_list(self, base_ring): sage: P = species.CycleSpecies() sage: g = P.isotype_generating_series() - sage: g.coefficients(5) + sage: g[0:5] [0, 1, 1, 1, 1] TESTS:: sage: P = species.CycleSpecies() sage: g = P.isotype_generating_series(RR) - sage: g.coefficients(3) + sage: g[0:3] [0.000000000000000, 1.00000000000000, 1.00000000000000] """ - return [base_ring(0), self._weight*base_ring(1)] + if n: + return self._weight * base_ring.one() + return base_ring.zero() - def _cis_iterator(self, base_ring): + def _cis_callable(self, base_ring, n): r""" The cycle index series of the species of cyclic permutations is given by @@ -256,7 +255,7 @@ def _cis_iterator(self, base_ring): sage: P = species.CycleSpecies() sage: cis = P.cycle_index_series() - sage: cis.coefficients(7) + sage: cis[0:7] [0, p[1], 1/2*p[1, 1] + 1/2*p[2], @@ -268,15 +267,15 @@ def _cis_iterator(self, base_ring): from sage.combinat.sf.sf import SymmetricFunctions p = SymmetricFunctions(base_ring).power() - zero = base_ring(0) + zero = base_ring.zero() - yield zero - for n in _integers_from(1): - res = zero - for k in divisors(n): - res += euler_phi(k)*p([k])**(n//k) - res /= n - yield self._weight*res + if not n: + return zero + res = zero + for k in divisors(n): + res += euler_phi(k)*p([k])**(n//k) + res /= n + return self._weight * res #Backward compatibility CycleSpecies_class = CycleSpecies diff --git a/src/sage/combinat/species/empty_species.py b/src/sage/combinat/species/empty_species.py index 600ea3ee2b7..5fd8081d1f8 100644 --- a/src/sage/combinat/species/empty_species.py +++ b/src/sage/combinat/species/empty_species.py @@ -16,7 +16,6 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from .species import GenericCombinatorialSpecies -from .series_order import inf from sage.structure.unique_representation import UniqueRepresentation class EmptySpecies(GenericCombinatorialSpecies, UniqueRepresentation): @@ -34,11 +33,11 @@ class EmptySpecies(GenericCombinatorialSpecies, UniqueRepresentation): [] sage: X.structures([1,2]).list() [] - sage: X.generating_series().coefficients(4) + sage: X.generating_series()[0:4] [0, 0, 0, 0] - sage: X.isotype_generating_series().coefficients(4) + sage: X.isotype_generating_series()[0:4] [0, 0, 0, 0] - sage: X.cycle_index_series().coefficients(4) + sage: X.cycle_index_series()[0:4] [0, 0, 0, 0] The empty species is the zero of the semi-ring of species. @@ -49,14 +48,14 @@ class EmptySpecies(GenericCombinatorialSpecies, UniqueRepresentation): sage: X = S + Empt sage: X == S # TODO: Not Implemented True - sage: (X.generating_series().coefficients(4) == - ....: S.generating_series().coefficients(4)) + sage: (X.generating_series()[0:4] == + ....: S.generating_series()[0:4]) True - sage: (X.isotype_generating_series().coefficients(4) == - ....: S.isotype_generating_series().coefficients(4)) + sage: (X.isotype_generating_series()[0:4] == + ....: S.isotype_generating_series()[0:4]) True - sage: (X.cycle_index_series().coefficients(4) == - ....: S.cycle_index_series().coefficients(4)) + sage: (X.cycle_index_series()[0:4] == + ....: S.cycle_index_series()[0:4]) True The following tests that it is the zero element with respect to @@ -65,11 +64,11 @@ class EmptySpecies(GenericCombinatorialSpecies, UniqueRepresentation): sage: Y = Empt*S sage: Y == Empt # TODO: Not Implemented True - sage: Y.generating_series().coefficients(4) + sage: Y.generating_series()[0:4] [0, 0, 0, 0] - sage: Y.isotype_generating_series().coefficients(4) + sage: Y.isotype_generating_series()[0:4] [0, 0, 0, 0] - sage: Y.cycle_index_series().coefficients(4) + sage: Y.cycle_index_series()[0:4] [0, 0, 0, 0] TESTS:: @@ -102,7 +101,7 @@ def _gs(self, series_ring, base_ring): EXAMPLES:: sage: F = species.EmptySpecies() - sage: F.generating_series().coefficients(5) # indirect doctest + sage: F.generating_series()[0:5] # indirect doctest [0, 0, 0, 0, 0] sage: F.generating_series().count(3) 0 @@ -114,18 +113,6 @@ def _gs(self, series_ring, base_ring): _itgs = _gs _cis = _gs - def _order(self): - """ - Returns the order of the generating series. - - EXAMPLES:: - - sage: F = species.EmptySpecies() - sage: F._order() - Infinite series order - """ - return inf - def _structures(self, structure_class, labels): """ Thanks to the counting optimisation, this is never called... Otherwise diff --git a/src/sage/combinat/species/functorial_composition_species.py b/src/sage/combinat/species/functorial_composition_species.py index 4930a70e6da..1f082753638 100644 --- a/src/sage/combinat/species/functorial_composition_species.py +++ b/src/sage/combinat/species/functorial_composition_species.py @@ -33,11 +33,11 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: WP = species.SubsetSpecies() sage: P2 = E2*E sage: G = WP.functorial_composition(P2) - sage: G.isotype_generating_series().coefficients(5) + sage: G.isotype_generating_series()[0:5] [1, 1, 2, 4, 11] sage: G = species.SimpleGraphSpecies() - sage: c = G.generating_series().coefficients(2) + sage: c = G.generating_series()[0:2] sage: type(G) sage: G == loads(dumps(G)) @@ -93,7 +93,7 @@ def _gs(self, series_ring, base_ring): EXAMPLES:: sage: G = species.SimpleGraphSpecies() - sage: G.generating_series().coefficients(5) + sage: G.generating_series()[0:5] [1, 1, 1, 4/3, 8/3] """ return self._F.generating_series(base_ring).functorial_composition(self._G.generating_series(base_ring)) @@ -103,7 +103,7 @@ def _itgs(self, series_ring, base_ring): EXAMPLES:: sage: G = species.SimpleGraphSpecies() - sage: G.isotype_generating_series().coefficients(5) + sage: G.isotype_generating_series()[0:5] [1, 1, 2, 4, 11] """ return self.cycle_index_series(base_ring).isotype_generating_series() @@ -113,7 +113,7 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: G = species.SimpleGraphSpecies() - sage: G.cycle_index_series().coefficients(5) + sage: G.cycle_index_series()[0:5] [p[], p[1], p[1, 1] + p[2], diff --git a/src/sage/combinat/species/generating_series.py b/src/sage/combinat/species/generating_series.py index 02e1bb52332..c6c30f301b6 100644 --- a/src/sage/combinat/species/generating_series.py +++ b/src/sage/combinat/species/generating_series.py @@ -15,37 +15,11 @@ TESTS:: - sage: from sage.combinat.species.stream import Stream, _integers_from sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: p = SymmetricFunctions(QQ).power() sage: CIS = CycleIndexSeriesRing(QQ) - -:: - - sage: geo1 = CIS((p([1])^i for i in _integers_from(0))) - sage: geo2 = CIS((p([2])^i for i in _integers_from(0))) - sage: s = geo1 * geo2 - sage: s[0] - p[] - sage: s[1] - p[1] + p[2] - sage: s[2] - p[1, 1] + p[2, 1] + p[2, 2] - sage: s[3] - p[1, 1, 1] + p[2, 1, 1] + p[2, 2, 1] + p[2, 2, 2] - -Whereas the coefficients of the above test are homogeneous with -respect to total degree, the following test groups with respect to -weighted degree where each variable x_i has weight i. - -:: - - sage: def g(): - ....: for i in _integers_from(0): - ....: yield p([2])^i - ....: yield p(0) - sage: geo1 = CIS((p([1])^i for i in _integers_from(0))) - sage: geo2 = CIS(g()) + sage: geo1 = CIS(lambda i: p([1])^i) + sage: geo2 = CIS(lambda i: p([2])^(i // 2) if is_even(i) else 0) sage: s = geo1 * geo2 sage: s[0] p[] @@ -55,8 +29,6 @@ p[1, 1] + p[2] sage: s[3] p[1, 1, 1] + p[2, 1] - sage: s[4] - p[1, 1, 1, 1] + p[2, 1, 1] + p[2, 2] REFERENCES: @@ -77,67 +49,40 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from .series import LazyPowerSeriesRing, LazyPowerSeries -from .stream import Stream, _integers_from +from sage.rings.lazy_series import LazyPowerSeries, LazySymmetricFunction +from sage.rings.lazy_series_ring import LazyPowerSeriesRing, LazySymmetricFunctions from sage.rings.integer import Integer -from sage.rings.rational_field import RationalField -from sage.arith.all import moebius, gcd, lcm, divisors +from sage.rings.rational_field import QQ +from sage.arith.all import divisors from sage.combinat.partition import Partition, Partitions -from functools import partial from sage.combinat.sf.sf import SymmetricFunctions from sage.misc.cachefunc import cached_function from sage.arith.misc import factorial -@cached_function -def OrdinaryGeneratingSeriesRing(R): - """ - Return the ring of ordinary generating series over ``R``. +class OrdinaryGeneratingSeries(LazyPowerSeries): + r""" + A class for ordinary generating series. - Note that it is just a - :class:`LazyPowerSeriesRing` whose elements have - some extra methods. + Note that it is just a :class:`LazyPowerSeries` whose elements + have some extra methods. EXAMPLES:: sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing - sage: R = OrdinaryGeneratingSeriesRing(QQ); R - Lazy Power Series Ring over Rational Field - sage: R([1]).coefficients(4) - [1, 1, 1, 1] - sage: R([1]).counts(4) - [1, 1, 1, 1] - - TESTS: - - We test to make sure that caching works. - - :: - - sage: R is OrdinaryGeneratingSeriesRing(QQ) - True + sage: R = OrdinaryGeneratingSeriesRing(QQ) + sage: f = R(lambda n: n) + sage: f + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) """ - return OrdinaryGeneratingSeriesRing_class(R) - - -class OrdinaryGeneratingSeriesRing_class(LazyPowerSeriesRing): - def __init__(self, R): - """ - EXAMPLES:: - - sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing - sage: R = OrdinaryGeneratingSeriesRing(QQ) - sage: R == loads(dumps(R)) - True - """ - LazyPowerSeriesRing.__init__(self, R, element_class=OrdinaryGeneratingSeries) - - -class OrdinaryGeneratingSeries(LazyPowerSeries): def count(self, n): """ Return the number of structures on a set of size ``n``. + INPUT: + + - ``n`` -- the size of the set + EXAMPLES:: sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing @@ -164,10 +109,9 @@ def counts(self, n): return [self.count(i) for i in range(n)] -@cached_function -def ExponentialGeneratingSeriesRing(R): - """ - Return the ring of exponential generating series over ``R``. +class OrdinaryGeneratingSeriesRing(LazyPowerSeriesRing): + r""" + Return the ring of ordinary generating series over ``R``. Note that it is just a :class:`LazyPowerSeriesRing` whose elements have @@ -175,39 +119,57 @@ def ExponentialGeneratingSeriesRing(R): EXAMPLES:: - sage: from sage.combinat.species.generating_series import ExponentialGeneratingSeriesRing - sage: R = ExponentialGeneratingSeriesRing(QQ); R - Lazy Power Series Ring over Rational Field - sage: R([1]).coefficients(4) + sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing + sage: R = OrdinaryGeneratingSeriesRing(QQ); R + Lazy Taylor Series Ring in z over Rational Field + sage: [R(lambda n: 1).coefficient(i) for i in range(4)] [1, 1, 1, 1] - sage: R([1]).counts(4) - [1, 1, 2, 6] + sage: R(lambda n: 1).counts(4) + [1, 1, 1, 1] + sage: R == loads(dumps(R)) + True TESTS: - We test to make sure that caching works. - - :: + We test to make sure that caching works:: - sage: R is ExponentialGeneratingSeriesRing(QQ) + sage: R is OrdinaryGeneratingSeriesRing(QQ) True """ - return ExponentialGeneratingSeriesRing_class(R) + def __init__(self, base_ring): + """ + Initialize ``self``. + TESTS:: -class ExponentialGeneratingSeriesRing_class(LazyPowerSeriesRing): - def __init__(self, R): - """ - EXAMPLES:: + sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing + sage: OrdinaryGeneratingSeriesRing.options.halting_precision(15) + sage: R = OrdinaryGeneratingSeriesRing(QQ) + sage: TestSuite(R).run() - sage: from sage.combinat.species.generating_series import ExponentialGeneratingSeriesRing - sage: R = ExponentialGeneratingSeriesRing(QQ) - sage: R == loads(dumps(R)) - True + sage: OrdinaryGeneratingSeriesRing.options._reset() # reset options """ - LazyPowerSeriesRing.__init__(self, R, element_class=ExponentialGeneratingSeries) + super().__init__(base_ring, names="z") + + Element = OrdinaryGeneratingSeries + class ExponentialGeneratingSeries(LazyPowerSeries): + r""" + A class for ordinary generating series. + + Note that it is just a + :class:`LazyPowerSeries` whose elements have + some extra methods. + + EXAMPLES:: + + sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing + sage: R = OrdinaryGeneratingSeriesRing(QQ) + sage: f = R(lambda n: n) + sage: f + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + """ def count(self, n): """ Return the number of structures of size ``n``. @@ -216,7 +178,7 @@ def count(self, n): sage: from sage.combinat.species.generating_series import ExponentialGeneratingSeriesRing sage: R = ExponentialGeneratingSeriesRing(QQ) - sage: f = R([1]) + sage: f = R(lambda n: 1) sage: [f.count(i) for i in range(7)] [1, 1, 2, 6, 24, 120, 720] """ @@ -248,7 +210,7 @@ def functorial_composition(self, y): .. MATH:: - f \Box g = \sum_{n=0}^{\infty} f_{g_n} \frac{x^n}{n!} + f \Box g = \sum_{n=0}^{\infty} f_{g_n} \frac{x^n}{n!}. REFERENCES: @@ -258,17 +220,8 @@ def functorial_composition(self, y): sage: G = species.SimpleGraphSpecies() sage: g = G.generating_series() - sage: g.coefficients(10) + sage: [g.coefficient(i) for i in range(10)] [1, 1, 1, 4/3, 8/3, 128/15, 2048/45, 131072/315, 2097152/315, 536870912/2835] - """ - return self._new(partial(self._functorial_compose_gen, y), lambda a,b: 0, self, y) - - def _functorial_compose_gen(self, y, ao): - """ - Returns a generator for the coefficients of the functorial - composition of self with y. - - EXAMPLES:: sage: E = species.SetSpecies() sage: E2 = E.restricted(min=2, max=3) @@ -276,117 +229,56 @@ def _functorial_compose_gen(self, y, ao): sage: P2 = E2*E sage: g1 = WP.generating_series() sage: g2 = P2.generating_series() - sage: g = g1._functorial_compose_gen(g2, 0) - sage: [next(g) for i in range(10)] + sage: g1.functorial_composition(g2)[:10] [1, 1, 1, 4/3, 8/3, 128/15, 2048/45, 131072/315, 2097152/315, 536870912/2835] """ - n = 0 - while True: - yield self.count(y.count(n)) / factorial(n) - n += 1 - + P = self.parent() + return P(lambda n: self.count(y.count(n)) / factorial(n), 0) -def factorial_gen(): - """ - A generator for the factorials starting at 0. - - EXAMPLES:: - - sage: from sage.combinat.species.generating_series import factorial_gen - sage: g = factorial_gen() - sage: [next(g) for i in range(5)] - [1, 1, 2, 6, 24] - """ - z = Integer(1) - yield z - yield z - n = Integer(2) - while True: - z *= n - yield z - n += 1 - - -@cached_function -def CycleIndexSeriesRing(R): +class ExponentialGeneratingSeriesRing(LazyPowerSeriesRing): r""" - Return the ring of cycle index series over ``R``. - - This is the ring of formal power series `\Lambda[x]`, where - `\Lambda` is the ring of symmetric functions over ``R`` in the - `p`-basis. Its purpose is to house the cycle index series of - species (in a somewhat nonstandard notation tailored to Sage): - If `F` is a species, then the *cycle index series* of `F` is - defined to be the formal power series - - .. MATH:: - - \sum_{n \geq 0} \frac{1}{n!} (\sum_{\sigma \in S_n} - \operatorname{fix} F[\sigma] - \prod_{z \text{ is a cycle of } \sigma} - p_{\text{length of } z}) x^n - \in \Lambda_\QQ [x], - - where `\operatorname{fix} F[\sigma]` denotes the number of - fixed points of the permutation `F[\sigma]` of `F[n]`. We - notice that this power series is "equigraded" (meaning that - its `x^n`-coefficient is homogeneous of degree `n`). A more - standard convention in combinatorics would be to use - `x_i` instead of `p_i`, and drop the `x` (that is, evaluate - the above power series at `x = 1`); but this would be more - difficult to implement in Sage, as it would be an element - of a power series ring in infinitely many variables. + Return the ring of exponential generating series over ``R``. - Note that it is just a :class:`LazyPowerSeriesRing` (whose base - ring is `\Lambda`) whose elements have some extra methods. + Note that it is just a + :class:`LazyPowerSeriesRing` whose elements have + some extra methods. EXAMPLES:: - sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: R = CycleIndexSeriesRing(QQ); R - Cycle Index Series Ring over Symmetric Functions over Rational Field in the powersum basis - sage: R([1]).coefficients(4) # This is not combinatorially - ....: # meaningful. + sage: from sage.combinat.species.generating_series import ExponentialGeneratingSeriesRing + sage: R = ExponentialGeneratingSeriesRing(QQ); R + Lazy Taylor Series Ring in z over Rational Field + sage: [R(lambda n: 1).coefficient(i) for i in range(4)] [1, 1, 1, 1] + sage: R(lambda n: 1).counts(4) + [1, 1, 2, 6] TESTS: - We test to make sure that caching works. + We test to make sure that caching works:: - :: - - sage: R is CycleIndexSeriesRing(QQ) + sage: R is ExponentialGeneratingSeriesRing(QQ) True """ - return CycleIndexSeriesRing_class(R) - - -class CycleIndexSeriesRing_class(LazyPowerSeriesRing): - def __init__(self, R): + def __init__(self, base_ring): """ - EXAMPLES:: + Initialize ``self``. - sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: R = CycleIndexSeriesRing(QQ); R - Cycle Index Series Ring over Symmetric Functions over Rational Field in the powersum basis - sage: R == loads(dumps(R)) - True - """ - R = SymmetricFunctions(R).power() - LazyPowerSeriesRing.__init__(self, R, element_class=CycleIndexSeries) + TESTS:: - def __repr__(self): - """ - EXAMPLES:: + sage: from sage.combinat.species.generating_series import ExponentialGeneratingSeriesRing + sage: ExponentialGeneratingSeriesRing.options.halting_precision(15) + sage: R = ExponentialGeneratingSeriesRing(QQ) + sage: TestSuite(R).run() - sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: CycleIndexSeriesRing(QQ) - Cycle Index Series Ring over Symmetric Functions over Rational Field in the powersum basis + sage: ExponentialGeneratingSeriesRing.options._reset() # reset options """ - return "Cycle Index Series Ring over %s" % self.base_ring() + super().__init__(base_ring, names="z") + + Element = ExponentialGeneratingSeries -class CycleIndexSeries(LazyPowerSeries): +class CycleIndexSeries(LazySymmetricFunction): def count(self, t): """ Return the number of structures corresponding to a certain cycle @@ -410,7 +302,7 @@ def count(self, t): def coefficient_cycle_type(self, t): """ - Returns the coefficient of a cycle type ``t`` in ``self``. + Return the coefficient of a cycle type ``t`` in ``self``. EXAMPLES:: @@ -429,668 +321,75 @@ def coefficient_cycle_type(self, t): p = self.coefficient(t.size()) return p.coefficient(t) - - def stretch(self, k): - r""" - Return the stretch of the cycle index series ``self`` by a positive - integer `k`. - - If - - .. MATH:: - - f = \sum_{n=0}^{\infty} f_n(p_1, p_2, p_3, \ldots ), - - then the stretch `g` of `f` by `k` is - - .. MATH:: - - g = \sum_{n=0}^{\infty} f_n(p_k, p_{2k}, p_{3k}, \ldots ). - - EXAMPLES:: - - sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() - sage: CIS = CycleIndexSeriesRing(QQ) - sage: f = CIS([p([]), p([1]), p([2]), p.zero()]) - sage: f.stretch(3).coefficients(10) - [p[], 0, 0, p[3], 0, 0, p[6], 0, 0, 0] - """ - return self._new(partial(self._stretch_gen, k), lambda ao: k*ao, self) - - def _stretch_gen(self, k, ao): - """ - EXAMPLES:: - - sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing - sage: p = SymmetricFunctions(QQ).power() - sage: CIS = CycleIndexSeriesRing(QQ) - sage: f = CIS([p([1])]) # This is the power series whose all coefficients - ....: # are p[1]. Not combinatorially meaningful! - sage: g = f._stretch_gen(2,0) - sage: [next(g) for i in range(10)] - [p[2], 0, p[2], 0, p[2], 0, p[2], 0, p[2], 0] - """ - from sage.combinat.partition import Partition - BR = self.base_ring() - zero = BR.zero() - - stretch_k = lambda p: Partition([k*i for i in p]) - - yield self.coefficient(0).map_support(stretch_k) - - n = 1 - while True: - for i in range(k-1): - yield zero - yield self.coefficient(n).map_support(stretch_k) - n += 1 - def isotype_generating_series(self): """ + Return the isotype generating series of ``self``. + EXAMPLES:: sage: P = species.PermutationSpecies() sage: cis = P.cycle_index_series() sage: f = cis.isotype_generating_series() - sage: f.coefficients(10) + sage: f[:10] [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ - R = self.base_ring().base_ring() - OGS = OrdinaryGeneratingSeriesRing(R)() - return OGS._new(self._ogs_gen, lambda ao: ao, self) - - def expand_as_sf(self, n, alphabet='x'): - """ - Returns the expansion of a cycle index series as a symmetric function in - ``n`` variables. - - Specifically, this returns a :class:`~sage.combinat.species.series.LazyPowerSeries` whose - ith term is obtained by calling :meth:`~sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic_Element.expand` - on the ith term of ``self``. - - This relies on the (standard) interpretation of a cycle index series as a symmetric function - in the power sum basis. - - INPUT: - - - ``self`` -- a cycle index series - - - ``n`` -- a positive integer - - - ``alphabet`` -- a variable for the expansion (default: `x`) - - EXAMPLES:: - - sage: from sage.combinat.species.set_species import SetSpecies - sage: SetSpecies().cycle_index_series().expand_as_sf(2).coefficients(4) - [1, x0 + x1, x0^2 + x0*x1 + x1^2, x0^3 + x0^2*x1 + x0*x1^2 + x1^3] - - """ - expanded_poly_ring = self.coefficient(0).expand(n, alphabet).parent() - LPSR = LazyPowerSeriesRing(expanded_poly_ring) - - expander_gen = (LPSR.term(self.coefficient(i).expand(n, alphabet), i) for i in _integers_from(0)) + R = self.base_ring() + OGS = OrdinaryGeneratingSeriesRing(R) + return OGS(lambda n: self._ogs_gen(n, self._coeff_stream._approximate_order), + self._coeff_stream._approximate_order) - return LPSR.sum_generator(expander_gen) - - def _ogs_gen(self, ao): + def _ogs_gen(self, n, ao): """ - Returns a generator for the coefficients of the ordinary generating + Return a generator for the coefficients of the ordinary generating series obtained from a cycle index series. EXAMPLES:: sage: P = species.PermutationSpecies() sage: cis = P.cycle_index_series() - sage: g = cis._ogs_gen(0) - sage: [next(g) for i in range(10)] + sage: [cis._ogs_gen(i, 0) for i in range(10)] [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ - for i in range(ao): - yield 0 - for i in _integers_from(ao): - yield sum( self.coefficient(i).coefficients() ) + if n < ao: + return 0 + return sum(self.coefficient(n).coefficients()) def generating_series(self): """ + Return the generating series of ``self``. + EXAMPLES:: sage: P = species.PartitionSpecies() sage: cis = P.cycle_index_series() sage: f = cis.generating_series() - sage: f.coefficients(5) + sage: f[:5] [1, 1, 1, 5/6, 5/8] """ - R = self.base_ring().base_ring() - EGS = ExponentialGeneratingSeriesRing(R)() - return EGS._new(self._egs_gen, lambda ao: ao, self) + R = self.base_ring() + EGS = ExponentialGeneratingSeriesRing(R) + return EGS(lambda n: self._egs_gen(n, self._coeff_stream._approximate_order), + self._coeff_stream._approximate_order) - def _egs_gen(self, ao): + def _egs_gen(self, n, ao): """ - Returns a generator for the coefficients of the exponential + Return a generator for the coefficients of the exponential generating series obtained from a cycle index series. EXAMPLES:: sage: P = species.PermutationSpecies() sage: cis = P.cycle_index_series() - sage: g = cis._egs_gen(0) - sage: [next(g) for i in range(10)] + sage: [cis._egs_gen(i, 0) for i in range(10)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] """ - for i in range(ao): - yield 0 - for i in _integers_from(ao): - yield self.coefficient(i).coefficient([1]*i) - - def __invert__(self): - r""" - Return the multiplicative inverse of ``self``. - - This algorithm is derived from [BLL]_. - - EXAMPLES:: - - sage: E = species.SetSpecies().cycle_index_series() - sage: E.__invert__().coefficients(4) - [p[], -p[1], 1/2*p[1, 1] - 1/2*p[2], -1/6*p[1, 1, 1] + 1/2*p[2, 1] - 1/3*p[3]] - - The defining characteristic of the multiplicative inverse `F^{-1}` of - a cycle index series `F` is that `F \cdot F^{-1} = F^{-1} \cdot F = 1` - (that is, both products with `F` yield the multiplicative identity `1`):: - - sage: E = species.SetSpecies().cycle_index_series() - sage: (E * ~E).coefficients(6) - [p[], 0, 0, 0, 0, 0] - - REFERENCES: - - - [BLL]_ - - [BLL-Intro]_ - - http://bergeron.math.uqam.ca/Site/bergeron_anglais_files/livre_combinatoire.pdf - - AUTHORS: - - - Andrew Gainer-Dewar - """ - if self.coefficient(0) == 0: - raise ValueError("constant term must be non-zero") - - def multinv_builder(i): - return self.coefficient(0)**(-i-1) * (self.coefficient(0) + (-1)*self)**i - - return self.parent().sum_generator(multinv_builder(i) for i in _integers_from(0)) - - def _div_(self, y): - """ - TESTS:: - - sage: E = species.SetSpecies().cycle_index_series() - sage: (E / E).coefficients(6) - [p[], 0, 0, 0, 0, 0] - """ - return self*(~y) + if n < ao: + return 0 + return self.coefficient(n).coefficient([1]*n) - def functorial_composition(self, g): + def derivative(self, n=1): r""" - Returns the functorial composition of ``self`` and ``g``. - - If `F` and `G` are species, their functorial composition is the species - `F \Box G` obtained by setting `(F \Box G) [A] = F[ G[A] ]`. - In other words, an `(F \Box G)`-structure on a set `A` of labels is an - `F`-structure whose labels are the set of all `G`-structures on `A`. - - It can be shown (as in section 2.2 of [BLL]_) that there is a - corresponding operation on cycle indices: - - .. MATH:: - - Z_{F} \Box Z_{G} = \sum_{n \geq 0} \frac{1}{n!} - \sum_{\sigma \in \mathfrak{S}_{n}} - \operatorname{fix} F[ (G[\sigma])_{1}, (G[\sigma])_{2}, \ldots ] - \, p_{1}^{\sigma_{1}} p_{2}^{\sigma_{2}} \cdots. - - This method implements that operation on cycle index series. - - EXAMPLES: - - The species `G` of simple graphs can be expressed in terms of a functorial - composition: `G = \mathfrak{p} \Box \mathfrak{p}_{2}`, where - `\mathfrak{p}` is the :class:`~sage.combinat.species.subset_species.SubsetSpecies`. - This is how it is implemented in - :meth:`~sage.combinat.species.library.SimpleGraphSpecies`:: - - sage: S = species.SimpleGraphSpecies() - sage: S.cycle_index_series().coefficients(5) - [p[], - p[1], - p[1, 1] + p[2], - 4/3*p[1, 1, 1] + 2*p[2, 1] + 2/3*p[3], - 8/3*p[1, 1, 1, 1] + 4*p[2, 1, 1] + 2*p[2, 2] + 4/3*p[3, 1] + p[4]] - """ - return self._new(partial(self._functorial_compose_gen, g), lambda a,b: 0, self, g) - - def _functorial_compose_gen(self, g, ao): - """ - Return a generator for the coefficients of the functorial - composition of ``self`` with ``g``. - - EXAMPLES:: - - sage: E = species.SetSpecies() - sage: E2 = species.SetSpecies(size=2) - sage: WP = species.SubsetSpecies() - sage: P2 = E2*E - sage: P2_cis = P2.cycle_index_series() - sage: WP_cis = WP.cycle_index_series() - sage: g = WP_cis._functorial_compose_gen(P2_cis,0) - sage: [next(g) for i in range(5)] - [p[], - p[1], - p[1, 1] + p[2], - 4/3*p[1, 1, 1] + 2*p[2, 1] + 2/3*p[3], - 8/3*p[1, 1, 1, 1] + 4*p[2, 1, 1] + 2*p[2, 2] + 4/3*p[3, 1] + p[4]] - """ - p = self.parent().base_ring() - n = 0 - while True: - res = p(0) - for s in Partitions(n): - t = g._cycle_type(s) - q = self.count(t) / s.aut() - res += q*p(s) - yield res - n += 1 - - def arithmetic_product(self, g, check_input = True): - r""" - Return the arithmetic product of ``self`` with ``g``. - - For species `M` and `N` such that `M[\\varnothing] = N[\\varnothing] = \\varnothing`, - their arithmetic product is the species `M \\boxdot N` of "`M`-assemblies of cloned `N`-structures". - This operation is defined and several examples are given in [MM]_. - - The cycle index series for `M \\boxdot N` can be computed in terms of the component series `Z_M` and `Z_N`, - as implemented in this method. - - INPUT: - - - ``g`` -- a cycle index series having the same parent as ``self``. - - - ``check_input`` -- (default: ``True``) a Boolean which, when set - to ``False``, will cause input checks to be skipped. - - OUTPUT: - - The arithmetic product of ``self`` with ``g``. This is a cycle - index series defined in terms of ``self`` and ``g`` such that - if ``self`` and ``g`` are the cycle index series of two species - `M` and `N`, their arithmetic product is the cycle index series - of the species `M \\boxdot N`. - - EXAMPLES: - - For `C` the species of (oriented) cycles and `L_{+}` the species of nonempty linear orders, `C \\boxdot L_{+}` corresponds - to the species of "regular octopuses"; a `(C \\boxdot L_{+})`-structure is a cycle of some length, each of whose elements - is an ordered list of a length which is consistent for all the lists in the structure. :: - - sage: C = species.CycleSpecies().cycle_index_series() - sage: Lplus = species.LinearOrderSpecies(min=1).cycle_index_series() - sage: RegularOctopuses = C.arithmetic_product(Lplus) - sage: RegOctSpeciesSeq = RegularOctopuses.generating_series().counts(8) - sage: RegOctSpeciesSeq - [0, 1, 3, 8, 42, 144, 1440, 5760] - - It is shown in [MM]_ that the exponential generating function for regular octopuses satisfies - `(C \\boxdot L_{+}) (x) = \\sum_{n \geq 1} \\sigma (n) (n - 1)! \\frac{x^{n}}{n!}` (where `\\sigma (n)` is - the sum of the divisors of `n`). :: - - sage: RegOctDirectSeq = [0] + [sum(divisors(i))*factorial(i-1) for i in range(1,8)] - sage: RegOctDirectSeq == RegOctSpeciesSeq - True - - AUTHORS: - - - Andrew Gainer-Dewar (2013) - - REFERENCES: - - .. [MM] \M. Maia and M. Mendez. "On the arithmetic product of combinatorial species". - Discrete Mathematics, vol. 308, issue 23, 2008, pp. 5407-5427. - :arxiv:`math/0503436v2`. - - """ - from itertools import product, repeat, chain - - p = self.base_ring() - - if check_input: - assert self.coefficient(0) == p.zero() - assert g.coefficient(0) == p.zero() - - # We first define an operation `\\boxtimes` on partitions as in Lemma 2.1 of [MM]_. - def arith_prod_of_partitions(l1, l2): - # Given two partitions `l_1` and `l_2`, we construct a new partition `l_1 \\boxtimes l_2` by - # the following procedure: each pair of parts `a \\in l_1` and `b \\in l_2` contributes - # `\\gcd (a, b)`` parts of size `\\lcm (a, b)` to `l_1 \\boxtimes l_2`. If `l_1` and `l_2` - # are partitions of integers `n` and `m`, respectively, then `l_1 \\boxtimes l_2` is a - # partition of `nm`. - term_iterable = chain.from_iterable(repeat(lcm(pair), gcd(pair)) - for pair in product(l1, l2)) - return Partition(sorted(term_iterable, reverse=True)) - - # We then extend this to an operation on symmetric functions as per eq. (52) of [MM]_. - # (Maia and Mendez, in [MM]_, are talking about polynomials instead of symmetric - # functions, but this boils down to the same: Their x_i corresponds to the i-th power - # sum symmetric function.) - def arith_prod_sf(x, y): - ap_sf_wrapper = lambda l1, l2: p(arith_prod_of_partitions(l1, l2)) - return p._apply_multi_module_morphism(x, y, ap_sf_wrapper) - - # Sage stores cycle index series by degree. - # Thus, to compute the arithmetic product `Z_M \\boxdot Z_N` it is useful - # to compute all terms of a given degree `n` at once. - def arith_prod_coeff(n): - if n == 0: - res = p.zero() - else: - index_set = ((d, n // d) for d in divisors(n)) - res = sum(arith_prod_sf(self.coefficient(i), g.coefficient(j)) for i,j in index_set) - - # Build a list which has res in the `n`th slot and 0's before and after - # to feed to sum_generator - res_in_seq = [p.zero()]*n + [res, p.zero()] - - return self.parent(res_in_seq) - - # Finally, we use the sum_generator method to assemble these results into a single - # LazyPowerSeries object. - return self.parent().sum_generator(arith_prod_coeff(n) for n in _integers_from(0)) - - def _cycle_type(self, s): - """ - EXAMPLES:: - - sage: cis = species.PartitionSpecies().cycle_index_series() - sage: [cis._cycle_type(p) for p in Partitions(3)] - [[3, 1, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]] - sage: cis = species.PermutationSpecies().cycle_index_series() - sage: [cis._cycle_type(p) for p in Partitions(3)] - [[3, 1, 1, 1], [2, 2, 1, 1], [1, 1, 1, 1, 1, 1]] - sage: cis = species.SetSpecies().cycle_index_series() - sage: [cis._cycle_type(p) for p in Partitions(3)] - [[1], [1], [1]] - """ - if s == []: - return self._card(0) - res = [] - for k in range(1, self._upper_bound_for_longest_cycle(s)+1): - e = 0 - for d in divisors(k): - m = moebius(d) - if m == 0: - continue - u = s.power(k/d) - e += m*self.count(u) - res.extend([k]*int(e/k)) - res.reverse() - return Partition(res) - - - def _upper_bound_for_longest_cycle(self, s): - """ - EXAMPLES:: - - sage: cis = species.PartitionSpecies().cycle_index_series() - sage: cis._upper_bound_for_longest_cycle([4]) - 4 - sage: cis._upper_bound_for_longest_cycle([3,1]) - 3 - sage: cis._upper_bound_for_longest_cycle([2,2]) - 2 - sage: cis._upper_bound_for_longest_cycle([2,1,1]) - 2 - sage: cis._upper_bound_for_longest_cycle([1,1,1,1]) - 1 - """ - if s == []: - return 1 - return min(self._card(sum(s)), lcm(list(s))) - - def _card(self, n): - r""" - Return the number of structures on an underlying set of size ``n`` for - the species associated with ``self``. - - This is just ``n!`` times the coefficient of ``p[1]n`` in ``self``. - - EXAMPLES:: - - sage: cis = species.PartitionSpecies().cycle_index_series() - sage: cis._card(4) - 15 - """ - p = self.coefficient(n) - return factorial(n) * p.coefficient([1] * n) - - def _compose_gen(self, y, ao): - """ - Return a generator for the coefficients of the composition of this - cycle index series and the cycle index series ``y``. This overrides - the method defined in ``LazyPowerSeries``. - - The notion "composition" means plethystic substitution here, as - defined in Section 2.2 of [BLL-Intro]_. - - EXAMPLES:: - - sage: E = species.SetSpecies(); C = species.CycleSpecies() - sage: E_cis = E.cycle_index_series() - sage: g = E_cis._compose_gen(C.cycle_index_series(),0) - sage: [next(g) for i in range(4)] - [p[], p[1], p[1, 1] + p[2], p[1, 1, 1] + p[2, 1] + p[3]] - """ - assert y.coefficient(0) == 0 - y_powers = Stream(y._power_gen()) - - parent = self.parent() - res = parent.sum_generator(self._compose_term(self.coefficient(i), y_powers) - for i in _integers_from(0)) - - for i in _integers_from(0): - yield res.coefficient(i) - - def _compose_term(self, p, y_powers): - r""" - Return the composition of one term in ``self`` with `y`. - - INPUT: - - - ``p`` - a term in ``self`` - - ``y_powers`` - a stream for the powers of `y` - starting with `y` - - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: E = species.SetSpecies(); C = species.CycleSpecies() - sage: E_cis = E.cycle_index_series() - sage: C_cis = C.cycle_index_series() - sage: c_powers = Stream(C_cis._power_gen()) - sage: p2 = E_cis.coefficient(2); p2 - 1/2*p[1, 1] + 1/2*p[2] - sage: E_cis._compose_term(p2, c_powers).coefficients(4) - [0, 0, 1/2*p[1, 1] + 1/2*p[2], 1/2*p[1, 1, 1] + 1/2*p[2, 1]] - """ - parent = self.parent() - if p == 0: - return parent(0) - - res = [] - #Go through all the partition, coefficient pairs in the term p - for m, c in p: - res_t = parent.term(c, 0) - - for e,v in enumerate(m.to_exp()): - if v == 0: - continue - res_t = res_t * y_powers[v-1].stretch(e+1) - res.append(res_t) - - return parent.sum(res) - - def weighted_composition(self, y_species): - r""" - Return the composition of this cycle index series with the cycle - index series of the weighted species ``y_species``. - - Note that this is basically the same algorithm as composition - except we can not use the optimization that the powering of cycle - index series commutes with 'stretching'. - - EXAMPLES:: - - sage: E = species.SetSpecies(); C = species.CycleSpecies() - sage: E_cis = E.cycle_index_series() - sage: E_cis.weighted_composition(C).coefficients(4) - [p[], p[1], p[1, 1] + p[2], p[1, 1, 1] + p[2, 1] + p[3]] - sage: E(C).cycle_index_series().coefficients(4) - [p[], p[1], p[1, 1] + p[2], p[1, 1, 1] + p[2, 1] + p[3]] - """ - base_ring = self.base_ring() - y = y_species.cycle_index_series(base_ring) - assert y.coefficient(0) == 0 - return self._new(partial(self._weighted_compose_gen, y_species), lambda a,b:a*b, self, y) - - - def _weighted_compose_gen(self, y_species, ao): - r""" - Return an iterator for the composition of this cycle index series - and the cycle index series of the weighted species ``y_species``. - - EXAMPLES:: - - sage: E = species.SetSpecies(); C = species.CycleSpecies() - sage: E_cis = E.cycle_index_series() - sage: g = E_cis._weighted_compose_gen(C,0) - sage: [next(g) for i in range(4)] - [p[], p[1], p[1, 1] + p[2], p[1, 1, 1] + p[2, 1] + p[3]] - """ - parent = self.parent() - res = parent.sum_generator(self._weighted_compose_term(self.coefficient(i), y_species) - for i in _integers_from(0)) - - for i in _integers_from(0): - yield res.coefficient(i) - - def _weighted_compose_term(self, p, y_species): - r""" - Return the weighted composition of one term in ``self`` with ``y``. - - INPUT: - - - ``p`` -- a term in ``self`` - - ``y_species`` -- a species - - EXAMPLES:: - - sage: E = species.SetSpecies(); C = species.CycleSpecies() - sage: E_cis = E.cycle_index_series() - sage: p2 = E_cis.coefficient(2); p2 - 1/2*p[1, 1] + 1/2*p[2] - sage: E_cis._weighted_compose_term(p2, C).coefficients(4) - [0, 0, 1/2*p[1, 1] + 1/2*p[2], 1/2*p[1, 1, 1] + 1/2*p[2, 1]] - """ - parent = self.parent() - if p == 0: - return parent(0) - - base_ring = self.base_ring().base_ring() - - res = [] - #Go through all the partition, coefficient pairs in the term p - for m, c in p: - res_t = parent.term(c, 0) - - for e,v in enumerate(m.to_exp()): - if v == 0: - continue - res_t = res_t * (y_species.weighted(y_species._weight**(e+1)).cycle_index_series(base_ring)**v).stretch(e+1) - res.append(res_t) - - return parent.sum(res) - - def compositional_inverse(self): - r""" - Return the compositional inverse of ``self`` if possible. - - (Specifically, if ``self`` is of the form `0 + p_{1} + \cdots`.) - - The compositional inverse is the inverse with respect to - plethystic substitution. This is the operation on cycle index - series which corresponds to substitution, a.k.a. partitional - composition, on the level of species. See Section 2.2 of - [BLL]_ for a definition of this operation. - - EXAMPLES:: - - sage: Eplus = species.SetSpecies(min=1).cycle_index_series() - sage: Eplus(Eplus.compositional_inverse()).coefficients(8) - [0, p[1], 0, 0, 0, 0, 0, 0] - - TESTS:: - - sage: Eplus = species.SetSpecies(min=2).cycle_index_series() - sage: Eplus.compositional_inverse() - Traceback (most recent call last): - ... - ValueError: not an invertible series - - ALGORITHM: - - Let `F` be a species satisfying `F = 0 + X + F_2 + F_3 + \cdots` for - `X` the species of singletons. (Equivalently, `\lvert F[\varnothing] - \rvert = 0` and `\lvert F[\{1\}] \rvert = 1`.) Then there exists a - (virtual) species `G` satisfying `F \circ G = G \circ F = X`. - - It follows that `(F - X) \circ G = F \circ G - X \circ G = X - G`. - Rearranging, we obtain the recursive equation `G = X - (F - X) \circ G`, - which can be solved using iterative methods. - - .. WARNING:: - - This algorithm is functional but can be very slow. - Use with caution! - - .. SEEALSO:: - - The compositional inverse `\Omega` of the species `E_{+}` - of nonempty sets can be handled much more efficiently - using specialized methods. See - :func:`~sage.combinat.species.generating_series.LogarithmCycleIndexSeries` - - AUTHORS: - - - Andrew Gainer-Dewar - """ - cisr = self.parent() - sfa = cisr._base - - X = cisr([0, sfa([1]), 0]) - - if self.coefficients(2) != X.coefficients(2): - raise ValueError('not an invertible series') - - res = cisr() - res.define(X - (self - X).compose(res)) - - return res - - def derivative(self, order=1): - r""" - Return the species-theoretic `n`-th derivative of ``self``, - where `n` is ``order``. + Return the species-theoretic `n`-th derivative of ``self``. For a cycle index series `F (p_{1}, p_{2}, p_{3}, \ldots)`, its derivative is the cycle index series `F' = D_{p_{1}} F` (that is, @@ -1105,7 +404,7 @@ def derivative(self, order=1): The species `E` of sets satisfies the relationship `E' = E`:: sage: E = species.SetSpecies().cycle_index_series() - sage: E.coefficients(8) == E.derivative().coefficients(8) + sage: E[:8] == E.derivative()[:8] True The species `C` of cyclic orderings and the species `L` of linear @@ -1113,25 +412,10 @@ def derivative(self, order=1): sage: C = species.CycleSpecies().cycle_index_series() sage: L = species.LinearOrderSpecies().cycle_index_series() - sage: L.coefficients(8) == C.derivative().coefficients(8) + sage: L[:8] == C.derivative()[:8] True """ - # Make sure that order is integral - order = Integer(order) - - if order < 0: - raise ValueError("Order must be a non-negative integer") - - elif order == 0: - return self - - elif order == 1: - parent = self.parent() - derivative_term = lambda n: parent.term(self.coefficient(n+1).derivative_with_respect_to_p1(), n) - return parent.sum_generator(derivative_term(i) for i in _integers_from(0)) - - else: - return self.derivative(order-1) + return self.derivative_with_respect_to_p1(n=n) def pointing(self): r""" @@ -1151,42 +435,11 @@ def pointing(self): sage: E = species.SetSpecies().cycle_index_series() sage: X = species.SingletonSpecies().cycle_index_series() - sage: E.pointing().coefficients(8) == (X*E).coefficients(8) - True - - """ - p1 = self.base_ring()([1]) - X = self.parent()([0, p1, 0]) - - return X*self.derivative() - - def integral(self, *args): - r""" - Given a cycle index `G`, it is not in general possible to recover a - single cycle index `F` such that `F' = G` (even up to addition of a - constant term). - - More broadly, it may be the case that there are many non-isomorphic - species `S` such that `S' = T` for a given species `T`. - For example, the species `3 C_{3}` of 3-cycles from three distinct - classes and the species `X^{3}` of 3-sets are not isomorphic, but - `(3 C_{3})' = (X^{3})' = 3 X^{2}`. - - EXAMPLES:: - - sage: C3 = species.CycleSpecies(size=3).cycle_index_series() - sage: X = species.SingletonSpecies().cycle_index_series() - sage: (3*C3).derivative().coefficients(8) == (3*X^2).coefficients(8) - True - sage: (X^3).derivative().coefficients(8) == (3*X^2).coefficients(8) + sage: E.pointing()[:8] == (X*E)[:8] True - - .. WARNING:: - - This method has no implementation and exists only to prevent you from - doing something strange. Calling it raises a ``NotImplementedError``! """ - raise NotImplementedError + X = self.parent()([1], valuation=1) + return X * self.derivative_with_respect_to_p1() def exponential(self): r""" @@ -1206,12 +459,12 @@ def exponential(self): sage: BT = species.BinaryTreeSpecies().cycle_index_series() sage: BF = species.BinaryForestSpecies().cycle_index_series() - sage: BT.exponential().isotype_generating_series().coefficients(8) == BF.isotype_generating_series().coefficients(8) + sage: BT.exponential().isotype_generating_series()[:8] == BF.isotype_generating_series()[:8] True """ base_ring = self.parent().base_ring().base_ring() E = ExponentialCycleIndexSeries(base_ring) - return E.compose(self) + return E(self) def logarithm(self): r""" @@ -1233,45 +486,112 @@ def logarithm(self): sage: G = species.SimpleGraphSpecies().cycle_index_series() - 1 sage: from sage.combinat.species.generating_series import LogarithmCycleIndexSeries - sage: CG = LogarithmCycleIndexSeries().compose(G) - sage: CG.isotype_generating_series().coefficients(8) + sage: CG = LogarithmCycleIndexSeries()(G) + sage: CG.isotype_generating_series()[0:8] [0, 1, 1, 2, 6, 21, 112, 853] """ base_ring = self.parent().base_ring().base_ring() Omega = LogarithmCycleIndexSeries(base_ring) - return Omega.compose(self) + return Omega(self) -@cached_function -def _exp_term(n, R = RationalField()): - """ - Compute the order-n term of the cycle index series of the species `E` of sets. + +class CycleIndexSeriesRing(LazySymmetricFunctions): + r""" + Return the ring of cycle index series over ``R``. + + This is the ring of formal power series `\Lambda[x]`, where + `\Lambda` is the ring of symmetric functions over ``R`` in the + `p`-basis. Its purpose is to house the cycle index series of + species (in a somewhat nonstandard notation tailored to Sage): + If `F` is a species, then the *cycle index series* of `F` is + defined to be the formal power series + + .. MATH:: + + \sum_{n \geq 0} \frac{1}{n!} (\sum_{\sigma \in S_n} + \operatorname{fix} F[\sigma] + \prod_{z \text{ is a cycle of } \sigma} + p_{\text{length of } z}) x^n + \in \Lambda_\QQ [x], + + where `\operatorname{fix} F[\sigma]` denotes the number of + fixed points of the permutation `F[\sigma]` of `F[n]`. We + notice that this power series is "equigraded" (meaning that + its `x^n`-coefficient is homogeneous of degree `n`). A more + standard convention in combinatorics would be to use + `x_i` instead of `p_i`, and drop the `x` (that is, evaluate + the above power series at `x = 1`); but this would be more + difficult to implement in Sage, as it would be an element + of a power series ring in infinitely many variables. + + Note that it is just a :class:`LazyPowerSeriesRing` (whose base + ring is `\Lambda`) whose elements have some extra methods. EXAMPLES:: - sage: from sage.combinat.species.generating_series import _exp_term - sage: [_exp_term(i) for i in range(4)] - [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], 1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3]] + sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing + sage: R = CycleIndexSeriesRing(QQ); R + Cycle Index Series Ring over Rational Field + sage: p = SymmetricFunctions(QQ).p() + sage: R(lambda n: p[n]) + p[] + p[1] + p[2] + p[3] + p[4] + p[5] + p[6] + O^7 + + TESTS: + + We test to make sure that caching works:: + + sage: R is CycleIndexSeriesRing(QQ) + True """ - p = SymmetricFunctions(R).power() - return sum(p(part) / part.aut() for part in Partitions(n)) + Element = CycleIndexSeries + + def __init__(self, base_ring, sparse=True): + """ + Initialize ``self``. + + TESTS:: + sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing + sage: CycleIndexSeriesRing.options.halting_precision(12) + sage: R = CycleIndexSeriesRing(QQ) + sage: TestSuite(R).run() + + sage: CycleIndexSeriesRing.options._reset() # reset options + """ + p = SymmetricFunctions(base_ring).power() + super().__init__(p) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: -def _exp_gen(R = RationalField()): + sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing + sage: CycleIndexSeriesRing(QQ) + Cycle Index Series Ring over Rational Field + """ + return "Cycle Index Series Ring over %s" % self.base_ring() + + +@cached_function +def _exp_term(n, R=QQ): r""" - Produce a generator which yields the terms of the cycle index - series of the species `E` of sets. + Compute the order-``n`` term of the cycle index series of the species + `E` of sets. EXAMPLES:: - sage: from sage.combinat.species.generating_series import _exp_gen - sage: g = _exp_gen() - sage: [next(g) for i in range(4)] + sage: from sage.combinat.species.generating_series import _exp_term + sage: [_exp_term(i) for i in range(4)] [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], 1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3]] """ - return (_exp_term(i, R) for i in _integers_from(0)) + p = SymmetricFunctions(R).power() + return sum(p(part) / part.aut() for part in Partitions(n)) + @cached_function -def ExponentialCycleIndexSeries(R = RationalField()): +def ExponentialCycleIndexSeries(R=QQ): r""" Return the cycle index series of the species `E` of sets. @@ -1285,20 +605,21 @@ def ExponentialCycleIndexSeries(R = RationalField()): EXAMPLES:: sage: from sage.combinat.species.generating_series import ExponentialCycleIndexSeries - sage: ExponentialCycleIndexSeries().coefficients(5) + sage: ExponentialCycleIndexSeries()[:5] [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], 1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3], 1/24*p[1, 1, 1, 1] + 1/4*p[2, 1, 1] + 1/8*p[2, 2] + 1/3*p[3, 1] + 1/4*p[4]] """ CIS = CycleIndexSeriesRing(R) - return CIS(_exp_gen(R)) + return CIS(_exp_term) @cached_function -def _cl_term(n, R = RationalField()): +def _cl_term(n, R=QQ): r""" - Compute the order-n term of the cycle index series of the virtual species - `\Omega`, the compositional inverse of the species `E^{+}` of nonempty sets. + Compute the order-``n`` term of the cycle index series of + the virtual species `\Omega`, the compositional inverse of + the species `E^{+}` of nonempty sets. EXAMPLES:: @@ -1318,25 +639,8 @@ def _cl_term(n, R = RationalField()): return res - -def _cl_gen (R = RationalField()): - r""" - Produce a generator which yields the terms of the cycle index series - of the virtual species `\Omega`, the compositional inverse of the - species `E^{+}` of nonempty sets. - - EXAMPLES:: - - sage: from sage.combinat.species.generating_series import _cl_gen - sage: g = _cl_gen() - sage: [next(g) for i in range(4)] - [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]] - """ - return (_cl_term(i, R) for i in _integers_from(0)) - - @cached_function -def LogarithmCycleIndexSeries(R = RationalField()): +def LogarithmCycleIndexSeries(R=QQ): r""" Return the cycle index series of the virtual species `\Omega`, the compositional inverse of the species `E^{+}` of nonempty sets. @@ -1351,7 +655,7 @@ def LogarithmCycleIndexSeries(R = RationalField()): its cycle index has negative coefficients:: sage: from sage.combinat.species.generating_series import LogarithmCycleIndexSeries - sage: LogarithmCycleIndexSeries().coefficients(4) + sage: LogarithmCycleIndexSeries()[0:4] [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]] Its defining property is that `\Omega \circ E^{+} = E^{+} \circ \Omega = X` @@ -1359,8 +663,8 @@ def LogarithmCycleIndexSeries(R = RationalField()): multiplicative identity `X`):: sage: Eplus = sage.combinat.species.set_species.SetSpecies(min=1).cycle_index_series() - sage: LogarithmCycleIndexSeries().compose(Eplus).coefficients(4) + sage: LogarithmCycleIndexSeries()(Eplus)[0:4] [0, p[1], 0, 0] """ CIS = CycleIndexSeriesRing(R) - return CIS(_cl_gen(R)) + return CIS(_cl_term) diff --git a/src/sage/combinat/species/library.py b/src/sage/combinat/species/library.py index c107edbfa33..d4235273a9f 100644 --- a/src/sage/combinat/species/library.py +++ b/src/sage/combinat/species/library.py @@ -1,7 +1,7 @@ """ Examples of Combinatorial Species """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Mike Hansen , # # Distributed under the terms of the GNU General Public License (GPL) @@ -13,8 +13,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from .set_species import SetSpecies from .partition_species import PartitionSpecies @@ -32,23 +32,24 @@ from sage.misc.cachefunc import cached_function + @cached_function def SimpleGraphSpecies(): """ - Returns the species of simple graphs. + Return the species of simple graphs. EXAMPLES:: sage: S = species.SimpleGraphSpecies() sage: S.generating_series().counts(10) [1, 1, 2, 8, 64, 1024, 32768, 2097152, 268435456, 68719476736] - sage: S.cycle_index_series().coefficients(5) + sage: S.cycle_index_series()[:5] [p[], p[1], p[1, 1] + p[2], 4/3*p[1, 1, 1] + 2*p[2, 1] + 2/3*p[3], 8/3*p[1, 1, 1, 1] + 4*p[2, 1, 1] + 2*p[2, 2] + 4/3*p[3, 1] + p[4]] - sage: S.isotype_generating_series().coefficients(6) + sage: S.isotype_generating_series()[:6] [1, 1, 2, 4, 11, 34] TESTS:: @@ -66,18 +67,17 @@ def SimpleGraphSpecies(): E = SetSpecies() E2 = SetSpecies(size=2) WP = SubsetSpecies() - P2 = E2*E + P2 = E2 * E return WP.functorial_composition(P2) @cached_function def BinaryTreeSpecies(): r""" - Return the species of binary trees on n leaves. + Return the species of binary trees on `n` leaves. - The species of - binary trees B is defined by B = X + B\*B where X is the singleton - species. + The species of binary trees `B` is defined by `B = X + B \cdot B`, + where `X` is the singleton species. EXAMPLES:: @@ -103,16 +103,18 @@ def BinaryTreeSpecies(): sage: oeis(seq)[0] # optional -- internet A000108: Catalan numbers: ... """ - B = CombinatorialSpecies() + B = CombinatorialSpecies(min=1) X = SingletonSpecies() - B.define(X+B*B) + B.define(X + B * B) return B + @cached_function def BinaryForestSpecies(): """ - Returns the species of binary forests. Binary forests are defined - as sets of binary trees. + Return the species of binary forests. + + Binary forests are defined as sets of binary trees. EXAMPLES:: @@ -121,7 +123,7 @@ def BinaryForestSpecies(): [1, 1, 3, 19, 193, 2721, 49171, 1084483, 28245729, 848456353] sage: F.isotype_generating_series().counts(10) [1, 1, 2, 4, 10, 26, 77, 235, 758, 2504] - sage: F.cycle_index_series().coefficients(7) + sage: F.cycle_index_series()[:7] [p[], p[1], 3/2*p[1, 1] + 1/2*p[2], @@ -140,3 +142,6 @@ def BinaryForestSpecies(): S = SetSpecies() F = S(B) return F + + +del cached_function # so it doesn't get picked up by tab completion diff --git a/src/sage/combinat/species/linear_order_species.py b/src/sage/combinat/species/linear_order_species.py index 98c4f62eb44..bd4b4a36f7d 100644 --- a/src/sage/combinat/species/linear_order_species.py +++ b/src/sage/combinat/species/linear_order_species.py @@ -17,7 +17,6 @@ #***************************************************************************** from .species import GenericCombinatorialSpecies from .structure import GenericSpeciesStructure -from .generating_series import _integers_from from sage.structure.unique_representation import UniqueRepresentation from sage.combinat.species.misc import accept_size @@ -87,7 +86,7 @@ def __init__(self, min=None, max=None, weight=None): EXAMPLES:: sage: L = species.LinearOrderSpecies() - sage: L.generating_series().coefficients(5) + sage: L.generating_series()[0:5] [1, 1, 1, 1, 1] sage: L = species.LinearOrderSpecies() @@ -123,7 +122,7 @@ def _isotypes(self, structure_class, labels): """ yield structure_class(self, labels, range(1, len(labels)+1)) - def _gs_list(self, base_ring): + def _gs_list(self, base_ring, n): r""" The generating series for the species of linear orders is `\frac{1}{1-x}`. @@ -132,12 +131,12 @@ def _gs_list(self, base_ring): sage: L = species.LinearOrderSpecies() sage: g = L.generating_series() - sage: g.coefficients(10) + sage: g[0:10] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] """ - return [base_ring(1)] + return base_ring.one() - def _itgs_list(self, base_ring): + def _itgs_list(self, base_ring, n): r""" The isomorphism type generating series is given by `\frac{1}{1-x}`. @@ -146,25 +145,24 @@ def _itgs_list(self, base_ring): sage: L = species.LinearOrderSpecies() sage: g = L.isotype_generating_series() - sage: g.coefficients(10) + sage: g[0:10] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] """ - return [base_ring(1)] + return base_ring.one() - def _cis_iterator(self, base_ring): + def _cis_callable(self, base_ring, n): """ EXAMPLES:: sage: L = species.LinearOrderSpecies() sage: g = L.cycle_index_series() - sage: g.coefficients(5) + sage: g[0:5] [p[], p[1], p[1, 1], p[1, 1, 1], p[1, 1, 1, 1]] """ from sage.combinat.sf.sf import SymmetricFunctions p = SymmetricFunctions(base_ring).power() - for n in _integers_from(0): - yield p([1]*n) + return p([1]*n) #Backward compatibility LinearOrderSpecies_class = LinearOrderSpecies diff --git a/src/sage/combinat/species/partition_species.py b/src/sage/combinat/species/partition_species.py index 7ba6ea84a13..cc8d1818821 100644 --- a/src/sage/combinat/species/partition_species.py +++ b/src/sage/combinat/species/partition_species.py @@ -17,7 +17,6 @@ #***************************************************************************** from .species import GenericCombinatorialSpecies -from .generating_series import _integers_from from sage.arith.misc import factorial from .subset_species import SubsetSpeciesStructure from .set_species import SetSpecies @@ -152,9 +151,9 @@ def __init__(self, min=None, max=None, weight=None): EXAMPLES:: sage: P = species.PartitionSpecies() - sage: P.generating_series().coefficients(5) + sage: P.generating_series()[0:5] [1, 1, 1, 5/6, 5/8] - sage: P.isotype_generating_series().coefficients(5) + sage: P.isotype_generating_series()[0:5] [1, 1, 2, 3, 5] sage: P = species.PartitionSpecies() @@ -233,20 +232,19 @@ def _canonical_rep_from_partition(self, structure_class, labels, p): breaks = [sum(p[:i]) for i in range(len(p) + 1)] return structure_class(self, labels, [list(range(breaks[i]+1, breaks[i+1]+1)) for i in range(len(p))]) - def _gs_iterator(self, base_ring): + def _gs_callable(self, base_ring, n): r""" EXAMPLES:: sage: P = species.PartitionSpecies() sage: g = P.generating_series() - sage: g.coefficients(5) + sage: [g.coefficient(i) for i in range(5)] [1, 1, 1, 5/6, 5/8] """ from sage.combinat.combinat import bell_number - for n in _integers_from(0): - yield self._weight * base_ring(bell_number(n) / factorial(n)) + return self._weight * base_ring(bell_number(n) / factorial(n)) - def _itgs_iterator(self, base_ring): + def _itgs_callable(self, base_ring, n): r""" The isomorphism type generating series is given by `\frac{1}{1-x}`. @@ -255,12 +253,11 @@ def _itgs_iterator(self, base_ring): sage: P = species.PartitionSpecies() sage: g = P.isotype_generating_series() - sage: g.coefficients(10) + sage: [g.coefficient(i) for i in range(10)] [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ from sage.combinat.partition import number_of_partitions - for n in _integers_from(0): - yield self._weight*base_ring(number_of_partitions(n)) + return self._weight*base_ring(number_of_partitions(n)) def _cis(self, series_ring, base_ring): r""" @@ -276,7 +273,7 @@ def _cis(self, series_ring, base_ring): sage: P = species.PartitionSpecies() sage: g = P.cycle_index_series() - sage: g.coefficients(5) + sage: g[0:5] [p[], p[1], p[1, 1] + p[2], @@ -284,7 +281,7 @@ def _cis(self, series_ring, base_ring): 5/8*p[1, 1, 1, 1] + 7/4*p[2, 1, 1] + 7/8*p[2, 2] + p[3, 1] + 3/4*p[4]] """ ciset = SetSpecies().cycle_index_series(base_ring) - res = ciset.composition(ciset - 1) + res = ciset(ciset - 1) if self.is_weighted(): res *= self._weight return res diff --git a/src/sage/combinat/species/permutation_species.py b/src/sage/combinat/species/permutation_species.py index d8ae5c216ea..a1a4b362f8e 100644 --- a/src/sage/combinat/species/permutation_species.py +++ b/src/sage/combinat/species/permutation_species.py @@ -18,9 +18,7 @@ from .species import GenericCombinatorialSpecies from .structure import GenericSpeciesStructure -from .generating_series import _integers_from from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.integer_ring import ZZ from sage.combinat.permutation import Permutation, Permutations from sage.combinat.species.misc import accept_size @@ -123,13 +121,13 @@ def __init__(self, min=None, max=None, weight=None): EXAMPLES:: sage: P = species.PermutationSpecies() - sage: P.generating_series().coefficients(5) + sage: P.generating_series()[0:5] [1, 1, 1, 1, 1] - sage: P.isotype_generating_series().coefficients(5) + sage: P.isotype_generating_series()[0:5] [1, 1, 2, 3, 5] sage: P = species.PermutationSpecies() - sage: c = P.generating_series().coefficients(3) + sage: c = P.generating_series()[0:3] sage: P._check() True sage: P == loads(dumps(P)) @@ -186,7 +184,7 @@ def _canonical_rep_from_partition(self, structure_class, labels, p): return structure_class(self, labels, perm) - def _gs_list(self, base_ring): + def _gs_list(self, base_ring, n): r""" The generating series for the species of linear orders is `\frac{1}{1-x}`. @@ -195,13 +193,13 @@ def _gs_list(self, base_ring): sage: P = species.PermutationSpecies() sage: g = P.generating_series() - sage: g.coefficients(10) + sage: g[0:10] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] """ - return [base_ring(1)] + return base_ring.one() - def _itgs_iterator(self, base_ring): + def _itgs_callable(self, base_ring, n): r""" The isomorphism type generating series is given by `\frac{1}{1-x}`. @@ -210,12 +208,11 @@ def _itgs_iterator(self, base_ring): sage: P = species.PermutationSpecies() sage: g = P.isotype_generating_series() - sage: g.coefficients(10) + sage: [g.coefficient(i) for i in range(10)] [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] """ from sage.combinat.partition import number_of_partitions - for n in _integers_from(0): - yield base_ring(number_of_partitions(n)) + return base_ring(number_of_partitions(n)) def _cis(self, series_ring, base_ring): @@ -226,43 +223,45 @@ def _cis(self, series_ring, base_ring): \prod{n=1}^\infty \frac{1}{1-x_n}. - - EXAMPLES:: sage: P = species.PermutationSpecies() sage: g = P.cycle_index_series() - sage: g.coefficients(5) + sage: g[0:5] [p[], p[1], p[1, 1] + p[2], p[1, 1, 1] + p[2, 1] + p[3], p[1, 1, 1, 1] + p[2, 1, 1] + p[2, 2] + p[3, 1] + p[4]] """ + from sage.combinat.sf.sf import SymmetricFunctions + from sage.combinat.partition import Partitions + p = SymmetricFunctions(base_ring).p() CIS = series_ring - return CIS.product_generator( CIS(self._cis_gen(base_ring, i)) for i in _integers_from(ZZ(1)) ) + return CIS(lambda n: sum(p(la) for la in Partitions(n))) - def _cis_gen(self, base_ring, n): + def _cis_gen(self, base_ring, m, n): """ EXAMPLES:: sage: P = species.PermutationSpecies() - sage: g = P._cis_gen(QQ, 2) - sage: [next(g) for i in range(10)] + sage: [P._cis_gen(QQ, 2, i) for i in range(10)] [p[], 0, p[2], 0, p[2, 2], 0, p[2, 2, 2], 0, p[2, 2, 2, 2], 0] """ from sage.combinat.sf.sf import SymmetricFunctions p = SymmetricFunctions(base_ring).power() - pn = p([n]) - - n = n - 1 - yield p(1) - - for k in _integers_from(1): - for i in range(n): - yield base_ring(0) - yield pn**k + pn = p([m]) + + if not n: + return p(1) + if m == 1: + if n % 2: + return base_ring.zero() + return pn**(n//2) + elif n % m: + return base_ring.zero() + return pn**(n//m) #Backward compatibility PermutationSpecies_class = PermutationSpecies diff --git a/src/sage/combinat/species/product_species.py b/src/sage/combinat/species/product_species.py index 0f7496a7dca..74004849b79 100644 --- a/src/sage/combinat/species/product_species.py +++ b/src/sage/combinat/species/product_species.py @@ -206,7 +206,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: X = species.SingletonSpecies() sage: A = X*X - sage: A.generating_series().coefficients(4) + sage: A.generating_series()[0:4] [0, 0, 1, 0] sage: P = species.PermutationSpecies() @@ -324,7 +324,7 @@ def _gs(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P * P - sage: F.generating_series().coefficients(5) + sage: F.generating_series()[0:5] [1, 2, 3, 4, 5] """ res = (self.left_factor().generating_series(base_ring) * @@ -339,7 +339,7 @@ def _itgs(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P * P - sage: F.isotype_generating_series().coefficients(5) + sage: F.isotype_generating_series()[0:5] [1, 2, 5, 10, 20] """ res = (self.left_factor().isotype_generating_series(base_ring) * @@ -354,7 +354,7 @@ def _cis(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P * P - sage: F.cycle_index_series().coefficients(5) + sage: F.cycle_index_series()[0:5] [p[], 2*p[1], 3*p[1, 1] + 2*p[2], diff --git a/src/sage/combinat/species/recursive_species.py b/src/sage/combinat/species/recursive_species.py index d6023264808..2e3e8cd895c 100644 --- a/src/sage/combinat/species/recursive_species.py +++ b/src/sage/combinat/species/recursive_species.py @@ -25,7 +25,7 @@ class CombinatorialSpeciesStructure(SpeciesStructureWrapper): class CombinatorialSpecies(GenericCombinatorialSpecies): - def __init__(self): + def __init__(self, min=None): """ EXAMPLES:: @@ -39,19 +39,16 @@ def __init__(self): sage: E = species.EmptySetSpecies() sage: L = CombinatorialSpecies() sage: L.define(E+X*L) - sage: L.generating_series().coefficients(4) + sage: L.generating_series()[0:4] [1, 1, 1, 1] sage: LL = loads(dumps(L)) - sage: LL.generating_series().coefficients(4) + sage: LL.generating_series()[0:4] [1, 1, 1, 1] """ self._generating_series = {} self._isotype_generating_series = {} self._cycle_index_series = {} - self._min = None - self._max = None - self._weight = 1 - GenericCombinatorialSpecies.__init__(self, min=None, max=None, weight=None) + GenericCombinatorialSpecies.__init__(self, min=min, max=None, weight=None) _default_structure_class = CombinatorialSpeciesStructure @@ -233,10 +230,10 @@ def _gs(self, series_ring, base_ring): sage: F = CombinatorialSpecies() sage: F.generating_series() - Uninitialized lazy power series + Uninitialized Lazy Laurent Series """ if base_ring not in self._generating_series: - self._generating_series[base_ring] = series_ring() + self._generating_series[base_ring] = series_ring.undefined(valuation=(0 if self._min is None else self._min)) res = self._generating_series[base_ring] if hasattr(self, "_reference") and not hasattr(res, "_reference"): @@ -250,10 +247,10 @@ def _itgs(self, series_ring, base_ring): sage: F = CombinatorialSpecies() sage: F.isotype_generating_series() - Uninitialized lazy power series + Uninitialized Lazy Laurent Series """ if base_ring not in self._isotype_generating_series: - self._isotype_generating_series[base_ring] = series_ring() + self._isotype_generating_series[base_ring] = series_ring.undefined(valuation=(0 if self._min is None else self._min)) res = self._isotype_generating_series[base_ring] if hasattr(self, "_reference") and not hasattr(res, "_reference"): @@ -267,10 +264,10 @@ def _cis(self, series_ring, base_ring): sage: F = CombinatorialSpecies() sage: F.cycle_index_series() - Uninitialized lazy power series + Uninitialized Lazy Laurent Series """ if base_ring not in self._cycle_index_series: - self._cycle_index_series[base_ring] = series_ring() + self._cycle_index_series[base_ring] = series_ring.undefined(valuation=(0 if self._min is None else self._min)) res = self._cycle_index_series[base_ring] if hasattr(self, "_reference") and not hasattr(res, "_reference"): @@ -325,7 +322,7 @@ def define(self, x): sage: E = species.EmptySetSpecies() sage: L = CombinatorialSpecies() sage: L.define(E+X*L) - sage: L.generating_series().coefficients(4) + sage: L.generating_series()[0:4] [1, 1, 1, 1] sage: L.structures([1,2,3]).cardinality() 6 @@ -340,7 +337,7 @@ def define(self, x): :: sage: L = species.LinearOrderSpecies() - sage: L.generating_series().coefficients(4) + sage: L.generating_series()[0:4] [1, 1, 1, 1] sage: L.structures([1,2,3]).cardinality() 6 @@ -351,28 +348,28 @@ def define(self, x): sage: A = CombinatorialSpecies() sage: A.define(E+X*A*A) - sage: A.generating_series().coefficients(6) + sage: A.generating_series()[0:6] [1, 1, 2, 5, 14, 42] sage: A.generating_series().counts(6) [1, 1, 4, 30, 336, 5040] sage: len(A.structures([1,2,3,4]).list()) 336 - sage: A.isotype_generating_series().coefficients(6) + sage: A.isotype_generating_series()[0:6] [1, 1, 2, 5, 14, 42] sage: len(A.isotypes([1,2,3,4]).list()) 14 :: - sage: A = CombinatorialSpecies() + sage: A = CombinatorialSpecies(min=1) sage: A.define(X+A*A) - sage: A.generating_series().coefficients(6) + sage: A.generating_series()[0:6] [0, 1, 1, 2, 5, 14] sage: A.generating_series().counts(6) [0, 1, 2, 12, 120, 1680] sage: len(A.structures([1,2,3]).list()) 12 - sage: A.isotype_generating_series().coefficients(6) + sage: A.isotype_generating_series()[0:6] [0, 1, 1, 2, 5, 14] sage: len(A.isotypes([1,2,3,4]).list()) 5 @@ -381,19 +378,17 @@ def define(self, x): sage: X2 = X*X sage: X5 = X2*X2*X - sage: A = CombinatorialSpecies() - sage: B = CombinatorialSpecies() - sage: C = CombinatorialSpecies() + sage: A = CombinatorialSpecies(min=1) + sage: B = CombinatorialSpecies(min=1) + sage: C = CombinatorialSpecies(min=1) sage: A.define(X5+B*B) sage: B.define(X5+C*C) sage: C.define(X2+C*C+A*A) - sage: A.generating_series().coefficients(Integer(10)) - [0, 0, 0, 0, 0, 1, 0, 0, 1, 2] - sage: A.generating_series().coefficients(15) + sage: A.generating_series()[0:15] [0, 0, 0, 0, 0, 1, 0, 0, 1, 2, 5, 4, 14, 10, 48] - sage: B.generating_series().coefficients(15) + sage: B.generating_series()[0:15] [0, 0, 0, 0, 1, 1, 2, 0, 5, 0, 14, 0, 44, 0, 138] - sage: C.generating_series().coefficients(15) + sage: C.generating_series()[0:15] [0, 0, 1, 0, 1, 0, 2, 0, 5, 0, 15, 0, 44, 2, 142] :: @@ -402,9 +397,9 @@ def define(self, x): sage: F.define(E+X+(X*F+X*X*F)) sage: F.generating_series().counts(10) [1, 2, 6, 30, 192, 1560, 15120, 171360, 2217600, 32296320] - sage: F.generating_series().coefficients(10) + sage: F.generating_series()[0:10] [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] - sage: F.isotype_generating_series().coefficients(10) + sage: F.isotype_generating_series()[0:10] [1, 2, 3, 5, 8, 13, 21, 34, 55, 89] """ if not isinstance(x, GenericCombinatorialSpecies): diff --git a/src/sage/combinat/species/series.py b/src/sage/combinat/species/series.py deleted file mode 100644 index 37e3e6e19ed..00000000000 --- a/src/sage/combinat/species/series.py +++ /dev/null @@ -1,1832 +0,0 @@ -""" -Lazy Power Series - -This file provides an implementation of lazy univariate power -series, which uses the stream class for its internal data -structure. The lazy power series keep track of their approximate -order as much as possible without forcing the computation of any -additional coefficients. This is required for recursively defined -power series. - -This code is based on the work of Ralf Hemmecke and Martin Rubey's -Aldor-Combinat, which can be found at -http://www.risc.uni-linz.ac.at/people/hemmecke/aldor/combinat/index.html. -In particular, the relevant section for this file can be found at -http://www.risc.uni-linz.ac.at/people/hemmecke/AldorCombinat/combinatse9.html. -""" -# **************************************************************************** -# Copyright (C) 2008 Mike Hansen , -# -# Distributed under the terms of the GNU General Public License (GPL) -# -# This code is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# The full text of the GPL is available at: -# -# https://www.gnu.org/licenses/ -# **************************************************************************** - -import builtins - -from collections.abc import Iterable -from .stream import Stream, Stream_class -from .series_order import bounded_decrement, increment, inf, unk -from sage.rings.integer import Integer -from sage.misc.misc_c import prod -from functools import partial -from sage.misc.misc import is_iterator -from sage.misc.repr import repr_lincomb -from sage.misc.cachefunc import cached_method - -from sage.rings.ring import Algebra -from sage.structure.parent import Parent -from sage.categories.all import Rings -from sage.structure.element import Element, parent, AlgebraElement - - -class LazyPowerSeriesRing(Algebra): - def __init__(self, R, names=None, element_class=None): - """ - TESTS:: - - sage: from sage.combinat.species.series import LazyPowerSeriesRing - sage: L = LazyPowerSeriesRing(QQ) - - Equality testing is undecidable in general, and not much - efforts are done at this stage to implement equality when - possible. Hence the failing tests below:: - - sage: TestSuite(L).run() - Failure in ... - The following tests failed: _test_additive_associativity, _test_associativity, _test_distributivity, _test_elements, _test_one, _test_prod, _test_zero - - :: - - sage: LazyPowerSeriesRing(QQ, 'z').gen() - z - sage: LazyPowerSeriesRing(QQ, ['z']).gen() - z - sage: LazyPowerSeriesRing(QQ, ['x', 'z']) - Traceback (most recent call last): - ... - NotImplementedError: only univariate lazy power series rings are supported - """ - #Make sure R is a ring with unit element - if R not in Rings(): - raise TypeError("argument R must be a ring") - - #Take care of the names - if names is None: - names = 'x' - elif isinstance(names, (list, tuple)): - if len(names) != 1: - raise NotImplementedError( - 'only univariate lazy power series rings are supported') - names = names[0] - else: - names = str(names) - - self._element_class = element_class if element_class is not None else LazyPowerSeries - self._order = None - self._name = names - self._zero_base_ring = R.zero() - Parent.__init__(self, R, category=Rings()) - - def ngens(self): - """ - EXAMPLES:: - - sage: LazyPowerSeriesRing(QQ).ngens() - 1 - """ - return 1 - - def __repr__(self): - """ - EXAMPLES:: - - sage: LazyPowerSeriesRing(QQ) - Lazy Power Series Ring over Rational Field - """ - return "Lazy Power Series Ring over %s" % self.base_ring() - - def __eq__(self, x): - """ - Check whether ``self`` is equal to ``x``. - - EXAMPLES:: - - sage: LQ = LazyPowerSeriesRing(QQ) - sage: LZ = LazyPowerSeriesRing(ZZ) - sage: LQ == LQ - True - sage: LZ == LQ - False - """ - if not isinstance(x, LazyPowerSeriesRing): - return False - return self.base_ring() == x.base_ring() - - def __ne__(self, other): - """ - Check whether ``self`` is not equal to ``other``. - - EXAMPLES:: - - sage: LQ = LazyPowerSeriesRing(QQ) - sage: LZ = LazyPowerSeriesRing(ZZ) - sage: LQ != LQ - False - sage: LZ != LQ - True - """ - return not (self == other) - - def __hash__(self): - """ - Return the hash of ``self``. - - EXAMPLES:: - - sage: LQ = LazyPowerSeriesRing(QQ) - sage: LZ = LazyPowerSeriesRing(ZZ) - sage: hash(LQ) == hash(LQ) - True - sage: hash(LZ) == hash(LQ) - False - """ - # with a random number, so that the hash is not that of the base ring - return hash((16079305, self.base_ring())) - - def _coerce_impl(self, x): - """ - EXAMPLES:: - - sage: L1 = LazyPowerSeriesRing(QQ) - sage: L2 = LazyPowerSeriesRing(RR) - sage: L2.has_coerce_map_from(L1) - True - sage: L1.has_coerce_map_from(L2) - False - - :: - - sage: a = L1([1]) + L2([1]) - sage: a.coefficients(3) - [2.00000000000000, 2.00000000000000, 2.00000000000000] - """ - return self(x) - - def __call__(self, x=None, order=unk): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: L = LazyPowerSeriesRing(QQ) - sage: L() - Uninitialized lazy power series - sage: L(1) - 1 - sage: L(ZZ).coefficients(10) - [0, 1, -1, 2, -2, 3, -3, 4, -4, 5] - sage: L(iter(ZZ)).coefficients(10) - [0, 1, -1, 2, -2, 3, -3, 4, -4, 5] - sage: L(Stream(ZZ)).coefficients(10) - [0, 1, -1, 2, -2, 3, -3, 4, -4, 5] - - :: - - sage: a = L([1,2,3]) - sage: a.coefficients(3) - [1, 2, 3] - sage: L(a) is a - True - sage: L_RR = LazyPowerSeriesRing(RR) - sage: b = L_RR(a) - sage: b.coefficients(3) - [1.00000000000000, 2.00000000000000, 3.00000000000000] - sage: L(b) - Traceback (most recent call last): - ... - TypeError: do not know how to coerce ... into self - - TESTS:: - - sage: L(pi) - Traceback (most recent call last): - ... - TypeError: do not know how to coerce pi into self - """ - cls = self._element_class - BR = self.base_ring() - - if x is None: - res = cls(self, stream=None, order=unk, aorder=unk, - aorder_changed=True, is_initialized=False) - res.compute_aorder = uninitialized - return res - - if isinstance(x, LazyPowerSeries): - x_parent = x.parent() - if x_parent.__class__ != self.__class__: - raise ValueError - - if x_parent.base_ring() == self.base_ring(): - return x - else: - if self.base_ring().has_coerce_map_from(x_parent.base_ring()): - return x._new(partial(x._change_ring_gen, self.base_ring()), lambda ao: ao, x, parent=self) - - - if BR.has_coerce_map_from(parent(x)): - x = BR(x) - return self.term(x, 0) - - if isinstance(x, Iterable) and not isinstance(x, Stream_class): - x = iter(x) - - if is_iterator(x): - x = Stream(x) - - if isinstance(x, Stream_class): - aorder = order if order != unk else 0 - return cls(self, stream=x, order=order, aorder=aorder, - aorder_changed=False, is_initialized=True) - elif not isinstance(x, Element): - x = BR(x) - return self.term(x, 0) - - raise TypeError("do not know how to coerce %s into self" % x) - - @cached_method - def zero(self): - """ - Return the zero power series. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: L.zero() - 0 - """ - return self.term(self._zero_base_ring, 0) - - def identity_element(self): - """ - Return the one power series. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: L.identity_element() - 1 - """ - return self(self.base_ring()(1)) - - def gen(self, i=0): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: L.gen().coefficients(5) - [0, 1, 0, 0, 0] - """ - res = self._new_initial(1, Stream([0,1,0])) - res._name = self._name - return res - - def term(self, r, n): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: L.term(0,0) - 0 - sage: L.term(3,2).coefficients(5) - [0, 0, 3, 0, 0] - """ - if n < 0: - raise ValueError("n must be non-negative") - BR = self.base_ring() - if r == 0: - res = self._new_initial(inf, Stream([0])) - res._name = "0" - else: - zero = BR(0) - s = [zero]*n+[BR(r),zero] - res = self._new_initial(n, Stream(s)) - - if n == 0: - res._name = repr(r) - elif n == 1: - res._name = repr(r) + "*" + self._name - else: - res._name = "%s*%s^%s" % (repr(r), self._name, n) - - return res - - def _new_initial(self, order, stream): - """ - Return a new power series with specified order. - - INPUT: - - - - ``order`` - a non-negative integer - - - ``stream`` - a Stream object - - - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: L = LazyPowerSeriesRing(QQ) - sage: L._new_initial(0, Stream([1,2,3,0])).coefficients(5) - [1, 2, 3, 0, 0] - """ - return self._element_class(self, stream=stream, order=order, aorder=order, - aorder_changed=False, is_initialized=True) - - - def _sum_gen(self, series_list): - """ - Return a generator for the coefficients of the sum of the lazy - power series in series_list. - - INPUT: - - - - ``series_list`` - a list of lazy power series - - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: series_list = [ L([1]), L([0,1]), L([0,0,1]) ] - sage: g = L._sum_gen(series_list) - sage: [next(g) for i in range(5)] - [1, 2, 3, 3, 3] - """ - last_index = len(series_list) - 1 - assert last_index >= 0 - n = 0 - while True: - r = sum( [f.coefficient(n) for f in series_list] ) - yield r - n += 1 - - def sum(self, a): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: l = [L(ZZ)]*3 - sage: L.sum(l).coefficients(10) - [0, 3, -3, 6, -6, 9, -9, 12, -12, 15] - """ - return self( self._sum_gen(a) ) - - #Potentially infinite sum - def _sum_generator_gen(self, g): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: s = L([1]) - sage: def f(): - ....: while True: - ....: yield s - sage: g = L._sum_generator_gen(f()) - sage: [next(g) for i in range(10)] - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - """ - s = Stream(g) - n = 0 - while True: - r = s[n].coefficient(n) - for i in range(len(s)-1): - r += s[i].coefficient(n) - yield r - n += 1 - - def sum_generator(self, g): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: g = [L([1])]*6 + [L(0)] - sage: t = L.sum_generator(g) - sage: t.coefficients(10) - [1, 2, 3, 4, 5, 6, 6, 6, 6, 6] - - :: - - sage: s = L([1]) - sage: def g(): - ....: while True: - ....: yield s - sage: t = L.sum_generator(g()) - sage: t.coefficients(9) - [1, 2, 3, 4, 5, 6, 7, 8, 9] - """ - return self(self._sum_generator_gen(g)) - - #Potentially infinite product - def _product_generator_gen(self, g): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import _integers_from - sage: L = LazyPowerSeriesRing(QQ) - sage: g = (L([1]+[0]*i+[1]) for i in _integers_from(0)) - sage: g2 = L._product_generator_gen(g) - sage: [next(g2) for i in range(10)] - [1, 1, 2, 4, 7, 12, 20, 33, 53, 84] - """ - z = next(g) - yield z.coefficient(0) - yield z.coefficient(1) - - n = 2 - - for x in g: - z = z * x - yield z.coefficient(n) - n += 1 - - while True: - yield z.coefficient(n) - n += 1 - - def product_generator(self, g): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: s1 = L([1,1,0]) - sage: s2 = L([1,0,1,0]) - sage: s3 = L([1,0,0,1,0]) - sage: s4 = L([1,0,0,0,1,0]) - sage: s5 = L([1,0,0,0,0,1,0]) - sage: s6 = L([1,0,0,0,0,0,1,0]) - sage: s = [s1, s2, s3, s4, s5, s6] - sage: def g(): - ....: for a in s: - ....: yield a - sage: p = L.product_generator(g()) - sage: p.coefficients(26) - [1, 1, 1, 2, 2, 3, 4, 4, 4, 5, 5, 5, 5, 4, 4, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0] - - :: - - sage: def m(n): - ....: yield 1 - ....: while True: - ....: for i in range(n-1): - ....: yield 0 - ....: yield 1 - sage: def s(n): - ....: q = 1/n - ....: yield 0 - ....: while True: - ....: for i in range(n-1): - ....: yield 0 - ....: yield q - - :: - - sage: def lhs_gen(): - ....: n = 1 - ....: while True: - ....: yield L(m(n)) - ....: n += 1 - - :: - - sage: def rhs_gen(): - ....: n = 1 - ....: while True: - ....: yield L(s(n)) - ....: n += 1 - sage: lhs = L.product_generator(lhs_gen()) - sage: rhs = L.sum_generator(rhs_gen()).exponential() - sage: lhs.coefficients(10) - [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] - sage: rhs.coefficients(10) - [1, 1, 2, 3, 5, 7, 11, 15, 22, 30] - """ - return self(self._product_generator_gen(g)) - - - -class LazyPowerSeries(AlgebraElement): - def __init__(self, A, stream=None, order=None, aorder=None, aorder_changed=True, is_initialized=False, name=None): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L() - sage: loads(dumps(f)) - Uninitialized lazy power series - """ - AlgebraElement.__init__(self, A) - self._stream = stream - self.order = unk if order is None else order - self.aorder = unk if aorder is None else aorder - if self.aorder == inf: - self.order = inf - self.aorder_changed = aorder_changed - self.is_initialized = is_initialized - self._name = name - - def compute_aorder(*args, **kwargs): - """ - The default compute_aorder does nothing. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: a = L(1) - sage: a.compute_aorder() is None - True - """ - return None - - def _get_repr_info(self, x): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: a = L([1,2,3]) - sage: a.compute_coefficients(5) - sage: a._get_repr_info('x') - [('1', 1), ('x', 2), ('x^2', 3)] - """ - n = len(self._stream) - m = ['1', x] - m += [x + "^" + str(i) for i in range(2, n)] - c = [self._stream[i] for i in range(n)] - return [(mo, co) for mo, co in zip(m, c) if co != 0] - - def __repr__(self): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: s = L(); s._name = 's'; s - s - - :: - - sage: L() - Uninitialized lazy power series - - :: - - sage: a = L([1,2,3]) - sage: a - O(1) - sage: a.compute_coefficients(2) - sage: a - 1 + 2*x + 3*x^2 + O(x^3) - sage: a.compute_coefficients(4) - sage: a - 1 + 2*x + 3*x^2 + 3*x^3 + 3*x^4 + 3*x^5 + ... - - :: - - sage: a = L([1,2,3,0]) - sage: a.compute_coefficients(5) - sage: a - 1 + 2*x + 3*x^2 - """ - if self._name is not None: - return self._name - - if self.is_initialized: - n = len(self._stream) - x = self.parent()._name - baserepr = repr_lincomb(self._get_repr_info(x)) - if self._stream.is_constant(): - if self._stream[n-1] == 0: - l = baserepr - else: - l = baserepr + " + " + repr_lincomb([(x+"^"+str(i), self._stream[n-1]) for i in range(n, n+3)]) + " + ..." - else: - l = baserepr + " + O(x^%s)" % n if n > 0 else "O(1)" - else: - l = 'Uninitialized lazy power series' - return l - - - def refine_aorder(self): - """ - Refines the approximate order of self as much as possible without - computing any coefficients. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: a = L([0,0,0,0,1]) - sage: a.aorder - 0 - sage: a.coefficient(2) - 0 - sage: a.aorder - 0 - sage: a.refine_aorder() - sage: a.aorder - 3 - - :: - - sage: a = L([0,0]) - sage: a.aorder - 0 - sage: a.coefficient(5) - 0 - sage: a.refine_aorder() - sage: a.aorder - Infinite series order - - :: - - sage: a = L([0,0,1,0,0,0]) - sage: a[4] - 0 - sage: a.refine_aorder() - sage: a.aorder - 2 - """ - #If we already know the order, then we don't have - #to worry about the approximate order - if self.order != unk: - return - - #aorder can never be infinity since order would have to - #be infinity as well - assert self.aorder != inf - - if self.aorder == unk or not self.is_initialized: - self.compute_aorder() - else: - #Try to improve the approximate order - ao = self.aorder - c = self._stream - n = c.number_computed() - - - if ao == 0 and n > 0: - while ao < n: - if self._stream[ao] == 0: - self.aorder += 1 - ao += 1 - else: - break - - #Try to recognize the zero series - if ao == n: - #For non-constant series, we cannot do anything - if not c.is_constant(): - return - if c[n-1] == 0: - self.aorder = inf - self.order = inf - return - - if ao < n: - self.order = ao - - - if hasattr(self, '_reference') and self._reference is not None: - self._reference._copy(self) - - def initialize_coefficient_stream(self, compute_coefficients): - """ - Initializes the coefficient stream. - - INPUT: compute_coefficients - - TESTS:: - - sage: from sage.combinat.species.series_order import inf, unk - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L() - sage: compute_coefficients = lambda ao: iter(ZZ) - sage: f.order = inf - sage: f.aorder = inf - sage: f.initialize_coefficient_stream(compute_coefficients) - sage: f.coefficients(5) - [0, 0, 0, 0, 0] - - :: - - sage: f = L() - sage: compute_coefficients = lambda ao: iter(ZZ) - sage: f.order = 1 - sage: f.aorder = 1 - sage: f.initialize_coefficient_stream(compute_coefficients) - sage: f.coefficients(5) - [0, 1, -1, 2, -2] - """ - ao = self.aorder - assert ao != unk - - if ao == inf: - self.order = inf - self._stream = Stream(0) - else: - self._stream = Stream(compute_coefficients(ao)) - - self.is_initialized = True - - def compute_coefficients(self, i): - """ - Computes all the coefficients of self up to i. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: a = L([1,2,3]) - sage: a.compute_coefficients(5) - sage: a - 1 + 2*x + 3*x^2 + 3*x^3 + 3*x^4 + 3*x^5 + ... - """ - self.coefficient(i) - - def coefficients(self, n): - """ - Return the first n coefficients of self. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L([1,2,3,0]) - sage: f.coefficients(5) - [1, 2, 3, 0, 0] - """ - return [self.coefficient(i) for i in range(n)] - - def is_zero(self): - """ - Return True if and only if self is zero. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: s = L([0,2,3,0]) - sage: s.is_zero() - False - - :: - - sage: s = L(0) - sage: s.is_zero() - True - - :: - - sage: s = L([0]) - sage: s.is_zero() - False - sage: s.coefficient(0) - 0 - sage: s.coefficient(1) - 0 - sage: s.is_zero() - True - """ - self.refine_aorder() - return self.order == inf - - def set_approximate_order(self, new_order): - """ - Sets the approximate order of self and returns True if the - approximate order has changed otherwise it will return False. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L([0,0,0,3,2,1,0]) - sage: f.get_aorder() - 0 - sage: f.set_approximate_order(3) - True - sage: f.set_approximate_order(3) - False - """ - self.aorder_changed = ( self.aorder != new_order ) - self.aorder = new_order - return self.aorder_changed - - def _copy(self, x): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L.term(2, 2) - sage: g = L() - sage: g._copy(f) - sage: g.order - 2 - sage: g.aorder - 2 - sage: g.is_initialized - True - sage: g.coefficients(4) - [0, 0, 2, 0] - """ - self.order = x.order - self.aorder = x.aorder - self.aorder_changed = x.aorder_changed - self.compute_aorder = x.compute_aorder - self.is_initialized = x.is_initialized - self._stream = x._stream - - def define(self, x): - """ - EXAMPLES: Test Recursive 0 - - :: - - sage: L = LazyPowerSeriesRing(QQ) - sage: one = L(1) - sage: monom = L.gen() - sage: s = L() - sage: s._name = 's' - sage: s.define(one+monom*s) - sage: s.aorder - 0 - sage: s.order - Unknown series order - sage: [s.coefficient(i) for i in range(6)] - [1, 1, 1, 1, 1, 1] - - Test Recursive 1 - - :: - - sage: s = L() - sage: s._name = 's' - sage: s.define(one+monom*s*s) - sage: s.aorder - 0 - sage: s.order - Unknown series order - sage: [s.coefficient(i) for i in range(6)] - [1, 1, 2, 5, 14, 42] - - Test Recursive 1b - - :: - - sage: s = L() - sage: s._name = 's' - sage: s.define(monom + s*s) - sage: s.aorder - 1 - sage: s.order - Unknown series order - sage: [s.coefficient(i) for i in range(7)] - [0, 1, 1, 2, 5, 14, 42] - - Test Recursive 2 - - :: - - sage: s = L() - sage: s._name = 's' - sage: t = L() - sage: t._name = 't' - sage: s.define(one+monom*t*t*t) - sage: t.define(one+monom*s*s) - sage: [s.coefficient(i) for i in range(9)] - [1, 1, 3, 9, 34, 132, 546, 2327, 10191] - sage: [t.coefficient(i) for i in range(9)] - [1, 1, 2, 7, 24, 95, 386, 1641, 7150] - - Test Recursive 2b - - :: - - sage: s = L() - sage: s._name = 's' - sage: t = L() - sage: t._name = 't' - sage: s.define(monom + t*t*t) - sage: t.define(monom + s*s) - sage: [s.coefficient(i) for i in range(9)] - [0, 1, 0, 1, 3, 3, 7, 30, 63] - sage: [t.coefficient(i) for i in range(9)] - [0, 1, 1, 0, 2, 6, 7, 20, 75] - - Test Recursive 3 - - :: - - sage: s = L() - sage: s._name = 's' - sage: s.define(one+monom*s*s*s) - sage: [s.coefficient(i) for i in range(10)] - [1, 1, 3, 12, 55, 273, 1428, 7752, 43263, 246675] - """ - self._copy(x) - x._reference = self - - def coefficient(self, n): - """ - Return the coefficient of xn in self. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L(ZZ) - sage: [f.coefficient(i) for i in range(5)] - [0, 1, -1, 2, -2] - """ - # The following line must not be written n < self.get_aorder() - # because comparison of Integer and OnfinityOrder is not implemented. - if self.get_aorder() > n: - return self.parent()._zero_base_ring - - assert self.is_initialized - - return self._stream[n] - - def get_aorder(self): - """ - Return the approximate order of self. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: a = L.gen() - sage: a.get_aorder() - 1 - """ - self.refine_aorder() - return self.aorder - - def get_order(self): - """ - Return the order of self. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: a = L.gen() - sage: a.get_order() - 1 - """ - self.refine_aorder() - return self.order - - def get_stream(self): - """ - Return self's underlying Stream object. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: a = L.gen() - sage: s = a.get_stream() - sage: [s[i] for i in range(5)] - [0, 1, 0, 0, 0] - """ - self.refine_aorder() - return self._stream - - def _approximate_order(self, compute_coefficients, new_order, *series): - if self.is_initialized: - return - - ochanged = self.aorder_changed - - ao = new_order(*[s.aorder for s in series]) - ao = inf if ao == unk else ao - - tchanged = self.set_approximate_order(ao) - - if len(series) == 0: - must_initialize_coefficient_stream = True - tchanged = ochanged = False - elif len(series) == 1 or len(series) == 2: - must_initialize_coefficient_stream = ( self.aorder == unk or self.is_initialized is False) - else: - raise ValueError - - if ochanged or tchanged: - for s in series: - s.compute_aorder() - ao = new_order(*[s.aorder for s in series]) - tchanged = self.set_approximate_order(ao) - - if must_initialize_coefficient_stream: - self.initialize_coefficient_stream(compute_coefficients) - - if hasattr(self, '_reference') and self._reference is not None: - self._reference._copy(self) - - def _new(self, compute_coefficients, order_op, *series, **kwds): - parent = kwds['parent'] if 'parent' in kwds else self.parent() - new_fps = self.__class__(parent, stream=None, order=unk, aorder=self.aorder, - aorder_changed=True, is_initialized=False) - - new_fps.compute_aorder = lambda: new_fps._approximate_order(compute_coefficients, order_op, *series) - return new_fps - - def _add_(self, y): - """ - EXAMPLES: Test Plus 1 - - :: - - sage: from sage.combinat.species.series import * - sage: from sage.combinat.species.stream import Stream - sage: L = LazyPowerSeriesRing(QQ) - sage: gs0 = L([0]) - sage: gs1 = L([1]) - sage: sum1 = gs0 + gs1 - sage: sum2 = gs1 + gs1 - sage: sum3 = gs1 + gs0 - sage: [gs0.coefficient(i) for i in range(11)] - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - sage: [gs1.coefficient(i) for i in range(11)] - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - sage: [sum1.coefficient(i) for i in range(11)] - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - sage: [sum2.coefficient(i) for i in range(11)] - [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] - sage: [sum3.coefficient(i) for i in range(11)] - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - - Test Plus 2 - - :: - - sage: gs1 = L([1,2,4,8,0]) - sage: gs2 = L([-1, 0,-1,-9,22,0]) - sage: sum = gs1 + gs2 - sage: sum2 = gs2 + gs1 - sage: [ sum.coefficient(i) for i in range(5) ] - [0, 2, 3, -1, 22] - sage: [ sum.coefficient(i) for i in range(5, 11) ] - [0, 0, 0, 0, 0, 0] - sage: [ sum2.coefficient(i) for i in range(5) ] - [0, 2, 3, -1, 22] - sage: [ sum2.coefficient(i) for i in range(5, 11) ] - [0, 0, 0, 0, 0, 0] - """ - return self._new(partial(self._plus_gen, y), min, self, y) - - add = _add_ - - - - def _plus_gen(self, y, ao): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: gs1 = L([1]) - sage: g = gs1._plus_gen(gs1, 0) - sage: [next(g) for i in range(5)] - [2, 2, 2, 2, 2] - - :: - - sage: g = gs1._plus_gen(gs1, 2) - sage: [next(g) for i in range(5)] - [0, 0, 2, 2, 2] - """ - base_ring = self.parent().base_ring() - zero = base_ring(0) - for n in range(ao): - yield zero - n = ao - while True: - yield self._stream[n] + y._stream[n] - n += 1 - - def _mul_(self, y): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: gs0 = L(0) - sage: gs1 = L([1]) - - :: - - sage: prod0 = gs0 * gs1 - sage: [prod0.coefficient(i) for i in range(11)] - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - - :: - - sage: prod1 = gs1 * gs0 - sage: [prod1.coefficient(i) for i in range(11)] - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - - :: - - sage: prod2 = gs1 * gs1 - sage: [prod2.coefficient(i) for i in range(11)] - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] - - :: - - sage: gs1 = L([1,2,4,8,0]) - sage: gs2 = L([-1, 0,-1,-9,22,0]) - - :: - - sage: prod1 = gs1 * gs2 - sage: [prod1.coefficient(i) for i in range(11)] - [-1, -2, -5, -19, 0, 0, 16, 176, 0, 0, 0] - - :: - - sage: prod2 = gs2 * gs1 - sage: [prod2.coefficient(i) for i in range(11)] - [-1, -2, -5, -19, 0, 0, 16, 176, 0, 0, 0] - """ - - return self._new(partial(self._times_gen, y), lambda a,b:a+b, self, y) - - times = _mul_ - - def _times_gen(self, y, ao): - r""" - Return an iterator for the coefficients of self \* y. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L([1,1,0]) - sage: g = f._times_gen(f,0) - sage: [next(g) for i in range(5)] - [1, 2, 1, 0, 0] - """ - base_ring = self.parent().base_ring() - zero = base_ring(0) - - for n in range(ao): - yield zero - - n = ao - while True: - low = self.aorder - high = n - y.aorder - nth_coefficient = zero - - #Handle the zero series - if low == inf or high == inf: - yield zero - n += 1 - continue - - for k in range(low, high+1): - cx = self._stream[k] - if cx == 0: - continue - nth_coefficient += cx * y._stream[n-k] - yield nth_coefficient - n += 1 - - def __pow__(self, n): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L([1,1,0]) # 1+x - sage: g = f^3 - sage: g.coefficients(4) - [1, 3, 3, 1] - - :: - - sage: f^0 - 1 - """ - if not isinstance(n, (int, Integer)) or n < 0: - raise ValueError("n must be a nonnegative integer") - return prod([self]*n, self.parent().identity_element()) - - def __invert__(self): - """ - Return 1 over this power series, i.e. invert this power series. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: x = L.gen() - - Geometric series:: - - sage: a = ~(1-x); a.compute_coefficients(10); a - 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + x^7 + x^8 + x^9 + x^10 + O(x^11) - - (Shifted) Fibonacci numbers:: - - sage: b = ~(1-x-x^2); b.compute_coefficients(10); b - 1 + x + 2*x^2 + 3*x^3 + 5*x^4 + 8*x^5 - + 13*x^6 + 21*x^7 + 34*x^8 + 55*x^9 + 89*x^10 + O(x^11) - - Series whose constant coefficient is `0` cannot be inverted:: - - sage: ~x - Traceback (most recent call last): - .... - ZeroDivisionError: cannot invert x because constant coefficient is 0 - """ - if self.get_aorder() > 0: - raise ZeroDivisionError( - 'cannot invert {} because ' - 'constant coefficient is 0'.format(self)) - return self._new(self._invert_gen, lambda a: 0, self) - - invert = __invert__ - - def _invert_gen(self, ao): - r""" - Return an iterator for the coefficients of 1 over this power series. - - TESTS:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L([1, -1, 0]) - sage: g = f._invert_gen(0) - sage: [next(g) for i in range(10)] - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - """ - from itertools import count - - assert ao == 0 - - ic0 = ~self.coefficient(0) - yield ic0 - if self.order == 0: - return - - one = self.parent()(1) - base = one - ic0 * self - base.coefficient(0) - ao_base = base.get_aorder() - assert ao_base >= 1 - - current = one + base - k = 1 - for n in count(1): - while ao_base*k < n: - current = one + base * current - k += 1 - current.coefficient(n) # make sure new current is initialized - ao_base = base.get_aorder() # update this so that while above is faster - yield current.coefficient(n) * ic0 - - def _div_(self, other): - """ - Divide this power series by ``other``. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: x = L.gen() - - Fibonacci numbers:: - - sage: b = x / (1-x-x^2); b.compute_coefficients(10); b - x + x^2 + 2*x^3 + 3*x^4 + 5*x^5 + 8*x^6 - + 13*x^7 + 21*x^8 + 34*x^9 + 55*x^10 + O(x^11) - """ - return self * ~other - - div = _div_ - - def __call__(self, y): - """ - Return the composition of this power series and the power series y. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: s = L([1]) - sage: t = L([0,0,1]) - sage: u = s(t) - sage: u.coefficients(11) - [1, 0, 1, 1, 2, 3, 5, 8, 13, 21, 34] - - Test Compose 2 - - :: - - sage: s = L([1]) - sage: t = L([0,0,1,0]) - sage: u = s(t) - sage: u.aorder - 0 - sage: u.order - Unknown series order - sage: u.coefficients(10) - [1, 0, 1, 0, 1, 0, 1, 0, 1, 0] - sage: u.aorder - 0 - sage: u.order - 0 - - Test Compose 3 s = 1/(1-x), t = x/(1-x) s(t) = (1-x)/(1-2x) - - :: - - sage: s = L([1]) - sage: t = L([0,1]) - sage: u = s(t) - sage: u.coefficients(14) - [1, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096] - """ - return self._new(partial(self._compose_gen, y), lambda a,b:a*b, self, y) - - composition = __call__ - - def _compose_gen(self, y, ao): - """ - Return a iterator for the coefficients of the composition of this - power series with the power series y. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: s = L([1]) - sage: t = L([0,1]) - sage: g = s._compose_gen(t, 0) - sage: [next(g) for i in range(10)] - [1, 1, 2, 4, 8, 16, 32, 64, 128, 256] - """ - assert y.coefficient(0) == 0 - yield self._stream[0] - z = self.tail().compose(y) * y - z.coefficient(1) - n = 1 - while True: - yield z._stream[n] - n += 1 - - def tail(self): - """ - Return the power series whose coefficients obtained by subtracting - the constant term from this series and then dividing by x. - - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L(range(20)) - sage: g = f.tail() - sage: g.coefficients(10) - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - """ - return self._new(lambda a0: self.iterator(1), bounded_decrement, self) - - def iterator(self, n=0, initial=None): - """ - Return an iterator for the coefficients of self starting at n. - - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L(range(10)) - sage: g = f.iterator(2) - sage: [next(g) for i in range(5)] - [2, 3, 4, 5, 6] - sage: g = f.iterator(2, initial=[0,0]) - sage: [next(g) for i in range(5)] - [0, 0, 2, 3, 4] - """ - if initial is not None: - for x in initial: - yield x - while True: - yield self._stream[n] - n += 1 - - compose = __call__ - - def _power_gen(self): - """ - Return a generator for all the powers self^k starting with k = 1. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L([1,1,0]) - sage: g = f._power_gen() - sage: next(g).coefficients(5) - [1, 1, 0, 0, 0] - sage: next(g).coefficients(5) - [1, 2, 1, 0, 0] - sage: next(g).coefficients(5) - [1, 3, 3, 1, 0] - """ - z = self - while True: - yield z - z = z*self - - def derivative(self): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: L = LazyPowerSeriesRing(QQ) - sage: one = L(1) - sage: monom = L.gen() - sage: s = L([1]) - sage: u = s.derivative() - sage: u.coefficients(10) - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - - :: - - sage: s = L() - sage: s._name = 's' - sage: s.define(one+monom*s*s) - sage: u = s.derivative() - sage: u.coefficients(5) #[1*1, 2*2, 3*5, 4*14, 5*42] - [1, 4, 15, 56, 210] - - :: - - sage: s = L([1]) - sage: t = L([0,1]) - sage: u = s(t).derivative() - sage: v = (s.derivative().compose(t))*t.derivative() - sage: u.coefficients(11) - [1, 4, 12, 32, 80, 192, 448, 1024, 2304, 5120, 11264] - sage: v.coefficients(11) - [1, 4, 12, 32, 80, 192, 448, 1024, 2304, 5120, 11264] - - :: - - sage: s = L(); s._name='s' - sage: t = L(); t._name='t' - sage: s.define(monom+t*t*t) - sage: t.define(monom+s*s) - sage: u = (s*t).derivative() - sage: v = s.derivative()*t + s*t.derivative() - sage: u.coefficients(10) - [0, 2, 3, 4, 30, 72, 133, 552, 1791, 4260] - sage: v.coefficients(10) - [0, 2, 3, 4, 30, 72, 133, 552, 1791, 4260] - sage: u.coefficients(10) == v.coefficients(10) - True - - :: - - sage: f = L._new_initial(2, Stream([0,0,4,5,6,0])) - sage: d = f.derivative() - sage: d.get_aorder() - 1 - sage: d.coefficients(5) - [0, 8, 15, 24, 0] - """ - return self._new(self._diff_gen, bounded_decrement, self) - - def _diff_gen(self, ao): - """ - Return an iterator for the coefficients of the derivative of self. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L([1]) - sage: g = f._diff_gen(0) - sage: [next(g) for i in range(10)] - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - """ - n = 1 - while True: - yield n*self._stream[n] - n += 1 - - ########### - #Integrals# - ########### - def integral(self, integration_constant = 0): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: zero = L(0) - sage: s = zero - sage: t = s.integral() - sage: t.is_zero() - True - - :: - - sage: s = zero - sage: t = s.integral(1) - sage: t.coefficients(6) - [1, 0, 0, 0, 0, 0] - sage: t._stream.is_constant() - True - - :: - - sage: s = L.term(1, 0) - sage: t = s.integral() - sage: t.coefficients(6) - [0, 1, 0, 0, 0, 0] - sage: t._stream.is_constant() - True - - :: - - sage: s = L.term(1,0) - sage: t = s.integral(1) - sage: t.coefficients(6) - [1, 1, 0, 0, 0, 0] - sage: t._stream.is_constant() - True - - :: - - sage: s = L.term(1, 4) - sage: t = s.integral() - sage: t.coefficients(10) - [0, 0, 0, 0, 0, 1/5, 0, 0, 0, 0] - - :: - - sage: s = L.term(1,4) - sage: t = s.integral(1) - sage: t.coefficients(10) - [1, 0, 0, 0, 0, 1/5, 0, 0, 0, 0] - - TESTS:: - - sage: from sage.combinat.species.stream import Stream - sage: f = L._new_initial(2, Stream([0,0,4,5,6,0])) - sage: i = f.derivative().integral() - sage: i.get_aorder() - 2 - sage: i.coefficients(5) - [0, 0, 4, 5, 6] - sage: i = f.derivative().integral(1) - sage: i.get_aorder() - 0 - sage: i.coefficients(5) - [1, 0, 4, 5, 6] - """ - if integration_constant == 0: - return self._new(self._integral_zero_gen, increment, self) - else: - L = self.parent() - return L._new_initial(0, Stream(self._integral_nonzero_gen(integration_constant))) - - def _integral_zero_gen(self, ao): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: s = L.gen() - sage: g = s._integral_zero_gen(1) - sage: [next(g) for i in range(5)] - [0, 0, 1/2, 0, 0] - """ - for n in range(ao): - yield self.parent().zero() - n = ao - while True: - #Check to see if the stream is finite - if self.is_finite(n-1): - yield self._stream[n-1] - break - else: - yield (Integer(1)/Integer(n))*self._stream[n-1] - n += 1 - - - def _integral_nonzero_gen(self, integration_constant): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L._new_initial(2, Stream([0,0,4,5,6,0])).derivative() - sage: g = f._integral_nonzero_gen(1) - sage: [next(g) for i in range(5)] - [1, 0, 4, 5, 6] - """ - yield integration_constant - ao = self.aorder - assert ao != unk - - if ao == inf: - yield self.parent()._zero_base_ring - else: - for _ in range(ao-1): - yield self.parent()._zero_base_ring - - n = max(1, ao) - while True: - self.coefficient(n - 1) - - #Check to see if the stream is finite - if self.is_finite(n-1): - yield self.coefficient(n-1) - break - else: - yield (Integer(1)/Integer(n))*self.coefficient(n-1) - n += 1 - - def is_finite(self, n=None): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: a = L([0,0,1,0,0]); a - O(1) - sage: a.is_finite() - False - sage: c = a[4] - sage: a.is_finite() - False - sage: a.is_finite(4) - False - sage: c = a[5] - sage: a.is_finite() - True - sage: a.is_finite(4) - True - """ - if self.order is inf: - return True - - s = self._stream - - if n is None: - n = len(s) - - if s.is_constant() and all(s[i] == 0 for i in range(n-1, max(n,len(s)))): - return True - - return False - - def exponential(self): - """ - TESTS:: - - sage: def inv_factorial(): - ....: q = 1 - ....: yield 0 - ....: yield q - ....: n = 2 - ....: while True: - ....: q = q / n - ....: yield q - ....: n += 1 - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L(inv_factorial()) #e^(x)-1 - sage: u = f.exponential() - sage: g = inv_factorial() - sage: z1 = [1,1,2,5,15,52,203,877,4140,21147,115975] - sage: l1 = [z*next(g) for z in z1] - sage: l1 = [1] + l1[1:] - sage: u.coefficients(11) - [1, 1, 1, 5/6, 5/8, 13/30, 203/720, 877/5040, 23/224, 1007/17280, 4639/145152] - sage: l1 == u.coefficients(11) - True - """ - base_ring = self.parent().base_ring() - s = self.parent()() - s.define( (self.derivative()*s).integral(base_ring(1)) ) - return s - - def __getitem__(self, i): - """ - Return the ith coefficient of self. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: f = L([1,2,3,0]) - sage: [f[i] for i in range(5)] - [1, 2, 3, 0, 0] - """ - return self.coefficient(i) - - - ######################### - #Min and max restriction# - ######################### - def restricted(self, min=None, max=None): - """ - Return the power series restricted to the coefficients starting at - ``min`` and going up to, but not including ``max``. - - If ``min`` is not specified, then it is assumed to be zero. If - ``max`` is not specified, then it is assumed to be infinity. - - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: a = L([1]) - sage: a.restricted().coefficients(10) - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] - sage: a.restricted(min=2).coefficients(10) - [0, 0, 1, 1, 1, 1, 1, 1, 1, 1] - sage: a.restricted(max=5).coefficients(10) - [1, 1, 1, 1, 1, 0, 0, 0, 0, 0] - sage: a.restricted(min=2, max=6).coefficients(10) - [0, 0, 1, 1, 1, 1, 0, 0, 0, 0] - """ - - if ((min is None and max is None) or - (max is None and self.get_aorder() >= min)): - return self - - if min is None: - min = 0 - return self._new(partial(self._restricted_gen, min, max), - lambda ao: builtins.max(ao, min), self) - - def _restricted_gen(self, mn, mx, ao): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: a = L([1]) - sage: g = a._restricted_gen(None, None, 2) - sage: [next(g) for i in range(10)] - [0, 0, 1, 1, 1, 1, 1, 1, 1, 1] - sage: g = a._restricted_gen(1, None, 2) - sage: [next(g) for i in range(10)] - [0, 0, 1, 1, 1, 1, 1, 1, 1, 1] - sage: g = a._restricted_gen(3, None, 2) - sage: [next(g) for i in range(10)] - [0, 0, 0, 1, 1, 1, 1, 1, 1, 1] - - :: - - sage: g = a._restricted_gen(1, 5, 2) - sage: [next(g) for i in range(6)] - [0, 0, 1, 1, 1, 0] - """ - BR = self.parent().base_ring() - for n in range(max(mn,ao)): - yield BR(0) - - n = max(mn, ao) - while True: - if mx is not None and n >= mx: - yield BR(0) - break - else: - yield self._stream[n] - n += 1 - - - ############# - #Change Ring# - ############# - def _change_ring_gen(self, R, ao): - """ - EXAMPLES:: - - sage: L = LazyPowerSeriesRing(QQ) - sage: L2 = LazyPowerSeriesRing(RR) - sage: a = L([1]) - sage: b = L2(a) - sage: b.parent() - Lazy Power Series Ring over Real Field with 53 bits of precision - sage: b.coefficients(3) - [1.00000000000000, 1.00000000000000, 1.00000000000000] - """ - for n in range(ao): - yield R(0) - - n = ao - while True: - yield R(self._stream[n]) - n += 1 - -################################# - - -def uninitialized(): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series import uninitialized - sage: uninitialized() - Traceback (most recent call last): - ... - RuntimeError: we should never be here - """ - raise RuntimeError("we should never be here") diff --git a/src/sage/combinat/species/series_order.py b/src/sage/combinat/species/series_order.py deleted file mode 100644 index f4c42d032bd..00000000000 --- a/src/sage/combinat/species/series_order.py +++ /dev/null @@ -1,294 +0,0 @@ -""" -Series Order - -This file provides some utility classes which are useful when -working with unknown, known, and infinite series orders for -univariate power series. - -This code is based on the work of Ralf Hemmecke and Martin Rubey's -Aldor-Combinat, which can be found at -http://www.risc.uni-linz.ac.at/people/hemmecke/aldor/combinat/index.html. -In particular, the relevant section for this file can be found at -http://www.risc.uni-linz.ac.at/people/hemmecke/AldorCombinat/combinatsu30.html. -""" -from sage.rings.integer import Integer - -class SeriesOrderElement: - pass - -class InfiniteSeriesOrder(SeriesOrderElement): - def __repr__(self): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: o = InfiniteSeriesOrder(); o - Infinite series order - """ - return "Infinite series order" - - def __add__(self, x): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: o = InfiniteSeriesOrder() - sage: o + 2 - Infinite series order - sage: o + o - Infinite series order - - :: - - sage: u = UnknownSeriesOrder() - sage: o + u - Unknown series order - - TESTS:: - - sage: o + -1 - Traceback (most recent call last): - ... - ValueError: x must be a positive integer - """ - if isinstance(x, (int, Integer)): - if x < 0: - raise ValueError("x must be a positive integer") - return self - - if isinstance(x, InfiniteSeriesOrder): - return self - - if isinstance(x, UnknownSeriesOrder): - return x - - raise TypeError("x must be a positive integer or a SeriesOrderElement") - - __radd__ = __add__ - - - def __mul__(self, x): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: o = InfiniteSeriesOrder() - sage: o * 2 - Infinite series order - sage: o * o - Infinite series order - - :: - - sage: u = UnknownSeriesOrder() - sage: o * u - Unknown series order - - TESTS:: - - sage: o * -1 - Traceback (most recent call last): - ... - ValueError: x must be a positive integer - """ - if isinstance(x, (int, Integer)): - if x < 0: - raise ValueError("x must be a positive integer") - elif x == 0: - return x - return self - - if isinstance(x, InfiniteSeriesOrder): - return self - - if isinstance(x, UnknownSeriesOrder): - return x - - raise TypeError("x must be a positive integer or a SeriesOrderElement") - - __rmul__ = __mul__ - - def __lt__(self, x): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: o = InfiniteSeriesOrder() - sage: o < 2 - False - sage: o < o - False - - :: - - sage: u = UnknownSeriesOrder() - sage: o < u - False - sage: 2 < o # TODO: Not Implemented - True - """ - if isinstance(x, (int, Integer)): - if x < 0: - raise ValueError("x must be a positive integer") - return False - - if isinstance(x, InfiniteSeriesOrder): - return False - - if isinstance(x, UnknownSeriesOrder): - return False - - - raise TypeError("x must be a positive integer or a SeriesOrderElement") - - - def __gt__(self, x): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: o = InfiniteSeriesOrder() - sage: o > 2 - True - """ - return True - -class UnknownSeriesOrder(SeriesOrderElement): - def __repr__(self): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: u = UnknownSeriesOrder(); u - Unknown series order - """ - return "Unknown series order" - - def __add__(self, x): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: u = UnknownSeriesOrder() - sage: u + 2 - Unknown series order - sage: u + u - Unknown series order - """ - - if isinstance(x, (int, Integer)): - if x < 0: - raise ValueError("x must be a positive integer") - return self - - if isinstance(x, SeriesOrderElement): - return self - - raise TypeError("x must be a positive integer or a SeriesOrderElement") - - __radd__ = __add__ - - - def __mul__(self, x): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: u = UnknownSeriesOrder() - sage: u * 2 - Unknown series order - sage: u * u - Unknown series order - """ - if isinstance(x, (int, Integer)): - if x < 0: - raise ValueError("x must be a positive integer") - return self - - if isinstance(x, SeriesOrderElement): - return self - - raise TypeError("x must be a positive integer or a SeriesOrderElement") - - __rmul__ = __mul__ - - def __lt__(self, x): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: u = UnknownSeriesOrder() - sage: u < 2 - True - sage: o = InfiniteSeriesOrder() - sage: u < o - True - """ - if isinstance(x, (int, Integer)): - if x < 0: - raise ValueError("x must be a positive integer") - return True - - if isinstance(x, SeriesOrderElement): - return True - - raise TypeError("x must be a positive integer or a SeriesOrderElement") - - def __gt__(self, x): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: u = UnknownSeriesOrder() - sage: u > 2 - False - """ - return False - -def bounded_decrement(x): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: u = UnknownSeriesOrder() - sage: bounded_decrement(u) - Unknown series order - sage: bounded_decrement(4) - 3 - sage: bounded_decrement(0) - 0 - """ - if isinstance(x, SeriesOrderElement): - return x - - if isinstance(x, (int, Integer)): - if x < 0: - raise ValueError("x must be a positive integer") - return max(0, x - 1) - - raise TypeError("x must be a positive integer or a SeriesOrderElement") - - -def increment(x): - """ - EXAMPLES:: - - sage: from sage.combinat.species.series_order import * - sage: u = UnknownSeriesOrder() - sage: increment(u) - Unknown series order - sage: increment(2) - 3 - """ - if isinstance(x, SeriesOrderElement): - return x + 1 - - if isinstance(x, (int, Integer)): - if x < 0: - raise ValueError("x must be a positive integer") - return x+1 - - raise TypeError("x must be a positive integer or a SeriesOrderElement") - -inf = InfiniteSeriesOrder() -unk = UnknownSeriesOrder() diff --git a/src/sage/combinat/species/set_species.py b/src/sage/combinat/species/set_species.py index 6bf21d4c462..64313334a2f 100644 --- a/src/sage/combinat/species/set_species.py +++ b/src/sage/combinat/species/set_species.py @@ -17,7 +17,6 @@ #***************************************************************************** from .species import GenericCombinatorialSpecies -from .generating_series import _integers_from from sage.combinat.species.structure import GenericSpeciesStructure from sage.combinat.species.misc import accept_size from sage.structure.unique_representation import UniqueRepresentation @@ -102,11 +101,11 @@ def __init__(self, min=None, max=None, weight=None): sage: E = species.SetSpecies() sage: E.structures([1,2,3]).list() [{1, 2, 3}] - sage: E.isotype_generating_series().coefficients(4) + sage: E.isotype_generating_series()[0:4] [1, 1, 1, 1] sage: S = species.SetSpecies() - sage: c = S.generating_series().coefficients(3) + sage: c = S.generating_series()[0:3] sage: S._check() True sage: S == loads(dumps(S)) @@ -130,7 +129,7 @@ def _structures(self, structure_class, labels): _isotypes = _structures - def _gs_iterator(self, base_ring): + def _gs_callable(self, base_ring, n): r""" The generating series for the species of sets is given by `e^x`. @@ -139,15 +138,14 @@ def _gs_iterator(self, base_ring): sage: S = species.SetSpecies() sage: g = S.generating_series() - sage: g.coefficients(10) + sage: [g.coefficient(i) for i in range(10)] [1, 1, 1/2, 1/6, 1/24, 1/120, 1/720, 1/5040, 1/40320, 1/362880] sage: [g.count(i) for i in range(10)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] """ - for n in _integers_from(0): - yield base_ring(self._weight / factorial(n)) + return base_ring(self._weight / factorial(n)) - def _itgs_list(self, base_ring): + def _itgs_list(self, base_ring, n): r""" The isomorphism type generating series for the species of sets is `\frac{1}{1-x}`. @@ -156,12 +154,12 @@ def _itgs_list(self, base_ring): sage: S = species.SetSpecies() sage: g = S.isotype_generating_series() - sage: g.coefficients(10) + sage: g[0:10] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] sage: [g.count(i) for i in range(10)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] """ - return [base_ring(self._weight)] + return base_ring(self._weight) def _cis(self, series_ring, base_ring): r""" @@ -172,7 +170,7 @@ def _cis(self, series_ring, base_ring): sage: S = species.SetSpecies() sage: g = S.cycle_index_series() - sage: g.coefficients(5) + sage: g[0:5] [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], diff --git a/src/sage/combinat/species/species.py b/src/sage/combinat/species/species.py index 4e82c1b9b39..4cd3403ae61 100644 --- a/src/sage/combinat/species/species.py +++ b/src/sage/combinat/species/species.py @@ -22,9 +22,9 @@ sage: leaf = species.SingletonSpecies() sage: internal_node = species.SingletonSpecies(weight=q) sage: L = species.LinearOrderSpecies(min=1) - sage: T = species.CombinatorialSpecies() + sage: T = species.CombinatorialSpecies(min=1) sage: T.define(leaf + internal_node*L(T)) - sage: T.isotype_generating_series().coefficients(6) + sage: T.isotype_generating_series()[0:6] [0, 1, q, q^2 + q, q^3 + 3*q^2 + q, q^4 + 6*q^3 + 6*q^2 + q] Consider the following:: @@ -335,7 +335,7 @@ def functorial_composition(self, g): sage: WP = species.SubsetSpecies() sage: P2 = E2*E sage: G = WP.functorial_composition(P2) - sage: G.isotype_generating_series().coefficients(5) + sage: G.isotype_generating_series()[0:5] [1, 1, 2, 4, 11] """ from .functorial_composition_species import FunctorialCompositionSpecies @@ -360,7 +360,7 @@ def restricted(self, min=None, max=None): Set species with min=3 sage: S.structures([1,2]).list() [] - sage: S.generating_series().coefficients(5) + sage: S.generating_series()[0:5] [0, 0, 0, 1/6, 1/24] """ kwargs = {'min': self._min if min is None else min, @@ -431,19 +431,19 @@ def __pow__(self, n): (Singleton species) and (Singleton species)) and (Product of (Singleton species) and (Singleton species))) - sage: (X^2).generating_series().coefficients(4) + sage: (X^2).generating_series()[0:4] [0, 0, 1, 0] - sage: (X^3).generating_series().coefficients(4) + sage: (X^3).generating_series()[0:4] [0, 0, 0, 1] - sage: ((One+X)^3).generating_series().coefficients(4) + sage: ((One+X)^3).generating_series()[0:4] [1, 3, 3, 1] - sage: ((One+X)^7).generating_series().coefficients(8) + sage: ((One+X)^7).generating_series()[0:8] [1, 7, 21, 35, 35, 21, 7, 1] sage: x = QQ[['x']].gen() sage: coeffs = ((1+x+x+x**2)**25+O(x**10)).padded_list() sage: T = ((One+X+X+X^2)^25) - sage: T.generating_series().coefficients(10) == coeffs + sage: T.generating_series()[0:10] == coeffs True sage: X^1 is X True @@ -479,21 +479,23 @@ def _get_series(self, series_ring_class, prefix, base_ring=None): EXAMPLES:: sage: P = species.PermutationSpecies(min=2, max=4) - sage: P.generating_series().coefficients(8) #indirect doctest + sage: P.generating_series()[0:8] #indirect doctest [0, 0, 1, 1, 0, 0, 0, 0] """ series = self._series_helper(series_ring_class, prefix, base_ring=base_ring) - # We need to restrict the series based on the min # and max of this species. Note that if min and max # are both None (as in the default case), then the restrict # method will just return series. - return series.restricted(min=self._min, max=self._max) + if self._min is None and self._max is None: + return series + return series.parent()(lambda n: series[n], + valuation=self._min, degree=self._max) def _series_helper(self, series_ring_class, prefix, base_ring=None): """ This code handles much of the common work involved in getting the - generating series for this species (such has determining the + generating series for this species (such as determining the correct base ring to pass down to the subclass, determining which method on the subclass to call to get the series object, etc.) @@ -516,13 +518,13 @@ def _series_helper(self, series_ring_class, prefix, base_ring=None): sage: from sage.combinat.species.generating_series import OrdinaryGeneratingSeriesRing sage: S = species.SetSpecies() sage: itgs = S._series_helper(OrdinaryGeneratingSeriesRing, "itgs") - sage: itgs.coefficients(3) + sage: itgs[:3] [1, 1, 1] :: sage: itgs = S._series_helper(OrdinaryGeneratingSeriesRing, "itgs", base_ring=RDF) - sage: itgs.coefficients(3) + sage: itgs[:3] [1.0, 1.0, 1.0] """ prefix = "_" + prefix @@ -550,16 +552,16 @@ def _series_helper(self, series_ring_class, prefix, base_ring=None): except AttributeError: pass - # Try to return things like self._gs_iterator(base_ring). - # This is used when the subclass just provides an iterator + # Try to return things like self._gs_callable(base_ring). + # This is used when the subclass just provides an callable # for the coefficients of the generating series. Optionally, # the subclass can specify the order of the series. try: - iterator = getattr(self, prefix + "_iterator")(base_ring) + callable = getattr(self, prefix + "_callable") try: - return series_ring(iterator, order=self._order()) + return series_ring(lambda n: callable(base_ring, n), valuation=self._order()) except AttributeError: - return series_ring(iterator) + return series_ring(lambda n: callable(base_ring, n)) except AttributeError: pass @@ -567,7 +569,7 @@ def _series_helper(self, series_ring_class, prefix, base_ring=None): # This is used when the generating series is just a single # term. try: - return series_ring.term(getattr(self, prefix + "_term")(base_ring), + return series_ring(getattr(self, prefix + "_term")(base_ring), self._order()) except AttributeError: pass @@ -578,7 +580,7 @@ def _series_helper(self, series_ring_class, prefix, base_ring=None): # The generating series with all ones coefficients is generated this # way. try: - return series_ring(getattr(self, prefix + "_list")(base_ring)) + return series_ring(lambda n: getattr(self, prefix + "_list")(base_ring, n)) except AttributeError: pass @@ -597,7 +599,7 @@ def generating_series(self, base_ring=None): sage: P = species.PermutationSpecies() sage: g = P.generating_series() - sage: g.coefficients(4) + sage: g[:4] [1, 1, 1, 1] sage: g.counts(4) [1, 1, 2, 6] @@ -620,7 +622,7 @@ def isotype_generating_series(self, base_ring=None): sage: P = species.PermutationSpecies() sage: g = P.isotype_generating_series() - sage: g.coefficients(4) + sage: g[0:4] [1, 1, 2, 3] sage: g.counts(4) [1, 1, 2, 3] @@ -642,7 +644,7 @@ def cycle_index_series(self, base_ring=None): sage: P = species.PermutationSpecies() sage: g = P.cycle_index_series() - sage: g.coefficients(4) + sage: g[0:4] [p[], p[1], p[1, 1] + p[2], p[1, 1, 1] + p[2, 1] + p[3]] """ return self._get_series(CycleIndexSeriesRing, "cis", base_ring) @@ -774,10 +776,10 @@ def algebraic_equation_system(self): :: sage: sorted(B.digraph().vertex_iterator(), key=str) - [Combinatorial species, - Product of (Combinatorial species) and (Combinatorial species), + [Combinatorial species with min=1, + Product of (Combinatorial species with min=1) and (Combinatorial species with min=1), Singleton species, - Sum of (Singleton species) and (Product of (Combinatorial species) and (Combinatorial species))] + Sum of (Singleton species) and (Product of (Combinatorial species with min=1) and (Combinatorial species with min=1))] :: diff --git a/src/sage/combinat/species/stream.py b/src/sage/combinat/species/stream.py deleted file mode 100644 index 56644b399ef..00000000000 --- a/src/sage/combinat/species/stream.py +++ /dev/null @@ -1,501 +0,0 @@ -""" -Streams or Infinite Arrays - -This code is based on the work of Ralf Hemmecke and Martin Rubey's -Aldor-Combinat, which can be found at -http://www.risc.uni-linz.ac.at/people/hemmecke/aldor/combinat/index.html. -In particular, the relevant section for this file can be found at -http://www.risc.uni-linz.ac.at/people/hemmecke/AldorCombinat/combinatse12.html. -""" -import types -from collections.abc import Iterable -from sage.structure.sage_object import SageObject - - -def _integers_from(n): - """ - Returns a generator for the integers starting at n. - - EXAMPLES:: - - sage: from sage.combinat.species.stream import _integers_from - sage: g = _integers_from(5) - sage: [next(g) for i in range(5)] - [5, 6, 7, 8, 9] - """ - while True: - yield n - n += 1 - -def _apply_function(func, list): - """ - Returns an iterator for func(i) for i in list. - - EXAMPLES:: - - sage: from sage.combinat.species.stream import _apply_function - sage: def square(l): - ....: l.append(l[-1]^2) - ....: return l[-1] - ... - sage: l = [2] - sage: g = _apply_function(square, l) - sage: [next(g) for i in range(5)] - [4, 16, 256, 65536, 4294967296] - """ - while True: - try: - yield func(list) - except Exception: - break - -def Stream(x=None, const=None): - """ - Returns a stream. - - EXAMPLES: We can create a constant stream by just passing a - - :: - - sage: from sage.combinat.species.stream import Stream - sage: s = Stream(const=0) - sage: [s[i] for i in range(10)] - [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] - """ - if const is not None: - return Stream_class(const=const) - elif isinstance(x, Iterable): - return Stream_class(iter(x)) - elif isinstance(x, (types.FunctionType, types.LambdaType)): - return Stream_class(func=x) - - return Stream_class(iter([x,0])) - -class Stream_class(SageObject): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: from builtins import zip - sage: s = Stream(const=0) - sage: len(s) - 1 - sage: [x for (x,i) in zip(s, range(4))] - [0, 0, 0, 0] - sage: len(s) - 1 - - :: - - sage: s = Stream(const=4) - sage: g = iter(s) - sage: l1 = [x for (x,i) in zip(g, range(10))] - sage: l = [4 for k in range(10)] - sage: l == l1 - True - - :: - - sage: h = lambda l: 1 if len(l) < 2 else l[-1] + l[-2] - sage: fib = Stream(h) - sage: [x for (x,i) in zip(fib, range(11))] - [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] - - :: - - sage: r = [4, 3, 5, 2, 6, 1, 1, 1, 1, 1] - sage: l = [4, 3, 5, 2, 6, 1] - sage: s = Stream(l) - sage: s[3] = -1 - sage: [x for (x,i) in zip(s, r)] - [4, 3, 5, -1, 6, 1, 1, 1, 1, 1] - sage: s[5] = -2 - sage: [x for (x,i) in zip(s, r)] - [4, 3, 5, -1, 6, -2, 1, 1, 1, 1] - sage: s[6] = -3 - sage: [x for (x,i) in zip(s, r)] - [4, 3, 5, -1, 6, -2, -3, 1, 1, 1] - sage: s[8] = -4 - sage: [x for (x,i) in zip(s, r)] - [4, 3, 5, -1, 6, -2, -3, 1, -4, 1] - sage: a = Stream(const=0) - sage: a[2] = 3 - sage: [x for (x,i) in zip(a, range(4))] - [0, 0, 3, 0] - """ - - def __init__(self, gen=None, const=None, func=None): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream_class, Stream - sage: s = Stream_class(const=4) - sage: loads(dumps(s)) - - - :: - - sage: sorted(s.__dict__.items()) - [('_constant', 4), - ('_gen', None), - ('_last_index', 0), - ('_list', [4]), - ('end_reached', True)] - - :: - - sage: s = Stream(ZZ) - sage: sorted(s.__dict__.items()) - [('_constant', None), - ('_gen', ), - ('_last_index', -1), - ('_list', []), - ('end_reached', False)] - """ - #We define self._list up here so that - #_apply_function can make use of it if - #it needs to. - self._list = [] - - - if func is not None: - if gen is not None: - raise ValueError("you cannot specify both a function and a generator") - gen = _apply_function(func, self._list) - - #Constant stream - if const is not None: - self._list = [const] - self._last_index = 0 # last_index == len(self._list) - 1 - self._gen = None - self._constant = const - self.end_reached = True - else: - self._last_index = -1 # last_index == len(self._list) - 1 - self._gen = gen - self._constant = const - self.end_reached = False - - def __setitem__(self, i, t): - """ - Set the i-th entry of self to t. - - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - - :: - - sage: s = Stream(const=0) - sage: s[5] - 0 - sage: s.data() - [0] - sage: s[5] = 5 - sage: s[5] - 5 - sage: s.data() - [0, 0, 0, 0, 0, 5] - - :: - - sage: s = Stream(ZZ) - sage: s[10] - -5 - sage: s.data() - [0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5] - sage: s[10] = 10 - sage: s.data() - [0, 1, -1, 2, -2, 3, -3, 4, -4, 5, 10] - """ - # Compute all of the coefficients up to (and including) the ith one - self[i] - - if i < len(self._list): - #If we are here, we can just change the entry in self._list - self._list[i] = t - else: - #If we are here, then the stream has become constant. We just - #extend self._list with self._constant and then change the - #last entry. - self._list += [ self._constant ] * (i+1 - len(self._list)) - self._last_index = i - self._list[i] = t - - def set_gen(self, gen): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: from builtins import zip - sage: fib = Stream() - sage: def g(): - ....: yield 1 - ....: yield 1 - ....: n = 0 - ....: while True: - ....: yield fib[n] + fib[n+1] - ....: n += 1 - - :: - - sage: fib.set_gen(g()) - sage: [x for (x,i) in zip(fib, range(11))] - [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] - - :: - - sage: l = [4,3,5,2,6,1] - sage: s = Stream(l) - sage: s[3] - 2 - sage: len(s) - 4 - sage: g = iter(l) - sage: s.set_gen(g) - sage: s[5] - 3 - sage: len(s) - 6 - """ - self._gen = gen - self.end_reached = False - - def map(self, f): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: s = Stream(ZZ) - sage: square = lambda x: x^2 - sage: ss = s.map(square) - sage: [ss[i] for i in range(10)] - [0, 1, 1, 4, 4, 9, 9, 16, 16, 25] - - TESTS:: - - sage: from builtins import zip - sage: f = lambda l: 0 if len(l) == 0 else l[-1] + 1 - sage: o = Stream(f) - sage: [x for (x,i) in zip(o, range(10))] - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - sage: double = lambda z: 2*z - sage: t = o.map(double) - sage: [x for (x,i) in zip(t, range(10))] - [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] - - :: - - sage: double = lambda z: 2*z - sage: o = Stream([0,1,2,3]) - sage: [x for (x,i) in zip(o, range(6))] - [0, 1, 2, 3, 3, 3] - sage: t = o.map(double) - sage: [x for (x,i) in zip(t, range(6))] - [0, 2, 4, 6, 6, 6] - """ - return Stream((f(x) for x in self)) - - def __getitem__(self, i): - """ - Returns the ith entry of self. - - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: s = Stream(ZZ) - sage: [s[i] for i in range(10)] - [0, 1, -1, 2, -2, 3, -3, 4, -4, 5] - sage: s[1] - 1 - - :: - - sage: s = Stream([1,2,3]) - sage: [s[i] for i in range(10)] - [1, 2, 3, 3, 3, 3, 3, 3, 3, 3] - - :: - - sage: s = Stream(QQ) - sage: s[10] - -3 - """ - if i <= self._last_index: - return self._list[i] - elif self.end_reached: - if self._constant is not False: - return self._constant - else: - raise IndexError("out of position") - else: - while self._last_index < i: - try: - self._list.append(next(self._gen)) - self._last_index += 1 - except StopIteration: - self.end_reached = True - self._constant = self._list[-1] - return self[i] - - return self._list[i] - - - def __iter__(self): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: s = Stream([1,2,3]) - sage: g = iter(s) - sage: [next(g) for i in range(5)] - [1, 2, 3, 3, 3] - """ - i = 0 - while True: - try: - yield self[i] - except IndexError: - break - i += 1 - - def __len__(self): - """ - Returns the number of coefficients computed so far. - - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: l = [4,3,5,7,4,1,9,7] - sage: s = Stream(l) - sage: s[3] - 7 - sage: len(s) - 4 - sage: s[3] - 7 - sage: len(s) - 4 - sage: s[1] - 3 - sage: len(s) - 4 - sage: s[4] - 4 - sage: len(s) - 5 - - TESTS:: - - sage: l = ['Hello', ' ', 'World', '!'] - sage: s = Stream(l) - sage: len(s) - 0 - sage: s[2] - 'World' - sage: len(s) - 3 - sage: u = "" - sage: for i in range(len(s)): u += s[i] - sage: u - 'Hello World' - sage: v = "" - sage: for i in range(10): v += s[i] - sage: v - 'Hello World!!!!!!!' - sage: len(s) - 4 - """ - return len(self._list) - - number_computed = __len__ - - def data(self): - """ - Returns a list of all the coefficients computed so far. - - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream, _integers_from - sage: s = Stream(_integers_from(3)) - sage: s.data() - [] - sage: s[5] - 8 - sage: s.data() - [3, 4, 5, 6, 7, 8] - """ - return self._list - - def is_constant(self): - """ - Returns True if and only if - - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: s = Stream([1,2,3]) - sage: s.is_constant() - False - sage: s[3] - 3 - sage: s.data() - [1, 2, 3] - sage: s.is_constant() - True - - TESTS:: - - sage: l = [2,3,5,7,11,0] - sage: s = Stream(l) - sage: s.is_constant() - False - sage: s[3] - 7 - sage: s.is_constant() - False - sage: s[5] - 0 - sage: s.is_constant() - False - sage: s[6] - 0 - sage: s.is_constant() - True - - :: - - sage: s = Stream(const='I am constant.') - sage: s.is_constant() - True - """ - return self.end_reached - - - def stretch(self, k): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: s = Stream(range(1, 10)) - sage: s2 = s.stretch(2) - sage: [s2[i] for i in range(10)] - [1, 0, 2, 0, 3, 0, 4, 0, 5, 0] - """ - return Stream(self._stretch_gen(k)) - - def _stretch_gen(self, k): - """ - EXAMPLES:: - - sage: from sage.combinat.species.stream import Stream - sage: s = Stream(range(1, 10)) - sage: g = s._stretch_gen(2) - sage: [next(g) for i in range(10)] - [1, 0, 2, 0, 3, 0, 4, 0, 5, 0] - """ - yield self[0] - for i in _integers_from(1): - for j in range(k-1): - yield 0 - yield self[i] diff --git a/src/sage/combinat/species/structure.py b/src/sage/combinat/species/structure.py index bdd6f710600..b37f0837ded 100644 --- a/src/sage/combinat/species/structure.py +++ b/src/sage/combinat/species/structure.py @@ -390,7 +390,7 @@ def __iter__(self): try: if self.cardinality() == 0: return iter([]) - except RuntimeError: + except TypeError: raise NotImplementedError return getattr(self._species, self._iterator)(self._structure_class, self._labels) diff --git a/src/sage/combinat/species/subset_species.py b/src/sage/combinat/species/subset_species.py index 0a41c7dbc9a..763b8bc8053 100644 --- a/src/sage/combinat/species/subset_species.py +++ b/src/sage/combinat/species/subset_species.py @@ -19,7 +19,6 @@ from .species import GenericCombinatorialSpecies from .set_species import SetSpecies -from .generating_series import _integers_from from .structure import GenericSpeciesStructure from sage.combinat.species.misc import accept_size from sage.structure.unique_representation import UniqueRepresentation @@ -143,13 +142,13 @@ def __init__(self, min=None, max=None, weight=None): EXAMPLES:: sage: S = species.SubsetSpecies() - sage: S.generating_series().coefficients(5) + sage: S.generating_series()[0:5] [1, 2, 2, 4/3, 2/3] - sage: S.isotype_generating_series().coefficients(5) + sage: S.isotype_generating_series()[0:5] [1, 2, 3, 4, 5] sage: S = species.SubsetSpecies() - sage: c = S.generating_series().coefficients(3) + sage: c = S.generating_series()[0:3] sage: S._check() True sage: S == loads(dumps(S)) @@ -187,7 +186,7 @@ def _isotypes(self, structure_class, labels): for i in range(len(labels)+1): yield structure_class(self, labels, range(1, i+1)) - def _gs_iterator(self, base_ring): + def _gs_callable(self, base_ring, n): """ The generating series for the species of subsets is `e^{2x}`. @@ -195,13 +194,12 @@ def _gs_iterator(self, base_ring): EXAMPLES:: sage: S = species.SubsetSpecies() - sage: S.generating_series().coefficients(5) + sage: [S.generating_series().coefficient(i) for i in range(5)] [1, 2, 2, 4/3, 2/3] """ - for n in _integers_from(0): - yield base_ring(2)**n / base_ring(factorial(n)) + return base_ring(2)**n / base_ring(factorial(n)) - def _itgs_iterator(self, base_ring): + def _itgs_callable(self, base_ring, n): r""" The generating series for the species of subsets is `e^{2x}`. @@ -209,11 +207,10 @@ def _itgs_iterator(self, base_ring): EXAMPLES:: sage: S = species.SubsetSpecies() - sage: S.isotype_generating_series().coefficients(5) + sage: S.isotype_generating_series()[0:5] [1, 2, 3, 4, 5] """ - for n in _integers_from(1): - yield base_ring(n) + return base_ring(n + 1) def _cis(self, series_ring, base_ring): r""" @@ -226,7 +223,7 @@ def _cis(self, series_ring, base_ring): EXAMPLES:: sage: S = species.SubsetSpecies() - sage: S.cycle_index_series().coefficients(5) + sage: S.cycle_index_series()[0:5] [p[], 2*p[1], 2*p[1, 1] + p[2], diff --git a/src/sage/combinat/species/sum_species.py b/src/sage/combinat/species/sum_species.py index 05950420dbb..e6644bdfa29 100644 --- a/src/sage/combinat/species/sum_species.py +++ b/src/sage/combinat/species/sum_species.py @@ -32,7 +32,7 @@ def __init__(self, F, G, min=None, max=None, weight=None): sage: S = species.PermutationSpecies() sage: A = S+S - sage: A.generating_series().coefficients(5) + sage: A.generating_series()[:5] [2, 2, 2, 2, 2] sage: P = species.PermutationSpecies() @@ -142,13 +142,12 @@ def _gs(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F.generating_series().coefficients(5) + sage: F.generating_series()[:5] [2, 2, 2, 2, 2] """ return (self.left_summand().generating_series(base_ring) + self.right_summand().generating_series(base_ring)) - def _itgs(self, series_ring, base_ring): """ Returns the isomorphism type generating series of this species. @@ -157,7 +156,7 @@ def _itgs(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F.isotype_generating_series().coefficients(5) + sage: F.isotype_generating_series()[:5] [2, 2, 4, 6, 10] """ return (self.left_summand().isotype_generating_series(base_ring) + @@ -171,7 +170,7 @@ def _cis(self, series_ring, base_ring): sage: P = species.PermutationSpecies() sage: F = P + P - sage: F.cycle_index_series().coefficients(5) + sage: F.cycle_index_series()[:5] [2*p[], 2*p[1], 2*p[1, 1] + 2*p[2], diff --git a/src/sage/combinat/tutorial.py b/src/sage/combinat/tutorial.py index e9df13c746c..6422d920378 100644 --- a/src/sage/combinat/tutorial.py +++ b/src/sage/combinat/tutorial.py @@ -310,7 +310,7 @@ It is unfortunate to have to recalculate everything if at some point we wanted the 101-st coefficient. Lazy power series (see -:mod:`sage.combinat.species.series`) come into their own here, in that +:mod:`sage.rings.lazy_series_ring`) come into their own here, in that one can define them from a system of equations without solving it, and, in particular, without needing a closed form for the answer. We begin by defining the ring of lazy power series:: @@ -320,8 +320,7 @@ Then we create a “free” power series, which we name, and which we then define by a recursive equation:: - sage: C = L() - sage: C._name = 'C' + sage: C = L.undefined(valuation=1) sage: C.define( z + C * C ) :: @@ -1672,7 +1671,7 @@ We begin by redefining the complete binary trees; to do so, we stipulate the recurrence relation directly on the sets:: - sage: BT = CombinatorialSpecies() + sage: BT = CombinatorialSpecies(min=1) sage: Leaf = SingletonSpecies() sage: BT.define( Leaf + (BT*BT) ) @@ -1697,7 +1696,7 @@ We recover the generating function for the Catalan numbers:: sage: g = BT.isotype_generating_series(); g - x + x^2 + 2*x^3 + 5*x^4 + 14*x^5 + O(x^6) + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) which is returned in the form of a lazy power series:: @@ -1715,7 +1714,7 @@ The Fibonacci sequence is easily recognized here, hence the name:: - sage: L = FW.isotype_generating_series().coefficients(15); L + sage: L = FW.isotype_generating_series()[:15]; L [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987] :: diff --git a/src/sage/combinat/words/finite_word.py b/src/sage/combinat/words/finite_word.py index 5773491e025..7fc8d3b4b18 100644 --- a/src/sage/combinat/words/finite_word.py +++ b/src/sage/combinat/words/finite_word.py @@ -217,6 +217,7 @@ from itertools import repeat from collections import defaultdict from itertools import islice, cycle + from sage.combinat.words.abstract_word import Word_class from sage.combinat.words.words import Words from sage.misc.cachefunc import cached_method @@ -2622,7 +2623,7 @@ def palindromic_lacunas_study(self, f=None): and lacunas of ``self`` (see [BMBL2008]_ and [BMBFLR2008]_). Note that a word `w` has at most `|w| + 1` different palindromic factors - (see [DJP2001]_). For `f`-palindromes (or pseudopalidromes or theta-palindromes), + (see [DJP2001]_). For `f`-palindromes (or pseudopalindromes or theta-palindromes), the maximum number of `f`-palindromic factors is `|w|+1-g_f(w)`, where `g_f(w)` is the number of pairs `\{a, f(a)\}` such that `a` is a letter, `a` is not equal to `f(a)`, and `a` or `f(a)` occurs in `w`, see [Star2011]_. @@ -5949,7 +5950,6 @@ def sturmian_desubstitute_as_possible(self): desubstitued_word = desubstitued_word + w_running ** (current_run_length - min_run) return desubstitued_word.sturmian_desubstitute_as_possible() - def is_sturmian_factor(self): r""" Tell whether ``self`` is a factor of a Sturmian word. @@ -6010,7 +6010,6 @@ def is_sturmian_factor(self): """ return self.sturmian_desubstitute_as_possible().is_empty() - def is_tangent(self): r""" Tell whether ``self`` is a tangent word. @@ -6080,7 +6079,6 @@ def is_tangent(self): mini = min(mini , height) return (maxi - mini <= 2) - # TODO. # 1. Those three swap functions should use the cmp of python. # 2. The actual code should then be copied as is in the Word_over_Alphabet @@ -7175,7 +7173,6 @@ def minimal_conjugate(self): if end >= p.length(): return factor ** q -####################################################################### class CallableFromListOfWords(tuple): r""" @@ -7222,6 +7219,7 @@ def __call__(self, i): j -= c.length() raise IndexError("index (=%s) out of range" % i) + class Factorization(list): r""" A list subclass having a nicer representation for factorization of words. @@ -7245,6 +7243,7 @@ def __repr__(self): """ return '(%s)' % ', '.join(w.string_rep() for w in self) + ####################################################################### def evaluation_dict(w): @@ -7270,13 +7269,13 @@ def evaluation_dict(w): sage: evaluation_dict('1213121') # keys appear in random order {'1': 4, '2': 2, '3': 1} - """ d = defaultdict(int) for a in w: d[a] += 1 return dict(d) + def word_to_ordered_set_partition(w): r""" Return the ordered set partition corresponding to a finite diff --git a/src/sage/combinat/words/lyndon_word.py b/src/sage/combinat/words/lyndon_word.py index c006bb9588c..ca271c5a114 100644 --- a/src/sage/combinat/words/lyndon_word.py +++ b/src/sage/combinat/words/lyndon_word.py @@ -613,6 +613,7 @@ def standard_bracketing(lw): if lw[i:] in LyndonWords(): return [standard_bracketing(lw[:i]), standard_bracketing(lw[i:])] + def standard_unbracketing(sblw): """ Return flattened ``sblw`` if it is a standard bracketing of a Lyndon word, diff --git a/src/sage/combinat/words/paths.py b/src/sage/combinat/words/paths.py index 38f238aa945..3d0ee41a4c4 100644 --- a/src/sage/combinat/words/paths.py +++ b/src/sage/combinat/words/paths.py @@ -202,6 +202,7 @@ WordDatatype_callable) from sage.matrix.constructor import vector_on_axis_rotation_matrix + ####################################################################### # # # WordPaths function # @@ -348,10 +349,11 @@ def WordPaths(alphabet, steps=None): elif steps == 'dyck': return WordPaths_dyck(alphabet=alphabet) else: - raise TypeError("Unknown type of steps : %s"%steps) + raise TypeError("Unknown type of steps : %s" % steps) else: return WordPaths_all(alphabet=alphabet, steps=steps) + ####################################################################### # # # Combinatorial classes of word paths # @@ -608,6 +610,7 @@ def vector_space(self): """ return self._vector_space + class WordPaths_square_grid(WordPaths_all): r""" The combinatorial class of all paths on the square grid. @@ -676,6 +679,7 @@ def __repr__(self): """ return "Word Paths on the square grid" + class WordPaths_triangle_grid(WordPaths_all): r""" The combinatorial class of all paths on the triangle grid. @@ -755,6 +759,7 @@ def __repr__(self): """ return "Word Paths on the triangle grid" + class WordPaths_hexagonal_grid(WordPaths_triangle_grid): r""" The combinatorial class of all paths on the hexagonal grid. @@ -823,6 +828,7 @@ def __repr__(self): """ return "Word Paths on the hexagonal grid" + class WordPaths_cube_grid(WordPaths_all): r""" The combinatorial class of all paths on the cube grid. @@ -890,6 +896,7 @@ def __repr__(self): """ return "Word Paths on the cube grid" + class WordPaths_dyck(WordPaths_all): r""" The combinatorial class of all Dyck paths. @@ -957,6 +964,7 @@ def __repr__(self): """ return "Finite Dyck paths" + class WordPaths_north_east(WordPaths_all): r""" The combinatorial class of all paths using North and East directions. @@ -1024,6 +1032,7 @@ def __repr__(self): """ return "Word Paths in North and East steps" + ####################################################################### # # # Abstract word path classes # @@ -1476,6 +1485,7 @@ def is_tangent(self): """ raise NotImplementedError + class FiniteWordPath_2d(FiniteWordPath_all): def plot(self, pathoptions=dict(rgbcolor='red',thickness=3), fill=True, filloptions=dict(rgbcolor='red',alpha=0.2), @@ -2023,6 +2033,7 @@ def plot(self, pathoptions=dict(rgbcolor='red',arrow_head=True,thickness=3), G += line(pts, **pathoptions) return G + ####################################################################### # # # Abstract word path classes # @@ -2208,7 +2219,8 @@ def tikz_trajectory(self): sage: f.tikz_trajectory() '(0, 0) -- (0, -1) -- (-1, -1) -- (-1, -2) -- (0, -2) -- (0, -3) -- (1, -3) -- (1, -2) -- (2, -2) -- (2, -1) -- (1, -1) -- (1, 0) -- (0, 0)' """ - return ' -- '.join(map(str,self.points())) + return ' -- '.join(map(str, self.points())) + class FiniteWordPath_triangle_grid(FiniteWordPath_2d): # Triangle grid paths are implemented with quadratic fields, @@ -2285,7 +2297,7 @@ def ymax(self): return max(RR(y) for (_,y) in self.points()) -#TODO: faire une verification du mot pour etre sur hexagonal grid +# TODO: faire une verification du mot pour etre sur hexagonal grid class FiniteWordPath_hexagonal_grid(FiniteWordPath_triangle_grid): def __init__(self, parent, *args, **kwds): r""" @@ -2310,15 +2322,19 @@ def __init__(self, parent, *args, **kwds): """ super().__init__(parent, *args, **kwds) + class FiniteWordPath_cube_grid(FiniteWordPath_3d): pass + class FiniteWordPath_north_east(FiniteWordPath_2d): pass + class FiniteWordPath_dyck(FiniteWordPath_2d): pass + ####################################################################### # # # Concrete word path classes # @@ -2345,6 +2361,7 @@ class FiniteWordPath_all_list(WordDatatype_list, FiniteWordPath_all, FiniteWord_ """ pass + class FiniteWordPath_all_str(WordDatatype_str, FiniteWordPath_all, FiniteWord_class): r""" TESTS:: @@ -2359,6 +2376,7 @@ class FiniteWordPath_all_str(WordDatatype_str, FiniteWordPath_all, FiniteWord_cl """ pass + class FiniteWordPath_all_tuple(WordDatatype_tuple, FiniteWordPath_all, FiniteWord_class): r""" TESTS:: @@ -2373,18 +2391,23 @@ class FiniteWordPath_all_tuple(WordDatatype_tuple, FiniteWordPath_all, FiniteWor """ pass + class FiniteWordPath_all_iter_with_caching(WordDatatype_iter_with_caching, FiniteWordPath_all, FiniteWord_class): pass + class FiniteWordPath_all_iter(WordDatatype_iter, FiniteWordPath_all, FiniteWord_class): pass + class FiniteWordPath_all_callable_with_caching(WordDatatype_callable_with_caching, FiniteWordPath_all, FiniteWord_class): pass + class FiniteWordPath_all_callable(WordDatatype_callable, FiniteWordPath_all, FiniteWord_class): pass + ##### Finite paths on 2d ##### class FiniteWordPath_2d_list(WordDatatype_list, FiniteWordPath_2d, FiniteWord_class): @@ -2401,6 +2424,7 @@ class FiniteWordPath_2d_list(WordDatatype_list, FiniteWordPath_2d, FiniteWord_cl """ pass + class FiniteWordPath_2d_str(WordDatatype_str, FiniteWordPath_2d, FiniteWord_class): r""" TESTS:: @@ -2415,6 +2439,7 @@ class FiniteWordPath_2d_str(WordDatatype_str, FiniteWordPath_2d, FiniteWord_clas """ pass + class FiniteWordPath_2d_tuple(WordDatatype_tuple, FiniteWordPath_2d, FiniteWord_class): r""" TESTS:: @@ -2429,18 +2454,23 @@ class FiniteWordPath_2d_tuple(WordDatatype_tuple, FiniteWordPath_2d, FiniteWord_ """ pass + class FiniteWordPath_2d_iter_with_caching(WordDatatype_iter_with_caching, FiniteWordPath_2d, FiniteWord_class): pass + class FiniteWordPath_2d_iter(WordDatatype_iter, FiniteWordPath_2d, FiniteWord_class): pass + class FiniteWordPath_2d_callable_with_caching(WordDatatype_callable_with_caching, FiniteWordPath_2d, FiniteWord_class): pass + class FiniteWordPath_2d_callable(WordDatatype_callable, FiniteWordPath_2d, FiniteWord_class): pass + ##### Finite paths on 3d ##### class FiniteWordPath_3d_list(WordDatatype_list, FiniteWordPath_3d, FiniteWord_class): @@ -2457,6 +2487,7 @@ class FiniteWordPath_3d_list(WordDatatype_list, FiniteWordPath_3d, FiniteWord_cl """ pass + class FiniteWordPath_3d_str(WordDatatype_str, FiniteWordPath_3d, FiniteWord_class): r""" TESTS:: @@ -2471,6 +2502,7 @@ class FiniteWordPath_3d_str(WordDatatype_str, FiniteWordPath_3d, FiniteWord_clas """ pass + class FiniteWordPath_3d_tuple(WordDatatype_tuple, FiniteWordPath_3d, FiniteWord_class): r""" TESTS:: @@ -2485,18 +2517,23 @@ class FiniteWordPath_3d_tuple(WordDatatype_tuple, FiniteWordPath_3d, FiniteWord_ """ pass + class FiniteWordPath_3d_iter_with_caching(WordDatatype_iter_with_caching, FiniteWordPath_3d, FiniteWord_class): pass + class FiniteWordPath_3d_iter(WordDatatype_iter, FiniteWordPath_3d, FiniteWord_class): pass + class FiniteWordPath_3d_callable_with_caching(WordDatatype_callable_with_caching, FiniteWordPath_3d, FiniteWord_class): pass + class FiniteWordPath_3d_callable(WordDatatype_callable, FiniteWordPath_3d, FiniteWord_class): pass + ##### Finite paths on square grid ##### class FiniteWordPath_square_grid_list(WordDatatype_list, FiniteWordPath_square_grid, FiniteWord_class): @@ -2513,6 +2550,7 @@ class FiniteWordPath_square_grid_list(WordDatatype_list, FiniteWordPath_square_g """ pass + class FiniteWordPath_square_grid_str(WordDatatype_str, FiniteWordPath_square_grid, FiniteWord_class): r""" TESTS:: @@ -2527,6 +2565,7 @@ class FiniteWordPath_square_grid_str(WordDatatype_str, FiniteWordPath_square_gri """ pass + class FiniteWordPath_square_grid_tuple(WordDatatype_tuple, FiniteWordPath_square_grid, FiniteWord_class): r""" TESTS:: @@ -2541,18 +2580,23 @@ class FiniteWordPath_square_grid_tuple(WordDatatype_tuple, FiniteWordPath_square """ pass + class FiniteWordPath_square_grid_iter_with_caching(WordDatatype_iter_with_caching, FiniteWordPath_square_grid, FiniteWord_class): pass + class FiniteWordPath_square_grid_iter(WordDatatype_iter, FiniteWordPath_square_grid, FiniteWord_class): pass + class FiniteWordPath_square_grid_callable_with_caching(WordDatatype_callable_with_caching, FiniteWordPath_square_grid, FiniteWord_class): pass + class FiniteWordPath_square_grid_callable(WordDatatype_callable, FiniteWordPath_square_grid, FiniteWord_class): pass + ##### Unknown length paths on square grid (experimental) ##### #class WordPath_square_grid_iter_with_caching(WordDatatype_iter_with_caching, FiniteWordPath_square_grid, Word_class): @@ -2574,6 +2618,7 @@ class FiniteWordPath_triangle_grid_list(WordDatatype_list, FiniteWordPath_triang """ pass + class FiniteWordPath_triangle_grid_str(WordDatatype_str, FiniteWordPath_triangle_grid, FiniteWord_class): r""" TESTS:: @@ -2588,6 +2633,7 @@ class FiniteWordPath_triangle_grid_str(WordDatatype_str, FiniteWordPath_triangle """ pass + class FiniteWordPath_triangle_grid_tuple(WordDatatype_tuple, FiniteWordPath_triangle_grid, FiniteWord_class): r""" TESTS:: @@ -2602,18 +2648,23 @@ class FiniteWordPath_triangle_grid_tuple(WordDatatype_tuple, FiniteWordPath_tria """ pass + class FiniteWordPath_triangle_grid_iter_with_caching(WordDatatype_iter_with_caching, FiniteWordPath_triangle_grid, FiniteWord_class): pass + class FiniteWordPath_triangle_grid_iter(WordDatatype_iter, FiniteWordPath_triangle_grid, FiniteWord_class): pass + class FiniteWordPath_triangle_grid_callable_with_caching(WordDatatype_callable_with_caching, FiniteWordPath_triangle_grid, FiniteWord_class): pass + class FiniteWordPath_triangle_grid_callable(WordDatatype_callable, FiniteWordPath_triangle_grid, FiniteWord_class): pass + ##### Finite paths on hexagonal grid ##### class FiniteWordPath_hexagonal_grid_list(WordDatatype_list, FiniteWordPath_hexagonal_grid, FiniteWord_class): @@ -2630,6 +2681,7 @@ class FiniteWordPath_hexagonal_grid_list(WordDatatype_list, FiniteWordPath_hexag """ pass + class FiniteWordPath_hexagonal_grid_str(WordDatatype_str, FiniteWordPath_hexagonal_grid, FiniteWord_class): r""" TESTS:: @@ -2644,6 +2696,7 @@ class FiniteWordPath_hexagonal_grid_str(WordDatatype_str, FiniteWordPath_hexagon """ pass + class FiniteWordPath_hexagonal_grid_tuple(WordDatatype_tuple, FiniteWordPath_hexagonal_grid, FiniteWord_class): r""" TESTS:: @@ -2658,18 +2711,23 @@ class FiniteWordPath_hexagonal_grid_tuple(WordDatatype_tuple, FiniteWordPath_hex """ pass + class FiniteWordPath_hexagonal_grid_iter_with_caching(WordDatatype_iter_with_caching, FiniteWordPath_hexagonal_grid, FiniteWord_class): pass + class FiniteWordPath_hexagonal_grid_iter(WordDatatype_iter, FiniteWordPath_hexagonal_grid, FiniteWord_class): pass + class FiniteWordPath_hexagonal_grid_callable_with_caching(WordDatatype_callable_with_caching, FiniteWordPath_hexagonal_grid, FiniteWord_class): pass + class FiniteWordPath_hexagonal_grid_callable(WordDatatype_callable, FiniteWordPath_hexagonal_grid, FiniteWord_class): pass + ##### Finite paths on cube grid ##### class FiniteWordPath_cube_grid_list(WordDatatype_list, FiniteWordPath_cube_grid, FiniteWord_class): @@ -2686,6 +2744,7 @@ class FiniteWordPath_cube_grid_list(WordDatatype_list, FiniteWordPath_cube_grid, """ pass + class FiniteWordPath_cube_grid_str(WordDatatype_str, FiniteWordPath_cube_grid, FiniteWord_class): r""" TESTS:: @@ -2700,6 +2759,7 @@ class FiniteWordPath_cube_grid_str(WordDatatype_str, FiniteWordPath_cube_grid, F """ pass + class FiniteWordPath_cube_grid_tuple(WordDatatype_tuple, FiniteWordPath_cube_grid, FiniteWord_class): r""" TESTS:: @@ -2714,18 +2774,23 @@ class FiniteWordPath_cube_grid_tuple(WordDatatype_tuple, FiniteWordPath_cube_gri """ pass + class FiniteWordPath_cube_grid_iter_with_caching(WordDatatype_iter_with_caching, FiniteWordPath_cube_grid, FiniteWord_class): pass + class FiniteWordPath_cube_grid_iter(WordDatatype_iter, FiniteWordPath_cube_grid, FiniteWord_class): pass + class FiniteWordPath_cube_grid_callable_with_caching(WordDatatype_callable_with_caching, FiniteWordPath_cube_grid, FiniteWord_class): pass + class FiniteWordPath_cube_grid_callable(WordDatatype_callable, FiniteWordPath_cube_grid, FiniteWord_class): pass + ##### Finite paths on north_east ##### class FiniteWordPath_north_east_list(WordDatatype_list, FiniteWordPath_north_east, FiniteWord_class): @@ -2742,6 +2807,7 @@ class FiniteWordPath_north_east_list(WordDatatype_list, FiniteWordPath_north_eas """ pass + class FiniteWordPath_north_east_str(WordDatatype_str, FiniteWordPath_north_east, FiniteWord_class): r""" TESTS:: @@ -2756,6 +2822,7 @@ class FiniteWordPath_north_east_str(WordDatatype_str, FiniteWordPath_north_east, """ pass + class FiniteWordPath_north_east_tuple(WordDatatype_tuple, FiniteWordPath_north_east, FiniteWord_class): r""" TESTS:: @@ -2770,18 +2837,23 @@ class FiniteWordPath_north_east_tuple(WordDatatype_tuple, FiniteWordPath_north_e """ pass + class FiniteWordPath_north_east_iter_with_caching(WordDatatype_iter_with_caching, FiniteWordPath_north_east, FiniteWord_class): pass + class FiniteWordPath_north_east_iter(WordDatatype_iter, FiniteWordPath_north_east, FiniteWord_class): pass + class FiniteWordPath_north_east_callable_with_caching(WordDatatype_callable_with_caching, FiniteWordPath_north_east, FiniteWord_class): pass + class FiniteWordPath_north_east_callable(WordDatatype_callable, FiniteWordPath_north_east, FiniteWord_class): pass + ##### Finite paths on dyck ##### class FiniteWordPath_dyck_list(WordDatatype_list, FiniteWordPath_dyck, FiniteWord_class): @@ -2798,6 +2870,7 @@ class FiniteWordPath_dyck_list(WordDatatype_list, FiniteWordPath_dyck, FiniteWor """ pass + class FiniteWordPath_dyck_str(WordDatatype_str, FiniteWordPath_dyck, FiniteWord_class): r""" TESTS:: @@ -2812,6 +2885,7 @@ class FiniteWordPath_dyck_str(WordDatatype_str, FiniteWordPath_dyck, FiniteWord_ """ pass + class FiniteWordPath_dyck_tuple(WordDatatype_tuple, FiniteWordPath_dyck, FiniteWord_class): r""" TESTS:: @@ -2826,14 +2900,18 @@ class FiniteWordPath_dyck_tuple(WordDatatype_tuple, FiniteWordPath_dyck, FiniteW """ pass + class FiniteWordPath_dyck_iter_with_caching(WordDatatype_iter_with_caching, FiniteWordPath_dyck, FiniteWord_class): pass + class FiniteWordPath_dyck_iter(WordDatatype_iter, FiniteWordPath_dyck, FiniteWord_class): pass + class FiniteWordPath_dyck_callable_with_caching(WordDatatype_callable_with_caching, FiniteWordPath_dyck, FiniteWord_class): pass + class FiniteWordPath_dyck_callable(WordDatatype_callable, FiniteWordPath_dyck, FiniteWord_class): pass diff --git a/src/sage/combinat/words/word.py b/src/sage/combinat/words/word.py index 85974ec33e7..051d0a1a702 100644 --- a/src/sage/combinat/words/word.py +++ b/src/sage/combinat/words/word.py @@ -41,6 +41,7 @@ # TODO. Word needs to be replaced by Word. Consider renaming # Word_class to Word and imbedding Word as its __call__ method. + def Word(data=None, alphabet=None, length=None, datatype=None, caching=True, RSK_data=None): r""" Construct a word. @@ -218,6 +219,7 @@ def Word(data=None, alphabet=None, length=None, datatype=None, caching=True, RSK ##### Finite Words ##### + class FiniteWord_char(WordDatatype_char, FiniteWord_class): r""" Finite word represented by an array ``unsigned char *`` (i.e. integers @@ -279,11 +281,12 @@ class FiniteWord_char(WordDatatype_char, FiniteWord_class): """ pass + class FiniteWord_list(WordDatatype_list, FiniteWord_class): r""" Finite word represented by a Python list. - For any word `w`, type ``w.`` and hit TAB key to see the list of + For any word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. EXAMPLES:: @@ -300,11 +303,12 @@ class FiniteWord_list(WordDatatype_list, FiniteWord_class): """ pass + class FiniteWord_str(WordDatatype_str, FiniteWord_class): r""" Finite word represented by a Python str. - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. EXAMPLES:: @@ -321,11 +325,12 @@ class FiniteWord_str(WordDatatype_str, FiniteWord_class): """ pass + class FiniteWord_tuple(WordDatatype_tuple, FiniteWord_class): r""" Finite word represented by a Python tuple. - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. EXAMPLES:: @@ -342,11 +347,12 @@ class FiniteWord_tuple(WordDatatype_tuple, FiniteWord_class): """ pass + class FiniteWord_iter_with_caching(WordDatatype_iter_with_caching, FiniteWord_class): r""" Finite word represented by an iterator (with caching). - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. EXAMPLES:: @@ -368,11 +374,12 @@ class FiniteWord_iter_with_caching(WordDatatype_iter_with_caching, FiniteWord_cl """ pass + class FiniteWord_iter(WordDatatype_iter, FiniteWord_class): r""" Finite word represented by an iterator. - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. EXAMPLES:: @@ -396,11 +403,12 @@ class FiniteWord_iter(WordDatatype_iter, FiniteWord_class): """ pass + class FiniteWord_callable_with_caching(WordDatatype_callable_with_caching, FiniteWord_class): r""" Finite word represented by a callable (with caching). - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. EXAMPLES:: @@ -447,11 +455,12 @@ class FiniteWord_callable_with_caching(WordDatatype_callable_with_caching, Finit """ pass + class FiniteWord_callable(WordDatatype_callable, FiniteWord_class): r""" Finite word represented by a callable. - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. EXAMPLES:: @@ -476,13 +485,14 @@ class FiniteWord_callable(WordDatatype_callable, FiniteWord_class): """ pass + ##### Infinite Words ##### class InfiniteWord_iter_with_caching(WordDatatype_iter_with_caching, InfiniteWord_class): r""" Infinite word represented by an iterable (with caching). - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. Infinite words behave like a Python list : they can be sliced using @@ -516,11 +526,12 @@ class InfiniteWord_iter_with_caching(WordDatatype_iter_with_caching, InfiniteWor """ pass + class InfiniteWord_iter(WordDatatype_iter, InfiniteWord_class): r""" Infinite word represented by an iterable. - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. Infinite words behave like a Python list : they can be sliced using @@ -554,11 +565,12 @@ class InfiniteWord_iter(WordDatatype_iter, InfiniteWord_class): """ pass + class InfiniteWord_callable_with_caching(WordDatatype_callable_with_caching, InfiniteWord_class): r""" Infinite word represented by a callable (with caching). - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. Infinite words behave like a Python list : they can be sliced using @@ -584,11 +596,12 @@ class InfiniteWord_callable_with_caching(WordDatatype_callable_with_caching, Inf """ pass + class InfiniteWord_callable(WordDatatype_callable, InfiniteWord_class): r""" Infinite word represented by a callable. - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. Infinite words behave like a Python list : they can be sliced using @@ -615,6 +628,7 @@ class InfiniteWord_callable(WordDatatype_callable, InfiniteWord_class): """ pass + ##### Words of unknown length ##### class Word_iter_with_caching(WordDatatype_iter_with_caching, Word_class): @@ -622,7 +636,7 @@ class Word_iter_with_caching(WordDatatype_iter_with_caching, Word_class): Word of unknown length (finite or infinite) represented by an iterable (with caching). - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. Words behave like a Python list : they can be sliced using @@ -653,12 +667,13 @@ class Word_iter_with_caching(WordDatatype_iter_with_caching, Word_class): """ pass + class Word_iter(WordDatatype_iter, Word_class): r""" Word of unknown length (finite or infinite) represented by an iterable. - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. Words behave like a Python list : they can be sliced using @@ -689,12 +704,14 @@ class Word_iter(WordDatatype_iter, Word_class): """ pass + ##### Morphic Words ##### + class FiniteWord_morphic(WordDatatype_morphic, FiniteWord_class): r""" Finite morphic word. - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. EXAMPLES:: @@ -713,15 +730,15 @@ class FiniteWord_morphic(WordDatatype_morphic, FiniteWord_class): sage: loads(dumps(w)) word: ab - """ pass + class InfiniteWord_morphic(WordDatatype_morphic, InfiniteWord_class): r""" Morphic word of infinite length. - For such word `w`, type ``w.`` and hit TAB key to see the list of + For such word `w`, type ``w.`` and hit :kbd:`Tab` key to see the list of functions defined on `w`. Infinite words behave like a Python list : they can be sliced using @@ -740,6 +757,5 @@ class InfiniteWord_morphic(WordDatatype_morphic, InfiniteWord_class): sage: loads(dumps(w)) word: abaababaabaababaababaabaababaabaababaaba... - """ pass diff --git a/src/sage/combinat/words/word_generators.py b/src/sage/combinat/words/word_generators.py index e7110609d63..b485205878f 100644 --- a/src/sage/combinat/words/word_generators.py +++ b/src/sage/combinat/words/word_generators.py @@ -5,16 +5,16 @@ AUTHORS: - Franco Saliola (2008-12-17): merged into sage -- Sebastien Labbe (2008-12-17): merged into sage +- Sébastien Labbé (2008-12-17): merged into sage - Arnaud Bergeron (2008-12-17): merged into sage - Amy Glen (2008-12-17): merged into sage - Sébastien Labbé (2009-12-19): Added S-adic words (:trac:`7543`) USE: -To see a list of all word constructors, type ``words.`` and then press the tab -key. The documentation for each constructor includes information about each -word, which provides a useful reference. +To see a list of all word constructors, type ``words.`` and then press +the :kbd:`Tab` key. The documentation for each constructor includes +information about each word, which provides a useful reference. REFERENCES: @@ -22,11 +22,11 @@ numbers with a regular expansion, J. Number Theory 103 (2003) 27--37. -.. [BmBGL07] \A. Blondin-Masse, S. Brlek, A. Glen, and S. Labbe. On the +.. [BmBGL07] \A. Blondin-Massé, S. Brlek, A. Glen, and S. Labbé. On the critical exponent of generalized Thue-Morse words. *Discrete Math. Theor. Comput. Sci.* 9 (1):293--304, 2007. -.. [BmBGL09] \A. Blondin-Masse, S. Brlek, A. Garon, and S. Labbe. Christoffel +.. [BmBGL09] \A. Blondin-Massé, S. Brlek, A. Garon, and S. Labbé. Christoffel and Fibonacci Tiles, DGCI 2009, Montreal, to appear in LNCS. .. [Loth02] \M. Lothaire, Algebraic Combinatorics On Words, vol. 90 of @@ -104,6 +104,7 @@ def _build_tab(sym, tab, W): res.append((w[-1] % c) + 1) return res + class LowerChristoffelWord(FiniteWord_list): r""" Returns the lower Christoffel word of slope `p/q`, where `p` and @@ -310,6 +311,7 @@ def __reduce__(self): """ return self.__class__, (self.__p, self.__q, self.parent().alphabet()) + class WordGenerator(): r""" Constructor of several famous words. @@ -351,7 +353,7 @@ class WordGenerator(): .. NOTE:: To see a list of all word constructors, type ``words.`` and then - hit the TAB key. The documentation for each constructor + hit the :kbd:`Tab` key. The documentation for each constructor includes information about each word, which provides a useful reference. @@ -1275,7 +1277,7 @@ def StandardEpisturmianWord(self, directive_word): if not isinstance(directive_word, Word_class): raise TypeError("directive_word is not a word, so it cannot be used to build an episturmian word") epistandard = directive_word.parent()(\ - self._StandardEpisturmianWord_LetterIterator(directive_word), \ + self._StandardEpisturmianWord_LetterIterator(directive_word), datatype='iter') return epistandard @@ -2042,4 +2044,5 @@ def BaumSweetWord(self): inner = WordMorphism('a->aa,b->cb,c->ba,d->db') return outer(inner.fixed_point('d')) + words = WordGenerator() diff --git a/src/sage/combinat/words/word_infinite_datatypes.py b/src/sage/combinat/words/word_infinite_datatypes.py index 90ab35efd84..defef1e84d1 100644 --- a/src/sage/combinat/words/word_infinite_datatypes.py +++ b/src/sage/combinat/words/word_infinite_datatypes.py @@ -244,13 +244,13 @@ def __getitem__(self, key): if step > 0: start = 0 if key.start is None else key.start length = self._len if key.stop is None else \ - int(max(0,ceil((key.stop-start)/float(step)))) + int(max(0, ceil((key.stop-start)/float(step)))) else: if key.start is None or key.start < 0: raise ValueError("start value must be nonnegative for negative step values") start = key.start stop = 0 if key.stop is None else key.stop - length = int(max(0,ceil((key.stop-start)/float(step)))) + length = int(max(0, ceil((key.stop-start)/float(step)))) fcn = lambda x: self._func(start + x*step) if length is None: return self._parent(fcn, length=length) @@ -270,7 +270,7 @@ def __getitem__(self, key): else: start, stop, step = slice(key.start, key.stop, step).indices(self._len) - length = int(max(0,ceil((stop-start)/float(step)))) + length = int(max(0, ceil((stop-start)/float(step)))) fcn = lambda x: self._func(start + x*step) return self._parent(fcn, length=length) else: @@ -313,6 +313,7 @@ def __reduce__(self): else: return self._parent, (s, 'pickled_function', False) + class WordDatatype_callable_with_caching(WordDatatype_callable): r""" Datatype for a word defined by a callable. @@ -581,6 +582,7 @@ def flush(self): """ self._letter_cache = {} + class WordDatatype_iter(WordDatatype): # NOTE: The constructor callable should do all the slicing (see islice) def __init__(self, parent, iter, length=None): @@ -839,7 +841,7 @@ def __getitem__(self, key): length = Infinity stop = None else: # key.stop > 0 - length = int(max(0,ceil((key.stop-start)/float(step)))) + length = int(max(0, ceil((key.stop-start)/float(step)))) stop = int(key.stop) data = itertools.islice(self, start, stop, step) else: @@ -847,7 +849,7 @@ def __getitem__(self, key): raise ValueError("start value must be nonnegative for negative step values") start = int(key.start) stop = 0 if key.stop is None else int(key.stop) - length = int(max(0,ceil((stop-start)/float(step)))) + length = int(max(0, ceil((stop-start)/float(step)))) data = list(itertools.islice(self, start+1))[key] if length is None or length is Infinity: @@ -872,7 +874,7 @@ def __getitem__(self, key): length = None else: # start >= 0, step >= 1, stop >= 0 or None data = itertools.islice(self, start, stop, step) - length = "unknown" if stop is None else int(max(0,((stop-start)/float(step)))) + length = "unknown" if stop is None else int(max(0, ((stop-start)/float(step)))) return self._parent.factors()(data, length=length) else: @@ -912,8 +914,8 @@ def __reduce__(self): """ if self.is_finite(): return self._parent, (list(self),) - else: - return self._parent, (iter(self), 'iter', False) + return self._parent, (iter(self), 'iter', False) + class WordDatatype_iter_with_caching(WordDatatype_iter): def __init__(self, parent, iter, length=None): diff --git a/src/sage/combinat/words/word_options.py b/src/sage/combinat/words/word_options.py index e49946a9deb..2d2bf3bc7ff 100644 --- a/src/sage/combinat/words/word_options.py +++ b/src/sage/combinat/words/word_options.py @@ -1,27 +1,26 @@ r""" User-customizable options for words """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Franco Saliola # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import copy from sage.rings.integer import Integer -word_options = {\ - 'identifier':'word: ', \ - 'display':'string', \ - 'truncate':True, \ - 'truncate_length':40, \ - 'letter_separator':',', \ - 'cache':True, \ - 'old_repr':False \ - } +word_options = {'identifier': 'word: ', + 'display': 'string', + 'truncate': True, + 'truncate_length': 40, + 'letter_separator': ',', + 'cache': True, + 'old_repr': False} + def WordOptions(**kwargs): """ @@ -73,7 +72,7 @@ def WordOptions(**kwargs): else: word_options['truncate'] = kwargs['truncate'] elif 'truncate_length' in kwargs: - if not isinstance(kwargs['truncate_length'], (int,Integer)) or kwargs['truncate_length'] <= 0: + if not isinstance(kwargs['truncate_length'], (int, Integer)) or kwargs['truncate_length'] <= 0: raise ValueError("truncate_length must be a positive integer") else: word_options['truncate_length'] = kwargs['truncate_length'] diff --git a/src/sage/crypto/block_cipher/present.py b/src/sage/crypto/block_cipher/present.py index 4cbb74fc241..1774e6d5977 100644 --- a/src/sage/crypto/block_cipher/present.py +++ b/src/sage/crypto/block_cipher/present.py @@ -838,7 +838,7 @@ def __getitem__(self, r): Computes the sub key for round ``r`` derived from initial master key. The key schedule object has to have been initialised with the - `master_key` argument. + ``master_key`` argument. INPUT: @@ -860,7 +860,7 @@ def __getitem__(self, r): def __iter__(self): """ Iterate over the ``self._rounds + 1`` PRESENT round keys, derived from - `master_key` + ``master_key``. EXAMPLES:: diff --git a/src/sage/crypto/boolean_function.pyx b/src/sage/crypto/boolean_function.pyx index 887afd683fd..1584ca252ac 100644 --- a/src/sage/crypto/boolean_function.pyx +++ b/src/sage/crypto/boolean_function.pyx @@ -1464,4 +1464,3 @@ def random_boolean_function(n): sig_check() T.bits[i] = r.randrange(0,Integer(1)<<(sizeof(unsigned long)*8)) return B - diff --git a/src/sage/crypto/sbox.pyx b/src/sage/crypto/sbox.pyx index 6e08ba3501c..77b7a904cc2 100644 --- a/src/sage/crypto/sbox.pyx +++ b/src/sage/crypto/sbox.pyx @@ -2030,4 +2030,3 @@ def misty_construction(*args): 64 """ return sbox_construction(misty_substitute, list(args)) - diff --git a/src/sage/data_structures/binary_search.pyx b/src/sage/data_structures/binary_search.pyx index 030d50266e5..a53061c3efb 100644 --- a/src/sage/data_structures/binary_search.pyx +++ b/src/sage/data_structures/binary_search.pyx @@ -63,4 +63,3 @@ cdef Py_ssize_t binary_search0(Py_ssize_t* v, Py_ssize_t n, Py_ssize_t x): else: # only possibility is that v[k] == x return k return -1 - diff --git a/src/sage/data_structures/blas_dict.pyx b/src/sage/data_structures/blas_dict.pyx index 55364880150..df6bf29641e 100644 --- a/src/sage/data_structures/blas_dict.pyx +++ b/src/sage/data_structures/blas_dict.pyx @@ -448,4 +448,3 @@ cpdef dict convert_remove_zeroes(dict D, R): for index in for_removal: del D[index] return D - diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index e349708c1ed..d8d780dbca4 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -21,10 +21,10 @@ example, we can add two streams:: sage: from sage.data_structures.stream import * - sage: f = Stream_function(lambda n: n, QQ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) sage: [f[i] for i in range(10)] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - sage: g = Stream_function(lambda n: 1, QQ, True, 0) + sage: g = Stream_function(lambda n: 1, True, 0) sage: [g[i] for i in range(10)] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] sage: h = Stream_add(f, g) @@ -52,7 +52,7 @@ Two streams can be composed:: - sage: g = Stream_function(lambda n: n, QQ, True, 1) + sage: g = Stream_function(lambda n: n, True, 1) sage: h = Stream_cauchy_compose(f, g) sage: [h[i] for i in range(10)] [0, 1, 4, 14, 46, 145, 444, 1331, 3926, 11434] @@ -71,7 +71,7 @@ Finally, we can apply an arbitrary functions to the elements of a stream:: - sage: h = Stream_map_coefficients(f, lambda n: n^2, QQ) + sage: h = Stream_map_coefficients(f, lambda n: n^2) sage: [h[i] for i in range(10)] [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] @@ -80,7 +80,6 @@ - Kwankyu Lee (2019-02-24): initial version - Tejasvi Chebrolu, Martin Rubey, Travis Scrimshaw (2021-08): refactored and expanded functionality - """ # **************************************************************************** @@ -98,7 +97,12 @@ from sage.rings.integer_ring import ZZ from sage.rings.infinity import infinity from sage.arith.misc import divisors +from sage.misc.misc_c import prod +from sage.misc.lazy_attribute import lazy_attribute from sage.combinat.integer_vector_weighted import iterator_fast as wt_int_vec_iter +from sage.combinat.sf.sfa import _variables_recursive, _raise_variables +from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis + class Stream(): """ @@ -107,10 +111,29 @@ class Stream(): INPUT: - ``sparse`` -- boolean; whether the implementation of the stream is sparse - - ``approximate_order`` -- integer; a lower bound for the order - of the stream + - ``true_order`` -- boolean; if the approximate order is the actual order + + .. NOTE:: + + An implementation of a stream class depending on other stream + classes must not access coefficients or the approximate order + of these, in order not to interfere with lazy definitions for + :class:`Stream_uninitialized`. + + If an approximate order or even the true order is known, it + must be set after calling ``super().__init__``. + + Otherwise, a lazy attribute `_approximate_order` has to be + defined. Any initialization code depending on the + approximate orders of input streams can be put into this + definition. + + However, keep in mind that (trivially) this initialization + code is not executed if `_approximate_order` is set to a + value before it is accessed. + """ - def __init__(self, sparse, approximate_order): + def __init__(self, sparse, true_order): """ Initialize ``self``. @@ -120,7 +143,21 @@ def __init__(self, sparse, approximate_order): sage: CS = Stream(True, 1) """ self._is_sparse = sparse - self._approximate_order = approximate_order + self._true_order = true_order + + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_exact + sage: f = Stream_exact([0,3], True) + sage: f._approximate_order + 1 + """ + raise NotImplementedError def __ne__(self, other): """ @@ -137,7 +174,6 @@ def __ne__(self, other): False sage: CS != Stream(False, -2) False - """ return False @@ -168,29 +204,58 @@ class Stream_inexact(Stream): - ``sparse`` -- boolean; whether the implementation of the stream is sparse - ``approximate_order`` -- integer; a lower bound for the order of the stream + + .. TODO:: + + The ``approximate_order`` is currently only updated when + invoking :meth:`order`. It might make sense to update it + whenever the coefficient one larger than the current + ``approximate_order`` is computed, since in some methods this + will allow shortcuts. + """ - def __init__(self, is_sparse, approximate_order): + def __init__(self, is_sparse, true_order): """ - Initialize the stream class for a Stream when it is not - or it cannot be determined if it is eventually geometric. + Initialize the stream class for a stream whose + coefficients are not necessarily eventually constant. TESTS:: sage: from sage.data_structures.stream import Stream_inexact sage: from sage.data_structures.stream import Stream_function - sage: g = Stream_function(lambda n: n, QQ, False, 0) + sage: g = Stream_function(lambda n: n, False, 0) sage: isinstance(g, Stream_inexact) True - """ - super().__init__(is_sparse, approximate_order) + """ + super().__init__(is_sparse, true_order) if self._is_sparse: self._cache = dict() # cache of known coefficients else: self._cache = list() - self._offset = approximate_order self._iter = self.iterate_coefficients() + @lazy_attribute + def _offset(self): + """ + Return the offset of a stream with a dense cache. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function + sage: f = Stream_function(lambda n: n, False, -3) + sage: f._offset + -3 + sage: [f[i] for i in range(-3, 5)] + [-3, -2, -1, 0, 1, 2, 3, 4] + sage: f._cache + [-3, -2, -1, 0, 1, 2, 3, 4] + """ + # self[n] = self._cache[n-self._offset] + if self._is_sparse: + raise ValueError("_offset is only for dense streams") + return self._approximate_order + def is_nonzero(self): r""" Return ``True`` if and only if the cache contains a nonzero element. @@ -198,7 +263,7 @@ def is_nonzero(self): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function - sage: CS = Stream_function(lambda n: 1/n, ZZ, False, 1) + sage: CS = Stream_function(lambda n: 1/n, False, 1) sage: CS.is_nonzero() False sage: CS[1] @@ -291,7 +356,7 @@ def __getitem__(self, n): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n^2, QQ, True, 0) + sage: f = Stream_function(lambda n: n^2, True, 0) sage: f[3] 9 sage: f._cache @@ -301,7 +366,7 @@ def __getitem__(self, n): sage: f._cache {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81} - sage: f = Stream_function(lambda n: n^2, QQ, False, 0) + sage: f = Stream_function(lambda n: n^2, False, 0) sage: f[3] 9 sage: f._cache @@ -339,8 +404,8 @@ def iterate_coefficients(self): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose - sage: f = Stream_function(lambda n: 1, ZZ, False, 1) - sage: g = Stream_function(lambda n: n^3, ZZ, False, 1) + sage: f = Stream_function(lambda n: 1, False, 1) + sage: g = Stream_function(lambda n: n^3, False, 1) sage: h = Stream_cauchy_compose(f, g) sage: n = h.iterate_coefficients() sage: [next(n) for i in range(10)] @@ -359,10 +424,12 @@ def order(self): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n, QQ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) sage: f.order() 1 """ + if self._true_order: + return self._approximate_order if self._is_sparse: n = self._approximate_order cache = self._cache @@ -370,11 +437,13 @@ def order(self): if n in cache: if cache[n]: self._approximate_order = n + self._true_order = True return n n += 1 else: if self[n]: self._approximate_order = n + self._true_order = True return n n += 1 else: @@ -384,11 +453,13 @@ def order(self): if n - self._offset < len(cache): if cache[n - self._offset]: self._approximate_order = n + self._true_order = True return n n += 1 else: if self[n]: self._approximate_order = n + self._true_order = True return n n += 1 @@ -402,8 +473,8 @@ def __ne__(self, other): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n, QQ, True, 0) - sage: g = Stream_function(lambda n: n^2, QQ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: f != g False sage: f[1], g[1] @@ -421,8 +492,8 @@ def __ne__(self, other): Checking the dense implementation:: - sage: f = Stream_function(lambda n: n if n > 0 else 0, QQ, False, -3) - sage: g = Stream_function(lambda n: n^2, QQ, False, 0) + sage: f = Stream_function(lambda n: n if n > 0 else 0, False, -3) + sage: g = Stream_function(lambda n: n^2, False, 0) sage: f != g False sage: g != f @@ -438,8 +509,8 @@ def __ne__(self, other): sage: g != f True - sage: f = Stream_function(lambda n: n if n > 0 else 0, QQ, False, -3) - sage: g = Stream_function(lambda n: n^2, QQ, False, 0) + sage: f = Stream_function(lambda n: n if n > 0 else 0, False, -3) + sage: g = Stream_function(lambda n: n^2, False, 0) sage: _ = f[5], g[1] sage: f != g False @@ -451,8 +522,8 @@ def __ne__(self, other): sage: g != f True - sage: f = Stream_function(lambda n: n if n > 0 else 0, QQ, False, -3) - sage: g = Stream_function(lambda n: n^2, QQ, False, 0) + sage: f = Stream_function(lambda n: n if n > 0 else 0, False, -3) + sage: g = Stream_function(lambda n: n^2, False, 0) sage: _ = g[5], f[1] sage: f != g False @@ -471,7 +542,7 @@ def __ne__(self, other): for i in self._cache: if i in other._cache and other._cache[i] != self._cache[i]: return True - else: # they are dense + else: # they are dense # Make ``self`` have the smaller approximate order. if self._approximate_order > other._approximate_order: self, other = other, self @@ -491,6 +562,7 @@ def __ne__(self, other): return False + class Stream_exact(Stream): r""" A stream of eventually constant coefficients. @@ -505,6 +577,13 @@ class Stream_exact(Stream): of the first element which is known to be equal to ``constant`` - ``constant`` -- integer (default: 0); the coefficient of every index larger than or equal to ``degree`` + + .. WARNING:: + + The convention for ``order`` is different to the one in + :class:`sage.rings.lazy_series_ring.LazySeriesRing`, where + the input is shifted to have the prescribed order. + """ def __init__(self, initial_coefficients, is_sparse, constant=None, degree=None, order=None): """ @@ -517,28 +596,79 @@ def __init__(self, initial_coefficients, is_sparse, constant=None, degree=None, Traceback (most recent call last): ... AssertionError: Stream_exact should only be used for non-zero streams + + sage: s = Stream_exact([0, 0, 1, 0, 0], False) + sage: s._initial_coefficients, s._approximate_order, s._degree, s._true_order + ((1,), 2, 3, True) + + sage: s = Stream_exact([0, 0, 1, 0, 0], False, constant=0) + sage: s._initial_coefficients, s._approximate_order, s._degree, s._true_order + ((1,), 2, 3, True) + + sage: s = Stream_exact([0, 0, 1, 0, 0], False, constant=0, degree=10) + sage: s._initial_coefficients, s._approximate_order, s._degree, s._true_order + ((1,), 2, 3, True) + + sage: s = Stream_exact([0, 0, 1, 0, 0], False, constant=1) + sage: s._initial_coefficients, s._approximate_order, s._degree, s._true_order + ((1,), 2, 5, True) + + sage: s = Stream_exact([0, 0, 1, 0, 1], False, constant=1, degree=10) + sage: s._initial_coefficients, s._approximate_order, s._degree, s._true_order + ((1, 0, 1), 2, 10, True) + + sage: s = Stream_exact([0, 0, 1, 0, 1], False, constant=1, degree=5) + sage: s._initial_coefficients, s._approximate_order, s._degree, s._true_order + ((1,), 2, 4, True) + + sage: s = Stream_exact([0, 0, 1, 2, 0, 1], False, constant=1) + sage: s._initial_coefficients, s._approximate_order, s._degree, s._true_order + ((1, 2), 2, 5, True) + + sage: s = Stream_exact([0, 0, 1, 2, 1, 1], False, constant=1) + sage: s._initial_coefficients, s._approximate_order, s._degree, s._true_order + ((1, 2), 2, 4, True) + + sage: s = Stream_exact([0, 0, 1, 2, 1, 1], False, constant=1, order=-2) + sage: s._initial_coefficients, s._approximate_order, s._degree, s._true_order + ((1, 2), 0, 2, True) """ if constant is None: self._constant = ZZ.zero() else: self._constant = constant + if order is None: order = 0 - if degree is None: + if (degree is None + or (not self._constant + and degree > order + len(initial_coefficients))): self._degree = order + len(initial_coefficients) else: self._degree = degree - assert order + len(initial_coefficients) <= self._degree - # We do not insist that the last entry of - # initial_coefficients is different from constant in case - # comparisons can be expensive such as in the symbolic ring + # we remove leading and trailing zeros from + # initial_coefficients + + # if the degree is order + len(initial_coefficients), we also + # insist that the last entry of initial_coefficients is + # different from constant, because __eq__ below would become + # complicated otherwise for i, v in enumerate(initial_coefficients): if v: + # We have found the first nonzero coefficient order += i initial_coefficients = initial_coefficients[i:] - for j, w in enumerate(reversed(initial_coefficients)): + if order + len(initial_coefficients) == self._degree: + # Strip off the constant values at the end + for w in reversed(initial_coefficients): + if w != self._constant: + break + initial_coefficients.pop() + self._degree -= 1 + # Strip off all remaining zeros at the end + for w in reversed(initial_coefficients): if w: break initial_coefficients.pop() @@ -550,7 +680,8 @@ def __init__(self, initial_coefficients, is_sparse, constant=None, degree=None, assert self._initial_coefficients or self._constant, "Stream_exact should only be used for non-zero streams" - super().__init__(is_sparse, order) + super().__init__(is_sparse, True) + self._approximate_order = order def __getitem__(self, n): """ @@ -586,6 +717,14 @@ def __getitem__(self, n): sage: t = Stream_exact([0, 2, 0], False, order=-2, degree=2, constant=1) sage: t == s True + + sage: s = Stream_exact([0,1,2,1,0,0,1,1], False, constant=1) + sage: [s[i] for i in range(10)] + [0, 1, 2, 1, 0, 0, 1, 1, 1, 1] + + sage: t = Stream_exact([0,1,2,1,0,0], False, constant=1) + sage: s == t + True """ if n >= self._degree: return self._constant @@ -596,8 +735,8 @@ def __getitem__(self, n): def order(self): r""" - Return the order of ``self``, which is the minimum index ``n`` such - that ``self[n]`` is nonzero. + Return the order of ``self``, which is the minimum index + ``n`` such that ``self[n]`` is nonzero. EXAMPLES:: @@ -605,6 +744,7 @@ def order(self): sage: s = Stream_exact([1], False) sage: s.order() 0 + """ return self._approximate_order @@ -664,7 +804,8 @@ def __eq__(self, other): def __ne__(self, other): """ - Test inequality between ``self`` and ``other``. + Test inequality between ``self`` and ``other``, where + other is exact or inexact, but not zero. INPUT: @@ -686,7 +827,7 @@ def __ne__(self, other): return ``False``:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: 2 if n == 0 else 1, ZZ, False, 0) + sage: f = Stream_function(lambda n: 2 if n == 0 else 1, False, 0) sage: s == f False sage: s != f @@ -695,12 +836,24 @@ def __ne__(self, other): [0, 0, 0, 2, 1, 1, 1, 1] sage: [f[i] for i in range(-3, 5)] [0, 0, 0, 2, 1, 1, 1, 1] + """ if isinstance(other, type(self)): return (self._degree != other._degree or self._approximate_order != other._approximate_order or self._initial_coefficients != other._initial_coefficients or self._constant != other._constant) + # if other is not exact, we can at least compare with the + # elements in its cache + if other._is_sparse: + for i in other._cache: + if self[i] != other._cache[i]: + return True + else: + if other._offset > self._approximate_order: + return False + return any(self[i] != c for i, c in enumerate(other._cache, other._offset)) + return False def is_nonzero(self): @@ -735,77 +888,89 @@ def _polynomial_part(self, R): return R(self._initial_coefficients).shift(v) -class Stream_function(Stream_inexact): +class Stream_iterator(Stream_inexact): r""" - Class that creates a stream from a function on the integers. + Class that creates a stream from an iterator. INPUT: - - ``function`` -- a function that generates the - coefficients of the stream - - ``ring`` -- the base ring - - ``is_sparse`` -- boolean; specifies whether the stream is sparse + - ``iter`` -- a function that generates the coefficients of the + stream - ``approximate_order`` -- integer; a lower bound for the order of the stream + Instances of this class are always dense. + EXAMPLES:: - sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n^2, ZZ, False, 1) - sage: f[3] - 9 + sage: from sage.data_structures.stream import Stream_iterator + sage: f = Stream_iterator(iter(NonNegativeIntegers()), 0) sage: [f[i] for i in range(10)] - [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] - """ + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + sage: f = Stream_iterator(iter(NonNegativeIntegers()), 1) + sage: [f[i] for i in range(10)] + [0, 0, 1, 2, 3, 4, 5, 6, 7, 8] - def __init__(self, function, ring, is_sparse, approximate_order): + """ + def __init__(self, iter, approximate_order, true_order=False): """ Initialize. TESTS:: - sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: 1, ZZ, False, 1) + sage: from sage.data_structures.stream import Stream_iterator + sage: f = Stream_iterator(iter(NonNegativeIntegers()), 0) sage: TestSuite(f).run(skip="_test_pickling") """ - self._function = function - self._ring = ring - super().__init__(is_sparse, approximate_order) + self.iterate_coefficients = lambda: iter + super().__init__(False, true_order) + self._approximate_order = approximate_order - def get_coefficient(self, n): - """ - Return the ``n``-th coefficient of ``self``. - INPUT: +class Stream_function(Stream_inexact): + r""" + Class that creates a stream from a function on the integers. - - ``n`` -- integer; the degree for the coefficient + INPUT: - EXAMPLES:: + - ``function`` -- a function that generates the + coefficients of the stream + - ``is_sparse`` -- boolean; specifies whether the stream is sparse + - ``approximate_order`` -- integer; a lower bound for the order + of the stream - sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: n, QQ, True, 0) - sage: f.get_coefficient(4) - 4 - """ - return self._ring(self._function(n)) + EXAMPLES:: - def iterate_coefficients(self): + sage: from sage.data_structures.stream import Stream_function + sage: f = Stream_function(lambda n: n^2, False, 1) + sage: f[3] + 9 + sage: [f[i] for i in range(10)] + [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] + + sage: f = Stream_function(lambda n: 1, False, 0) + sage: n = f.iterate_coefficients() + sage: [next(n) for _ in range(10)] + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + + sage: f = Stream_function(lambda n: n, True, 0) + sage: f.get_coefficient(4) + 4 + """ + def __init__(self, function, is_sparse, approximate_order, true_order=False): """ - A generator for the coefficients of ``self``. + Initialize. - EXAMPLES:: + TESTS:: sage: from sage.data_structures.stream import Stream_function - sage: f = Stream_function(lambda n: 1, QQ, False, 0) - sage: n = f.iterate_coefficients() - sage: [next(n) for _ in range(10)] - [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] + sage: f = Stream_function(lambda n: 1, False, 1) + sage: TestSuite(f).run(skip="_test_pickling") """ - n = self._offset - ring = self._ring - while True: - yield ring(self._function(n)) - n += 1 + self.get_coefficient = function + super().__init__(is_sparse, true_order) + self._approximate_order = approximate_order class Stream_uninitialized(Stream_inexact): @@ -829,7 +994,7 @@ class Stream_uninitialized(Stream_inexact): sage: C.get_coefficient(4) 0 """ - def __init__(self, is_sparse, approximate_order): + def __init__(self, is_sparse, approximate_order, true_order=False): """ Initialize ``self``. @@ -840,8 +1005,10 @@ def __init__(self, is_sparse, approximate_order): sage: TestSuite(C).run(skip="_test_pickling") """ self._target = None - assert approximate_order is not None, "calling Stream_uninitialized with None as approximate order" - super().__init__(is_sparse, approximate_order) + if approximate_order is None: + raise ValueError("the valuation must be specified for undefined series") + super().__init__(is_sparse, true_order) + self._approximate_order = approximate_order def get_coefficient(self, n): """ @@ -897,7 +1064,7 @@ class Stream_unary(Stream_inexact): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_cauchy_invert, Stream_lmul) - sage: f = Stream_function(lambda n: 2*n, ZZ, False, 1) + sage: f = Stream_function(lambda n: 2*n, False, 1) sage: g = Stream_cauchy_invert(f) sage: [g[i] for i in range(10)] [-1, 1/2, 0, 0, 0, 0, 0, 0, 0, 0] @@ -906,7 +1073,7 @@ class Stream_unary(Stream_inexact): [0, 4, 8, 12, 16, 20, 24, 28, 32, 36] """ - def __init__(self, series, *args, **kwargs): + def __init__(self, series, is_sparse): """ Initialize ``self``. @@ -921,7 +1088,7 @@ def __init__(self, series, *args, **kwargs): sage: TestSuite(g).run() """ self._series = series - super().__init__(*args, **kwargs) + super().__init__(is_sparse, False) def __hash__(self): """ @@ -931,7 +1098,7 @@ def __hash__(self): sage: from sage.data_structures.stream import Stream_unary sage: from sage.data_structures.stream import Stream_function - sage: M = Stream_unary(Stream_function(lambda n: 1, ZZ, False, 1), True, 0) + sage: M = Stream_unary(Stream_function(lambda n: 1, False, 1), True) sage: hash(M) == hash(M) True """ @@ -948,8 +1115,8 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_rmul) - sage: f = Stream_function(lambda n: 2*n, ZZ, False, 1) - sage: g = Stream_function(lambda n: n, ZZ, False, 1) + sage: f = Stream_function(lambda n: 2*n, False, 1) + sage: g = Stream_function(lambda n: n, False, 1) sage: h = Stream_rmul(f, 2) sage: n = Stream_rmul(g, 2) sage: h == n @@ -974,8 +1141,8 @@ class Stream_binary(Stream_inexact): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_add, Stream_sub) - sage: f = Stream_function(lambda n: 2*n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: 2*n, True, 0) + sage: g = Stream_function(lambda n: n, True, 1) sage: h = Stream_add(f, g) sage: [h[i] for i in range(10)] [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] @@ -984,7 +1151,7 @@ class Stream_binary(Stream_inexact): [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] """ - def __init__(self, left, right, *args, **kwargs): + def __init__(self, left, right, is_sparse): """ Initialize ``self``. @@ -1003,7 +1170,7 @@ def __init__(self, left, right, *args, **kwargs): """ self._left = left self._right = right - super().__init__(*args, **kwargs) + super().__init__(is_sparse, False) def __hash__(self): """ @@ -1013,9 +1180,9 @@ def __hash__(self): sage: from sage.data_structures.stream import Stream_binary sage: from sage.data_structures.stream import Stream_function - sage: M = Stream_function(lambda n: n, ZZ, True, 0) - sage: N = Stream_function(lambda n: -2*n, ZZ, True, 0) - sage: O = Stream_binary(M, N, True, 0) + sage: M = Stream_function(lambda n: n, True, 0) + sage: N = Stream_function(lambda n: -2*n, True, 0) + sage: O = Stream_binary(M, N, True) sage: hash(O) == hash(O) True """ @@ -1032,9 +1199,9 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_cauchy_mul) - sage: f = Stream_function(lambda n: 2*n, ZZ, False, 1) - sage: g = Stream_function(lambda n: n, ZZ, False, 1) - sage: h = Stream_function(lambda n: 1, ZZ, False, 1) + sage: f = Stream_function(lambda n: 2*n, False, 1) + sage: g = Stream_function(lambda n: n, False, 1) + sage: h = Stream_function(lambda n: 1, False, 1) sage: t = Stream_cauchy_mul(f, g) sage: u = Stream_cauchy_mul(g, h) sage: v = Stream_cauchy_mul(h, f) @@ -1057,8 +1224,8 @@ class Stream_binaryCommutative(Stream_binary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_add) - sage: f = Stream_function(lambda n: 2*n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: 2*n, True, 0) + sage: g = Stream_function(lambda n: n, True, 1) sage: h = Stream_add(f, g) sage: [h[i] for i in range(10)] [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] @@ -1075,8 +1242,8 @@ def __hash__(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_add) - sage: f = Stream_function(lambda n: 2*n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: 2*n, True, 0) + sage: g = Stream_function(lambda n: n, True, 1) sage: h = Stream_add(f, g) sage: u = Stream_add(g, f) sage: hash(h) == hash(u) @@ -1095,8 +1262,8 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_add) - sage: f = Stream_function(lambda n: 2*n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: 2*n, True, 0) + sage: g = Stream_function(lambda n: n, True, 1) sage: h = Stream_add(f, g) sage: [h[i] for i in range(10)] [0, 3, 6, 9, 12, 15, 18, 21, 24, 27] @@ -1131,7 +1298,7 @@ class Stream_zero(Stream): 0 """ - def __init__(self, sparse): + def __init__(self, is_sparse): """ Initialize ``self``. @@ -1140,8 +1307,14 @@ def __init__(self, sparse): sage: from sage.data_structures.stream import Stream_zero sage: s = Stream_zero(False) sage: TestSuite(s).run() + + .. TODO:: + + Having ``is_sparse`` as argument here does not really + make sense, since this stream does not cache values. """ - return super().__init__(sparse, 0) + super().__init__(is_sparse, True) + self._approximate_order = infinity def __getitem__(self, n): """ @@ -1173,7 +1346,7 @@ def order(self): sage: s.order() +Infinity """ - return infinity + return self._approximate_order # == infinity def __eq__(self, other): """ @@ -1221,8 +1394,8 @@ class Stream_add(Stream_binaryCommutative): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_add, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: 1, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: 1, True, 0) sage: h = Stream_add(f, g) sage: [h[i] for i in range(10)] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] @@ -1237,15 +1410,28 @@ def __init__(self, left, right): TESTS:: sage: from sage.data_structures.stream import (Stream_function, Stream_add) - sage: f = Stream_function(lambda n: 1, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: 1, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_add(f, g) """ if left._is_sparse != right._is_sparse: raise NotImplementedError + super().__init__(left, right, left._is_sparse) + + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. - a = min(left._approximate_order, right._approximate_order) - super().__init__(left, right, left._is_sparse, a) + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_exact + sage: h = Stream_exact([0,3], True) + sage: h._approximate_order + 1 + """ + # this is not the true order, because we may have cancellation + return min(self._left._approximate_order, self._right._approximate_order) def get_coefficient(self, n): """ @@ -1258,8 +1444,8 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_add) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_add(f, g) sage: h.get_coefficient(5) 30 @@ -1281,8 +1467,8 @@ class Stream_sub(Stream_binary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_sub, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: 1, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: 1, True, 0) sage: h = Stream_sub(f, g) sage: [h[i] for i in range(10)] [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8] @@ -1290,7 +1476,6 @@ class Stream_sub(Stream_binary): sage: [u[i] for i in range(10)] [1, 0, -1, -2, -3, -4, -5, -6, -7, -8] """ - def __init__(self, left, right): """ initialize ``self``. @@ -1298,15 +1483,32 @@ def __init__(self, left, right): TESTS:: sage: from sage.data_structures.stream import (Stream_function, Stream_sub) - sage: f = Stream_function(lambda n: 1, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: 1, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_sub(f, g) """ if left._is_sparse != right._is_sparse: raise NotImplementedError + super().__init__(left, right, left._is_sparse) - a = min(left._approximate_order, right._approximate_order) - super().__init__(left, right, left._is_sparse, a) + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_exact, Stream_function, Stream_add + sage: f = Stream_exact([0,3], True) + sage: g = Stream_function(lambda n: -3*n, True, 1) + sage: h = Stream_add(f, g) + sage: h._approximate_order + 1 + sage: [h[i] for i in range(5)] + [0, 0, -6, -9, -12] + """ + # this is not the true order, because we may have cancellation + return min(self._left._approximate_order, self._right._approximate_order) def get_coefficient(self, n): """ @@ -1319,8 +1521,8 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_sub) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_sub(f, g) sage: h.get_coefficient(5) -20 @@ -1346,8 +1548,8 @@ class Stream_cauchy_mul(Stream_binary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_mul, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: 1, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: 1, True, 0) sage: h = Stream_cauchy_mul(f, g) sage: [h[i] for i in range(10)] [0, 1, 3, 6, 10, 15, 21, 28, 36, 45] @@ -1362,15 +1564,32 @@ def __init__(self, left, right): TESTS:: sage: from sage.data_structures.stream import (Stream_function, Stream_cauchy_mul) - sage: f = Stream_function(lambda n: 1, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: 1, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_cauchy_mul(f, g) """ if left._is_sparse != right._is_sparse: raise NotImplementedError + super().__init__(left, right, left._is_sparse) - a = left._approximate_order + right._approximate_order - super().__init__(left, right, left._is_sparse, a) + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_exact, Stream_function, Stream_cauchy_mul + sage: f = Stream_exact([0, Zmod(6)(2)], True) + sage: g = Stream_function(lambda n: Zmod(6)(3*n), True, 1) + sage: h = Stream_cauchy_mul(f, g) + sage: h._approximate_order + 2 + sage: [h[i] for i in range(5)] + [0, 0, 0, 0, 0] + """ + # this is not the true order, unless we have an integral domain + return self._left._approximate_order + self._right._approximate_order def get_coefficient(self, n): """ @@ -1383,8 +1602,8 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_function, Stream_cauchy_mul) - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 0) + sage: f = Stream_function(lambda n: n, True, 0) + sage: g = Stream_function(lambda n: n^2, True, 0) sage: h = Stream_cauchy_mul(f, g) sage: h.get_coefficient(5) 50 @@ -1408,7 +1627,7 @@ def is_nonzero(self): sage: from sage.data_structures.stream import (Stream_function, ....: Stream_cauchy_mul, Stream_cauchy_invert) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_cauchy_mul(f, f) sage: g.is_nonzero() False @@ -1435,7 +1654,7 @@ class Stream_dirichlet_convolve(Stream_binary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_exact([0], True, constant=1) sage: h = Stream_dirichlet_convolve(f, g) sage: [h[i] for i in range(1, 10)] @@ -1449,29 +1668,49 @@ class Stream_dirichlet_convolve(Stream_binary): """ def __init__(self, left, right): """ - Initalize ``self``. + Initialize ``self``. sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_exact([1], True, constant=0) - sage: Stream_dirichlet_convolve(f, g) + sage: h = Stream_dirichlet_convolve(f, g) + sage: h[1] Traceback (most recent call last): ... - AssertionError: Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1 - sage: Stream_dirichlet_convolve(g, f) + ValueError: Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1 + sage: h = Stream_dirichlet_convolve(g, f) + sage: h[1] Traceback (most recent call last): ... - AssertionError: Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1 + ValueError: Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1 """ if left._is_sparse != right._is_sparse: raise NotImplementedError + super().__init__(left, right, left._is_sparse) - assert left._approximate_order > 0 and right._approximate_order > 0, "Dirichlet convolution is only defined for coefficient streams with minimal index of nonzero coefficient at least 1" + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. - vl = left._approximate_order - vr = right._approximate_order - a = vl * vr - super().__init__(left, right, left._is_sparse, a) + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_exact, Stream_function, Stream_dirichlet_convolve + sage: f = Stream_exact([0, 2], True) + sage: g = Stream_function(lambda n: 3*n, True, 1) + sage: h = Stream_dirichlet_convolve(f, g) + sage: h._approximate_order + 1 + sage: [h[i] for i in range(5)] + [0, 6, 12, 18, 24] + """ + # this is not the true order, unless we have an integral domain + if (self._left._approximate_order <= 0 + or self._right._approximate_order <= 0): + raise ValueError("Dirichlet convolution is only defined for " + "coefficient streams with minimal index of " + "nonzero coefficient at least 1") + return self._left._approximate_order * self._right._approximate_order def get_coefficient(self, n): """ @@ -1484,7 +1723,7 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_dirichlet_convolve, Stream_function, Stream_exact) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_exact([0], True, constant=1) sage: h = Stream_dirichlet_convolve(f, g) sage: h.get_coefficient(7) @@ -1513,7 +1752,7 @@ class Stream_dirichlet_invert(Stream_unary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_dirichlet_invert, Stream_function) - sage: f = Stream_function(lambda n: 1, ZZ, True, 1) + sage: f = Stream_function(lambda n: 1, True, 1) sage: g = Stream_dirichlet_invert(f) sage: [g[i] for i in range(10)] [0, 1, -1, -1, 0, -1, 1, -1, 0, 0] @@ -1529,16 +1768,59 @@ def __init__(self, series): sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) sage: f = Stream_exact([0, 0], True, constant=1) sage: g = Stream_dirichlet_invert(f) + sage: g[1] Traceback (most recent call last): ... - AssertionError: the Dirichlet inverse only exists if the coefficient with index 1 is non-zero + ZeroDivisionError: the Dirichlet inverse only exists if the coefficient with index 1 is non-zero """ - assert series[1], "the Dirichlet inverse only exists if the coefficient with index 1 is non-zero" - super().__init__(series, series._is_sparse, 1) - - self._ainv = ~series[1] + super().__init__(series, series._is_sparse) self._zero = ZZ.zero() + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_dirichlet_invert + sage: f = Stream_function(lambda n: n, True, 1) + sage: h = Stream_dirichlet_invert(f) + sage: h._approximate_order + 1 + sage: [h[i] for i in range(5)] + [0, -2, -8, -12, -48] + """ + # this is the true order, but we want to check first + if self._series._approximate_order > 1: + raise ZeroDivisionError("the Dirichlet inverse only exists if the " + "coefficient with index 1 is non-zero") + self._true_order = True + return 1 + + @lazy_attribute + def _ainv(self): + """ + The inverse of the leading coefficient. + + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_exact, Stream_dirichlet_invert) + sage: f = Stream_exact([0, 3], True, constant=2) + sage: g = Stream_dirichlet_invert(f) + sage: g._ainv + 1/3 + + sage: f = Stream_exact([Zmod(6)(5)], False, constant=2, order=1) + sage: g = Stream_dirichlet_invert(f) + sage: g._ainv + 5 + """ + try: + return ~self._series[1] + except TypeError: + return self._series[1].inverse_of_unit() + def get_coefficient(self, n): """ Return the ``n``-th coefficient of ``self``. @@ -1582,8 +1864,8 @@ class Stream_cauchy_compose(Stream_binary): EXAMPLES:: sage: from sage.data_structures.stream import Stream_cauchy_compose, Stream_function - sage: f = Stream_function(lambda n: n, ZZ, True, 1) - sage: g = Stream_function(lambda n: 1, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) + sage: g = Stream_function(lambda n: 1, True, 1) sage: h = Stream_cauchy_compose(f, g) sage: [h[i] for i in range(10)] [0, 1, 3, 8, 20, 48, 112, 256, 576, 1280] @@ -1598,24 +1880,49 @@ def __init__(self, f, g): TESTS:: sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose - sage: f = Stream_function(lambda n: 1, ZZ, True, 1) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 1) + sage: f = Stream_function(lambda n: 1, True, 1) + sage: g = Stream_function(lambda n: n^2, True, 1) + sage: h = Stream_cauchy_compose(f, g) + """ + if g._true_order and g._approximate_order <= 0: + raise ValueError("can only compose with a series of positive valuation") + super().__init__(f, g, f._is_sparse) + + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose + sage: f = Stream_function(lambda n: n, True, 1) + sage: g = Stream_function(lambda n: n^2, True, 1) sage: h = Stream_cauchy_compose(f, g) + sage: h._approximate_order + 1 + sage: [h[i] for i in range(5)] + [0, 1, 6, 28, 124] + + .. TODO:: + + check similarities with :class:`Stream_plethysm` """ - #assert g._approximate_order > 0 - self._fv = f._approximate_order - self._gv = g._approximate_order - if self._fv < 0: - ginv = Stream_cauchy_invert(g) + # this is very likely not the true order + if self._right._approximate_order <= 0: + raise ValueError("can only compose with a series of positive valuation") + + if self._left._approximate_order < 0: + ginv = Stream_cauchy_invert(self._right) # The constant part makes no contribution to the negative. # We need this for the case so self._neg_powers[0][n] => 0. - self._neg_powers = [Stream_zero(f._is_sparse), ginv] - for i in range(1, -self._fv): + self._neg_powers = [Stream_zero(self._left._is_sparse), ginv] + for i in range(1, -self._left._approximate_order): self._neg_powers.append(Stream_cauchy_mul(self._neg_powers[-1], ginv)) - # Placeholder None to make this 1-based. - self._pos_powers = [None, g] - val = self._fv * self._gv - super().__init__(f, g, f._is_sparse, val) + # placeholder None to make this 1-based. + self._pos_powers = [None, self._right] + + return self._left._approximate_order * self._right._approximate_order def get_coefficient(self, n): """ @@ -1628,23 +1935,26 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_compose - sage: f = Stream_function(lambda n: n, ZZ, True, 1) - sage: g = Stream_function(lambda n: n^2, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) + sage: g = Stream_function(lambda n: n^2, True, 1) sage: h = Stream_cauchy_compose(f, g) - sage: h.get_coefficient(5) + sage: h[5] # indirect doctest 527 - sage: [h.get_coefficient(i) for i in range(10)] + sage: [h[i] for i in range(10)] # indirect doctest [0, 1, 6, 28, 124, 527, 2172, 8755, 34704, 135772] """ + fv = self._left._approximate_order + gv = self._right._approximate_order if n < 0: - return sum(self._left[i] * self._neg_powers[-i][n] for i in range(self._fv, n // self._gv + 1)) + return sum(self._left[i] * self._neg_powers[-i][n] + for i in range(fv, n // gv + 1)) # n > 0 - while len(self._pos_powers) <= n // self._gv: + while len(self._pos_powers) <= n // gv: self._pos_powers.append(Stream_cauchy_mul(self._pos_powers[-1], self._right)) - ret = sum(self._left[i] * self._neg_powers[-i][n] for i in range(self._fv, 0)) + ret = sum(self._left[i] * self._neg_powers[-i][n] for i in range(fv, 0)) if n == 0: ret += self._left[0] - return ret + sum(self._left[i] * self._pos_powers[i][n] for i in range(1, n // self._gv+1)) + return ret + sum(self._left[i] * self._pos_powers[i][n] for i in range(1, n // gv+1)) class Stream_plethysm(Stream_binary): @@ -1652,37 +1962,89 @@ class Stream_plethysm(Stream_binary): Return the plethysm of ``f`` composed by ``g``. This is the plethysm `f \circ g = f(g)` when `g` is an element of - the ring of symmetric functions. + a ring of symmetric functions. INPUT: - ``f`` -- a :class:`Stream` - - ``g`` -- a :class:`Stream` with positive order - - ``p`` -- the powersum symmetric functions + - ``g`` -- a :class:`Stream` with positive order, unless ``f`` is + of :class:`Stream_exact`. + - ``p`` -- the ring of powersum symmetric functions containing ``g`` + - ``ring`` (optional, default ``None``) -- the ring the result + should be in, by default ``p`` + - ``include`` -- a list of variables to be treated as degree one + elements instead of the default degree one elements + - ``exclude`` -- a list of variables to be excluded from the + default degree one elements EXAMPLES:: - sage: from sage.data_structures.stream import Stream_function, Stream_plethysm + sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() - sage: f = Stream_function(lambda n: s[n], s, True, 1) - sage: g = Stream_function(lambda n: s[[1]*n], s, True, 1) - sage: h = Stream_plethysm(f, g, p) - sage: [s(h[i]) for i in range(5)] + sage: f = Stream_function(lambda n: s[n], True, 1) + sage: g = Stream_function(lambda n: s[[1]*n], True, 1) + sage: h = Stream_plethysm(f, g, p, s) + sage: [h[i] for i in range(5)] [0, s[1], s[1, 1] + s[2], 2*s[1, 1, 1] + s[2, 1] + s[3], 3*s[1, 1, 1, 1] + 2*s[2, 1, 1] + s[2, 2] + s[3, 1] + s[4]] - sage: u = Stream_plethysm(g, f, p) - sage: [s(u[i]) for i in range(5)] + sage: u = Stream_plethysm(g, f, p, s) + sage: [u[i] for i in range(5)] [0, s[1], s[1, 1] + s[2], s[1, 1, 1] + s[2, 1] + 2*s[3], s[1, 1, 1, 1] + s[2, 1, 1] + 3*s[3, 1] + 2*s[4]] + + This class also handles the plethysm of an exact stream with a + stream of order `0`:: + + sage: from sage.data_structures.stream import Stream_exact + sage: f = Stream_exact([s[1]], True, order=1) + sage: g = Stream_function(lambda n: s[n], True, 0) + sage: r = Stream_plethysm(f, g, p, s) + sage: [r[n] for n in range(3)] + [s[], s[1], s[2]] + + TESTS: + + Check corner cases:: + + sage: f0 = Stream_exact([p([])], True) + sage: f1 = Stream_exact([p[1]], True, order=1) + sage: f2 = Stream_exact([p[2]], True, order=2 ) + sage: f11 = Stream_exact([p[1,1]], True, order=2 ) + sage: r = Stream_plethysm(f0, f1, p); [r[n] for n in range(3)] + [p[], 0, 0] + sage: r = Stream_plethysm(f0, f2, p); [r[n] for n in range(3)] + [p[], 0, 0] + sage: r = Stream_plethysm(f0, f11, p); [r[n] for n in range(3)] + [p[], 0, 0] + + Check that degree one elements are treated in the correct way:: + + sage: R. = QQ[]; p = SymmetricFunctions(R).p() + sage: f_s = a1*p[1] + a2*p[2] + a11*p[1,1] + sage: g_s = b1*p[1] + b21*p[2,1] + b111*p[1,1,1] + sage: r_s = f_s(g_s) + sage: f = Stream_exact([f_s.restrict_degree(k) for k in range(f_s.degree()+1)], True) + sage: g = Stream_exact([g_s.restrict_degree(k) for k in range(g_s.degree()+1)], True) + sage: r = Stream_plethysm(f, g, p) + sage: r_s == sum(r[n] for n in range(2*(r_s.degree()+1))) + True + + sage: r_s - f_s(g_s, include=[]) + (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] + + sage: r2 = Stream_plethysm(f, g, p, include=[]) + sage: r_s - sum(r2[n] for n in range(2*(r_s.degree()+1))) + (a2*b1^2-a2*b1)*p[2] + (a2*b111^2-a2*b111)*p[2, 2, 2] + (a2*b21^2-a2*b21)*p[4, 2] + """ - def __init__(self, f, g, p): + def __init__(self, f, g, p, ring=None, include=None, exclude=None): r""" Initialize ``self``. @@ -1691,16 +2053,60 @@ def __init__(self, f, g, p): sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() - sage: f = Stream_function(lambda n: s[n], s, True, 1) - sage: g = Stream_function(lambda n: s[n-1,1], s, True, 2) + sage: f = Stream_function(lambda n: s[n], True, 1) + sage: g = Stream_function(lambda n: s[n-1,1], True, 2) sage: h = Stream_plethysm(f, g, p) """ - #assert g._approximate_order > 0 - self._fv = f._approximate_order - self._gv = g._approximate_order + if isinstance(f, Stream_exact): + self._degree_f = f._degree + else: + self._degree_f = None + + if g._true_order and g._approximate_order == 0 and self._degree_f is None: + raise ValueError("can only compute plethysm with a series of valuation 0 for symmetric functions of finite support") + + if ring is None: + self._basis = p + else: + self._basis = ring self._p = p - val = self._fv * self._gv - super().__init__(f, g, f._is_sparse, val) + g = Stream_map_coefficients(g, lambda x: p(x)) + self._powers = [g] # a cache for the powers of g + R = self._basis.base_ring() + self._degree_one = _variables_recursive(R, include=include, exclude=exclude) + + if HopfAlgebrasWithBasis(R).TensorProducts() in p.categories(): + self._tensor_power = len(p._sets) + p_f = p._sets[0] + f = Stream_map_coefficients(f, lambda x: p_f(x)) + else: + self._tensor_power = None + f = Stream_map_coefficients(f, lambda x: p(x)) + super().__init__(f, g, f._is_sparse) + + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_plethysm + sage: p = SymmetricFunctions(QQ).p() + sage: f = Stream_function(lambda n: p[n], True, 1) + sage: h = Stream_plethysm(f, f, p) + sage: h._approximate_order + 1 + sage: [h[i] for i in range(5)] + [0, p[1], 2*p[2], 2*p[3], 3*p[4]] + """ + # this is very likely not the true order +# if self._right._approximate_order == 0 and self._degree_f is None: +# raise ValueError("can only compute plethysm with a series of " +# " valuation 0 for symmetric functions of finite " +# " support") + return self._left._approximate_order * self._right._approximate_order + def get_coefficient(self, n): r""" @@ -1715,8 +2121,8 @@ def get_coefficient(self, n): sage: from sage.data_structures.stream import Stream_function, Stream_plethysm sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() - sage: f = Stream_function(lambda n: s[n], s, True, 1) - sage: g = Stream_function(lambda n: s[[1]*n], s, True, 1) + sage: f = Stream_function(lambda n: s[n], True, 1) + sage: g = Stream_function(lambda n: s[[1]*n], True, 1) sage: h = Stream_plethysm(f, g, p) sage: s(h.get_coefficient(5)) 4*s[1, 1, 1, 1, 1] + 4*s[2, 1, 1, 1] + 2*s[2, 2, 1] + 2*s[3, 1, 1] + s[3, 2] + s[4, 1] + s[5] @@ -1728,57 +2134,142 @@ def get_coefficient(self, n): 3*s[1, 1, 1, 1] + 2*s[2, 1, 1] + s[2, 2] + s[3, 1] + s[4], 4*s[1, 1, 1, 1, 1] + 4*s[2, 1, 1, 1] + 2*s[2, 2, 1] + 2*s[3, 1, 1] + s[3, 2] + s[4, 1] + s[5]] """ - if not n: # special case of 0 - return self._left[0] - - # We assume n > 0 - p = self._p - ret = p.zero() - for k in range(n+1): - temp = p(self._left[k]) - for la, c in temp: - inner = self._compute_product(n, la, c) - if inner is not None: - ret += inner - return ret + if not n: # special case of 0 + if self._right[0]: + assert self._degree_f is not None, "the plethysm with a lazy symmetric function of valuation 0 is defined only for symmetric functions of finite support" - def _compute_product(self, n, la, c): - """ + return sum((c * self.compute_product(n, la) + for k in range(self._left._approximate_order, self._degree_f) + if self._left[k] + for la, c in self._left[k]), + self._basis.zero()) + + res = sum((c * self.compute_product(n, la) + for k in range(self._left._approximate_order, n+1) + if self._left[k] + for la, c in self._left[k]), + self._basis.zero()) + return res + + def compute_product(self, n, la): + r""" Compute the product ``c * p[la](self._right)`` in degree ``n``. EXAMPLES:: - sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function + sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function, Stream_zero sage: s = SymmetricFunctions(QQ).s() sage: p = SymmetricFunctions(QQ).p() - sage: f = Stream_function(lambda n: s[n], s, True, 1) + sage: f = Stream_exact([1], False) # irrelevant for this test sage: g = Stream_exact([s[2], s[3]], False, 0, 4, 2) sage: h = Stream_plethysm(f, g, p) - sage: ret = h._compute_product(7, [2, 1], 1); ret + sage: A = h.compute_product(7, Partition([2, 1])); A 1/12*p[2, 2, 1, 1, 1] + 1/4*p[2, 2, 2, 1] + 1/6*p[3, 2, 2] + 1/12*p[4, 1, 1, 1] + 1/4*p[4, 2, 1] + 1/6*p[4, 3] - sage: ret == p[2,1](s[2] + s[3]).homogeneous_component(7) + sage: A == p[2, 1](s[2] + s[3]).homogeneous_component(7) + True + + sage: p2 = tensor([p, p]) + sage: f = Stream_exact([1], True) # irrelevant for this test + sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), True, 1) + sage: h = Stream_plethysm(f, g, p2) + sage: A = h.compute_product(7, Partition([2, 1])) + sage: B = p[2, 1](sum(g[n] for n in range(7))) + sage: B = p2.element_class(p2, {m: c for m, c in B if sum(mu.size() for mu in m) == 7}) + sage: A == B + True + + sage: f = Stream_exact([1], True) # irrelevant for this test + sage: g = Stream_function(lambda n: s[n], True, 0) + sage: h = Stream_plethysm(f, g, p) + sage: B = p[2, 2, 1](sum(s[i] for i in range(7))) + sage: all(h.compute_product(k, Partition([2, 2, 1])) == B.restrict_degree(k) for k in range(7)) True """ - p = self._p - ret = p.zero() - for mu in wt_int_vec_iter(n, la): - temp = c - for i, j in zip(la, mu): - gs = self._right[j] - if not gs: - temp = p.zero() - break - temp *= p[i](gs) - ret += temp + # This is the approximate order of the result + rao = self._right._approximate_order + ret_approx_order = rao * sum(la) + ret = self._basis.zero() + if n < ret_approx_order: + return ret + + la_exp = la.to_exp() + wgt = [i for i, m in enumerate(la_exp, 1) if m] + exp = [m for m in la_exp if m] + # the docstring of wt_int_vec_iter, i.e., iterator_fast, + # states that the weights should be weakly decreasing + wgt.reverse() + exp.reverse() + for k in wt_int_vec_iter(n - ret_approx_order, wgt): + # TODO: it may make a big difference here if the + # approximate order would be updated. + # The test below is based on not removing the fixed block + #if any(d < self._right._approximate_order * m + # for m, d in zip(exp, k)): + # continue + ret += prod(self.stretched_power_restrict_degree(i, m, rao * m + d) + for i, m, d in zip(wgt, exp, k)) return ret + def stretched_power_restrict_degree(self, i, m, d): + r""" + Return the degree ``d*i`` part of ``p([i]*m)(g)``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_plethysm, Stream_exact, Stream_function, Stream_zero + sage: s = SymmetricFunctions(QQ).s() + sage: p = SymmetricFunctions(QQ).p() + sage: f = Stream_exact([1], False) # irrelevant for this test + sage: g = Stream_exact([s[2], s[3]], False, 0, 4, 2) + sage: h = Stream_plethysm(f, g, p) + sage: A = h.stretched_power_restrict_degree(2, 3, 6) + sage: A == p[2,2,2](s[2] + s[3]).homogeneous_component(12) + True + + sage: p2 = tensor([p, p]) + sage: f = Stream_exact([1], True) # irrelevant for this test + sage: g = Stream_function(lambda n: sum(tensor([p[k], p[n-k]]) for k in range(n+1)), True, 1) + sage: h = Stream_plethysm(f, g, p2) + sage: A = h.stretched_power_restrict_degree(2, 3, 6) + sage: B = p[2,2,2](sum(g[n] for n in range(7))) # long time + sage: B = p2.element_class(p2, {m: c for m, c in B if sum(mu.size() for mu in m) == 12}) # long time + sage: A == B # long time + True + """ + while len(self._powers) < m: + self._powers.append(Stream_cauchy_mul(self._powers[-1], self._powers[0])) + power_d = self._powers[m-1][d] + # we have to check power_d for zero because it might be an + # integer and not a symmetric function + if power_d: + if self._tensor_power is None: + terms = {mon.stretch(i): raised_c for mon, c in power_d + if (raised_c := _raise_variables(c, i, self._degree_one))} + else: + terms = {tuple((mu.stretch(i) for mu in mon)): raised_c + for mon, c in power_d + if (raised_c := _raise_variables(c, i, self._degree_one))} + return self._p.element_class(self._p, terms) + + return self._p.zero() + + ##################################################################### # Unary operations class Stream_scalar(Stream_inexact): """ - Base class for operators multiplying a coefficient stream by a scalar. + Base class for operators multiplying a coefficient stream by a + scalar. + + .. TODO:: + + This does not inherit from :class:`Stream_unary`, because of + the extra argument ``scalar``. However, we could also + override :meth:`Stream_unary.hash`, + :meth:`Stream_unary.__eq__`. Would this be any better? + """ def __init__(self, series, scalar): """ @@ -1787,13 +2278,31 @@ def __init__(self, series, scalar): TESTS:: sage: from sage.data_structures.stream import (Stream_rmul, Stream_function) - sage: f = Stream_function(lambda n: -1, ZZ, True, 0) + sage: f = Stream_function(lambda n: -1, True, 0) sage: g = Stream_rmul(f, 3) """ self._series = series self._scalar = scalar assert scalar, "the scalar must not be equal to 0" - super().__init__(series._is_sparse, series._approximate_order) + super().__init__(series._is_sparse, series._true_order) + + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_rmul + sage: f = Stream_function(lambda n: Zmod(6)(n), True, 2) + sage: h = Stream_rmul(f, 3) # indirect doctest + sage: h._approximate_order + 2 + sage: [h[i] for i in range(5)] + [0, 0, 0, 3, 0] + """ + # this is not the true order, unless we have an integral domain + return self._series._approximate_order def __hash__(self): """ @@ -1803,7 +2312,7 @@ def __hash__(self): sage: from sage.data_structures.stream import Stream_function sage: from sage.data_structures.stream import Stream_rmul - sage: a = Stream_function(lambda n: 2*n, ZZ, False, 1) + sage: a = Stream_function(lambda n: 2*n, False, 1) sage: f = Stream_rmul(a, 2) sage: hash(f) == hash(f) True @@ -1822,8 +2331,8 @@ def __eq__(self, other): sage: from sage.data_structures.stream import Stream_function sage: from sage.data_structures.stream import Stream_rmul, Stream_lmul - sage: a = Stream_function(lambda n: 2*n, ZZ, False, 1) - sage: b = Stream_function(lambda n: n, ZZ, False, 1) + sage: a = Stream_function(lambda n: 2*n, False, 1) + sage: b = Stream_function(lambda n: n, False, 1) sage: f = Stream_rmul(a, 2) sage: f == Stream_rmul(b, 2) False @@ -1845,7 +2354,7 @@ def is_nonzero(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_rmul, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_rmul(f, 2) sage: g.is_nonzero() False @@ -1874,7 +2383,7 @@ class Stream_rmul(Stream_scalar): sage: from sage.data_structures.stream import (Stream_rmul, Stream_function) sage: W = algebras.DifferentialWeyl(QQ, names=('x',)) sage: x, dx = W.gens() - sage: f = Stream_function(lambda n: x^n, W, True, 1) + sage: f = Stream_function(lambda n: x^n, True, 1) sage: g = Stream_rmul(f, dx) sage: [g[i] for i in range(5)] [0, x*dx + 1, x^2*dx + 2*x, x^3*dx + 3*x^2, x^4*dx + 4*x^3] @@ -1890,7 +2399,7 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_rmul, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_rmul(f, 3) sage: g.get_coefficient(5) 15 @@ -1915,7 +2424,7 @@ class Stream_lmul(Stream_scalar): sage: from sage.data_structures.stream import (Stream_lmul, Stream_function) sage: W = algebras.DifferentialWeyl(QQ, names=('x',)) sage: x, dx = W.gens() - sage: f = Stream_function(lambda n: x^n, W, True, 1) + sage: f = Stream_function(lambda n: x^n, True, 1) sage: g = Stream_lmul(f, dx) sage: [g[i] for i in range(5)] [0, x*dx, x^2*dx, x^3*dx, x^4*dx] @@ -1931,7 +2440,7 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_lmul, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_lmul(f, 3) sage: g.get_coefficient(5) 15 @@ -1952,7 +2461,7 @@ class Stream_neg(Stream_unary): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_neg, Stream_function) - sage: f = Stream_function(lambda n: 1, ZZ, True, 1) + sage: f = Stream_function(lambda n: 1, True, 1) sage: g = Stream_neg(f) sage: [g[i] for i in range(10)] [0, -1, -1, -1, -1, -1, -1, -1, -1, -1] @@ -1964,10 +2473,29 @@ def __init__(self, series): TESTS:: sage: from sage.data_structures.stream import (Stream_neg, Stream_function) - sage: f = Stream_function(lambda n: -1, ZZ, True, 0) + sage: f = Stream_function(lambda n: -1, True, 0) sage: g = Stream_neg(f) """ - super().__init__(series, series._is_sparse, series._approximate_order) + super().__init__(series, series._is_sparse) + self._true_order = self._series._true_order + + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_neg + sage: f = Stream_function(lambda n: Zmod(6)(n), True, 2) + sage: h = Stream_neg(f) + sage: h._approximate_order + 2 + sage: [h[i] for i in range(5)] + [0, 0, 4, 3, 2] + """ + # this is the true order + return self._series._approximate_order def get_coefficient(self, n): """ @@ -1980,7 +2508,7 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_neg, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_neg(f) sage: g.get_coefficient(5) -5 @@ -1997,7 +2525,7 @@ def is_nonzero(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_neg, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_neg(f) sage: g.is_nonzero() False @@ -2010,6 +2538,7 @@ def is_nonzero(self): """ return self._series.is_nonzero() + class Stream_cauchy_invert(Stream_unary): """ Operator for multiplicative inverse of the stream. @@ -2018,15 +2547,19 @@ class Stream_cauchy_invert(Stream_unary): - ``series`` -- a :class:`Stream` + - ``approximate_order`` -- ``None``, or a lower bound on the + order of ``Stream_cauchy_invert(series)`` + EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: 1, ZZ, True, 1) + sage: f = Stream_function(lambda n: 1, True, 1) sage: g = Stream_cauchy_invert(f) sage: [g[i] for i in range(10)] [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0] + """ - def __init__(self, series): + def __init__(self, series, approximate_order=None): """ Initialize ``self``. @@ -2036,12 +2569,57 @@ def __init__(self, series): sage: f = Stream_exact([1, -1], False) sage: g = Stream_cauchy_invert(f) """ - v = series.order() - super().__init__(series, series._is_sparse, -v) - - self._ainv = ~series[v] + super().__init__(series, series._is_sparse) + if approximate_order is not None: + self._approximate_order = approximate_order self._zero = ZZ.zero() + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_cauchy_invert + sage: f = Stream_function(lambda n: GF(7)(n), True, 0) + sage: [f[i] for i in range(5)] + [0, 1, 2, 3, 4] + sage: h = Stream_cauchy_invert(f) + sage: h._approximate_order + -1 + sage: [h[i] for i in range(-2, 5)] + [0, 1, 5, 1, 0, 0, 0] + """ + try: + return -self._series.order() + except RecursionError: + raise ValueError("inverse does not exist") + + @lazy_attribute + def _ainv(self): + r""" + The inverse of the leading coefficient. + + EXAMPLES:: + + sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_exact) + sage: f = Stream_exact([2, -3], False) + sage: g = Stream_cauchy_invert(f) + sage: g._ainv + 1/2 + + sage: f = Stream_exact([Zmod(6)(5)], False, constant=2) + sage: g = Stream_cauchy_invert(f) + sage: g._ainv + 5 + """ + v = self._series.order() + try: + return ~self._series[v] + except TypeError: + return self._series[v].inverse_of_unit() + def get_coefficient(self, n): """ Return the ``n``-th coefficient of ``self``. @@ -2053,16 +2631,21 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, 1) + sage: f = Stream_function(lambda n: n, True, 1) sage: g = Stream_cauchy_invert(f) sage: g.get_coefficient(5) 0 sage: [g.get_coefficient(i) for i in range(10)] [-2, 1, 0, 0, 0, 0, 0, 0, 0, 0] """ + if not self._series._true_order: + self._ainv # this computes the true order of ``self`` v = self._approximate_order + if n < v: + return ZZ.zero() if n == v: return self._ainv + c = self._zero for k in range(v, n): l = self[k] @@ -2077,17 +2660,20 @@ def iterate_coefficients(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: n^2, ZZ, False, 1) + sage: f = Stream_function(lambda n: n^2, False, 1) sage: g = Stream_cauchy_invert(f) sage: n = g.iterate_coefficients() sage: [next(n) for i in range(10)] [1, -4, 7, -8, 8, -8, 8, -8, 8, -8] """ + yield self._ainv + # This is the true order, which is computed in self._ainv v = self._approximate_order n = 0 # Counts the number of places from v. - yield self._ainv # Note that the first entry of the cache will correspond to # z^v, when the stream corresponds to a Laurent series. + + # TODO: don't we need to distinguish between sparse and dense here? while True: n += 1 c = self._zero @@ -2112,47 +2698,67 @@ def is_nonzero(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: n^2, ZZ, False, 1) + sage: f = Stream_function(lambda n: n^2, False, 1) sage: g = Stream_cauchy_invert(f) sage: g.is_nonzero() True """ return True + class Stream_map_coefficients(Stream_inexact): r""" - The stream with ``function`` applied to each nonzero - coefficient of ``series``. + The stream with ``function`` applied to each nonzero coefficient + of ``series``. INPUT: - ``series`` -- a :class:`Stream` - ``function`` -- a function that modifies the elements of the stream - - ``ring`` -- the base ring of the stream EXAMPLES:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) - sage: f = Stream_function(lambda n: 1, ZZ, True, 1) - sage: g = Stream_map_coefficients(f, lambda n: -n, ZZ) + sage: f = Stream_function(lambda n: 1, True, 1) + sage: g = Stream_map_coefficients(f, lambda n: -n) sage: [g[i] for i in range(10)] [0, -1, -1, -1, -1, -1, -1, -1, -1, -1] + """ - def __init__(self, series, function, ring): + def __init__(self, series, function, approximate_order=None, true_order=False): """ Initialize ``self``. TESTS:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) - sage: f = Stream_function(lambda n: -1, ZZ, True, 0) - sage: g = Stream_map_coefficients(f, lambda n: n + 1, ZZ) + sage: f = Stream_function(lambda n: -1, True, 0) + sage: g = Stream_map_coefficients(f, lambda n: n + 1) sage: TestSuite(g).run(skip="_test_pickling") """ self._function = function - self._ring = ring self._series = series - super().__init__(series._is_sparse, series._approximate_order) + super().__init__(series._is_sparse, true_order) + if approximate_order is not None: + self._approximate_order = approximate_order + + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_map_coefficients + sage: f = Stream_function(lambda n: Zmod(6)(n), True, 2) + sage: h = Stream_map_coefficients(f, lambda c: 3*c) + sage: h._approximate_order + 2 + sage: [h[i] for i in range(5)] + [0, 0, 0, 3, 0] + """ + # this is not the true order + return self._series._approximate_order def get_coefficient(self, n): """ @@ -2165,25 +2771,20 @@ def get_coefficient(self, n): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) - sage: f = Stream_function(lambda n: n, ZZ, True, -1) - sage: g = Stream_map_coefficients(f, lambda n: n^2 + 1, ZZ) + sage: f = Stream_function(lambda n: n, True, -1) + sage: g = Stream_map_coefficients(f, lambda n: n^2 + 1) sage: g.get_coefficient(5) 26 sage: [g.get_coefficient(i) for i in range(-1, 10)] [2, 0, 2, 5, 10, 17, 26, 37, 50, 65, 82] sage: R. = ZZ[] - sage: f = Stream_function(lambda n: n, ZZ, True, -1) - sage: g = Stream_map_coefficients(f, lambda n: n.degree() + 1, R) + sage: f = Stream_function(lambda n: n, True, -1) + sage: g = Stream_map_coefficients(f, lambda n: R(n).degree() + 1) sage: [g.get_coefficient(i) for i in range(-1, 3)] [1, 0, 1, 1] - - sage: f = Stream_function(lambda n: n, ZZ, True, 0) - sage: g = Stream_map_coefficients(f, lambda n: 5, GF(3)) - sage: [g.get_coefficient(i) for i in range(10)] - [0, 5, 5, 0, 5, 5, 0, 5, 5, 0] """ - c = self._ring(self._series[n]) + c = self._series[n] if c: return self._function(c) return c @@ -2195,13 +2796,13 @@ def __hash__(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) - sage: f = Stream_function(lambda n: -1, ZZ, True, 0) - sage: g = Stream_map_coefficients(f, lambda n: n + 1, ZZ) + sage: f = Stream_function(lambda n: -1, True, 0) + sage: g = Stream_map_coefficients(f, lambda n: n + 1) sage: hash(g) == hash(g) True """ # We don't hash the function as it might not be hashable. - return hash((type(self), self._series, self._ring)) + return hash((type(self), self._series)) def __eq__(self, other): """ @@ -2214,18 +2815,17 @@ def __eq__(self, other): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_map_coefficients, Stream_function) - sage: f = Stream_function(lambda n: -1, ZZ, True, 0) + sage: f = Stream_function(lambda n: -1, True, 0) sage: def plus_one(n): return n + 1 - sage: g = Stream_map_coefficients(f, plus_one, ZZ) + sage: g = Stream_map_coefficients(f, plus_one) sage: g == f False - sage: g == Stream_map_coefficients(f, plus_one, QQ) + sage: g == Stream_map_coefficients(f, lambda n: n + 1) False - sage: g == Stream_map_coefficients(f, plus_one, ZZ) - True """ return (isinstance(other, type(self)) and self._series == other._series - and self._ring == other._ring and self._function == other._function) + and self._function == other._function) + class Stream_shift(Stream_inexact): """ @@ -2246,11 +2846,29 @@ def __init__(self, series, shift): sage: from sage.data_structures.stream import Stream_exact sage: h = Stream_exact([1], False, constant=3) sage: M = Stream_shift(h, 2) - sage: TestSuite(M).run() + sage: TestSuite(M).run(skip="_test_pickling") """ self._series = series self._shift = shift - super().__init__(series._is_sparse, series._approximate_order + shift) + super().__init__(series._is_sparse, series._true_order) + + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_shift + sage: f = Stream_function(lambda n: Zmod(6)(n), True, 2) + sage: h = Stream_shift(f, -2) + sage: h._approximate_order + 0 + sage: [h[i] for i in range(5)] + [2, 3, 4, 5, 0] + """ + # this is the true order + return self._series._approximate_order + self._shift def __getitem__(self, n): """ @@ -2260,7 +2878,7 @@ def __getitem__(self, n): sage: from sage.data_structures.stream import Stream_shift sage: from sage.data_structures.stream import Stream_function - sage: F = Stream_function(lambda n: n, ZZ, False, 1) + sage: F = Stream_function(lambda n: n, False, 1) sage: M = Stream_shift(F, 2) sage: [F[i] for i in range(6)] [0, 1, 2, 3, 4, 5] @@ -2277,7 +2895,7 @@ def __hash__(self): sage: from sage.data_structures.stream import Stream_shift sage: from sage.data_structures.stream import Stream_function - sage: F = Stream_function(lambda n: n, ZZ, False, 1) + sage: F = Stream_function(lambda n: n, False, 1) sage: M = Stream_shift(F, 2) sage: hash(M) == hash(M) True @@ -2296,7 +2914,7 @@ def __eq__(self, other): sage: from sage.data_structures.stream import Stream_shift sage: from sage.data_structures.stream import Stream_function - sage: F = Stream_function(lambda n: 1, ZZ, False, 1) + sage: F = Stream_function(lambda n: 1, False, 1) sage: M2 = Stream_shift(F, 2) sage: M3 = Stream_shift(F, 3) sage: M2 == M3 @@ -2317,10 +2935,137 @@ def is_nonzero(self): EXAMPLES:: sage: from sage.data_structures.stream import (Stream_cauchy_invert, Stream_function) - sage: f = Stream_function(lambda n: n^2, ZZ, False, 1) + sage: f = Stream_function(lambda n: n^2, False, 1) sage: g = Stream_cauchy_invert(f) sage: g.is_nonzero() True """ return self._series.is_nonzero() + +class Stream_derivative(Stream_inexact): + """ + Operator for taking derivatives of a stream. + + INPUT: + + - ``series`` -- a :class:`Stream` + - ``shift`` -- a positive integer + """ + def __init__(self, series, shift): + """ + Initialize ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_exact, Stream_derivative + sage: f = Stream_exact([1,2,3], False) + sage: f2 = Stream_derivative(f, 2) + sage: TestSuite(f2).run() + """ + self._series = series + self._shift = shift + super().__init__(series._is_sparse, False) + + @lazy_attribute + def _approximate_order(self): + """ + Compute and return the approximate order of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_derivative + sage: f = Stream_function(lambda n: Zmod(6)(n), True, 2) + sage: h = Stream_derivative(f, 3) + sage: h._approximate_order + 0 + sage: [h[i] for i in range(5)] + [0, 0, 0, 0, 0] + """ + # this is not the true order, unless multiplying by an + # integer cannot give 0 + if 0 <= self._series._approximate_order <= self._shift: + return 0 + return self._series._approximate_order - self._shift + + def __getitem__(self, n): + """ + Return the ``n``-th coefficient of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function, Stream_derivative + sage: f = Stream_function(lambda n: 1/n if n else 0, True, -2) + sage: [f[i] for i in range(-5, 3)] + [0, 0, 0, -1/2, -1, 0, 1, 1/2] + sage: f2 = Stream_derivative(f, 2) + sage: [f2[i] for i in range(-5, 3)] + [0, -3, -2, 0, 0, 1, 2, 3] + + sage: f = Stream_function(lambda n: 1/n, True, 2) + sage: [f[i] for i in range(-1, 4)] + [0, 0, 0, 1/2, 1/3] + sage: f2 = Stream_derivative(f, 3) + sage: [f2[i] for i in range(-1, 4)] + [0, 2, 6, 12, 20] + """ + return (prod(n+k for k in range(1, self._shift + 1)) + * self._series[n + self._shift]) + + def __hash__(self): + """ + Return the hash of ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function + sage: from sage.data_structures.stream import Stream_derivative + sage: a = Stream_function(lambda n: 2*n, False, 1) + sage: f = Stream_derivative(a, 1) + sage: g = Stream_derivative(a, 2) + sage: hash(f) == hash(f) + True + sage: hash(f) == hash(g) + False + + """ + return hash((type(self), self._series, self._shift)) + + def __eq__(self, other): + """ + Test equality. + + INPUT: + + - ``other`` -- a stream of coefficients + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_function + sage: from sage.data_structures.stream import Stream_derivative + sage: a = Stream_function(lambda n: 2*n, False, 1) + sage: f = Stream_derivative(a, 1) + sage: g = Stream_derivative(a, 2) + sage: f == g + False + sage: f == Stream_derivative(a, 1) + True + """ + return (isinstance(other, type(self)) and self._shift == other._shift + and self._series == other._series) + + def is_nonzero(self): + r""" + Return ``True`` if and only if this stream is known + to be nonzero. + + EXAMPLES:: + + sage: from sage.data_structures.stream import Stream_exact, Stream_derivative + sage: f = Stream_exact([1,2], False) + sage: Stream_derivative(f, 1).is_nonzero() + True + sage: Stream_derivative(f, 2).is_nonzero() # it might be nice if this gave False + True + """ + return self._series.is_nonzero() 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/databases/knotinfo_db.py b/src/sage/databases/knotinfo_db.py index bd066b73809..759ded16cac 100644 --- a/src/sage/databases/knotinfo_db.py +++ b/src/sage/databases/knotinfo_db.py @@ -75,6 +75,7 @@ class KnotInfoColumns(Enum): 'PD Notation (vector)', 'PD Notation (KnotTheory)', 'Braid Notation', + 'Quasipositive Braid', 'Multivariable Alexander Polynomial', 'HOMFLYPT Polynomial', 'Unoriented', @@ -822,6 +823,8 @@ def _test_database(self, **options): 'homfly_polynomial': ['HOMFLY', KnotInfoColumnTypes.OnlyKnots], 'homflypt_polynomial': ['HOMFLYPT Polynomial', KnotInfoColumnTypes.OnlyLinks], 'kauffman_polynomial': ['Kauffman', KnotInfoColumnTypes.KnotsAndLinks], + 'khovanov_polynomial': ['Khovanov', KnotInfoColumnTypes.KnotsAndLinks], + 'khovanov_torsion_polynomial': ['Khovanov Torsion', KnotInfoColumnTypes.OnlyKnots], 'determinant': ['Determinant', KnotInfoColumnTypes.KnotsAndLinks], 'positive': ['Positive', KnotInfoColumnTypes.OnlyKnots], 'fibered': ['Fibered', KnotInfoColumnTypes.OnlyKnots], @@ -1089,5 +1092,60 @@ def _test_database(self, **options): '1-3*t+ 3*t^2-3*t^3+ t^4', '1-3*t+ 5*t^2-3*t^3+ t^4', '1-t+ t^2-t^3+ t^4-t^5+ t^6', - '3-5*t+ 3*t^2'] + '3-5*t+ 3*t^2'], + dc.conway_polynomial: [ + '1', + '1+z^2', + '1-z^2', + '1+3*z^2+z^4', + '1+2*z^2', + '1-2*z^2', + '1-z^2-z^4', + '1+z^2+z^4', + '1+6*z^2+5*z^4+z^6', + '1+3*z^2', + '-z', + 'z', + '-2*z', + '2*z + z^3', + 'z^3', + 'z^3', + '-2*z + z^3', + '2*z + 2*z^3', + '-3*z-2*z^3', + '3*z + 2*z^3', + '-3*z-4*z^3-z^5'], + dc.khovanov_polynomial: [ + '', + 'q^(-9)t^(-3)+q^(-5)t^(-2)+q^(-3)+q^(-1)', + 'q^(-5)t^(-2)+q^(-1)t^(-1)+q+q^(-1)+qt+q^5t^2', + 'q^(-15)t^(-5)+q^(-11)t^(-4)+q^(-11)t^(-3)+q^(-7)t^(-2)+q^(-5)+q^(-3)', + 'q^(-13)t^(-5)+q^(-9)t^(-4)+q^(-9)t^(-3)+(q^(-7)+q^(-5))t^(-2)+q^(-3)t^(-1)+q^(-3)+q^(-1)', + 'q^(-9)t^(-4)+q^(-5)t^(-3)+q^(-5)t^(-2)+(q^(-3)+q^(-1))t^(-1)+2q+q^(-1)+qt+q^5t^2', + 'q^(-11)t^(-4)+(q^(-9)+q^(-7))t^(-3)+(q^(-7)+q^(-5))t^(-2)+(q^(-5)+q^(-3))t^(-1)+q^(-3)+2q^(-1)+tq^(-1)+q^3t^2', + 'q^(-7)t^(-3)+(q^(-5)+q^(-3))t^(-2)+(q^(-3)+q^(-1))t^(-1)+2q+2q^(-1)+t(q+q^3)+(q^3+q^5)t^2+q^7t^3', + 'q^(-21)t^(-7)+q^(-17)t^(-6)+q^(-17)t^(-5)+q^(-13)t^(-4)+q^(-13)t^(-3)+q^(-9)t^(-2)+q^(-7)+q^(-5)', + 'q^(-17)t^(-7)+q^(-13)t^(-6)+q^(-13)t^(-5)+(q^(-11)+q^(-9))t^(-4)+(q^(-9)+q^(-7))t^(-3)+(q^(-7)+q^(-5))t^(-2)+q^(-3)t^(-1)+q^(-3)+q^(-1)', + '1 + q^(-2) + 1/(q^6*t^2) + 1/(q^4*t^2)', + '1 + q^2 + q^4*t^2 + q^6*t^2', + '1 + q^(-2) + 1/(q^10*t^4) + 1/(q^8*t^4) + 1/(q^6*t^2) + 1/(q^2*t)', + 'q^2 + q^4 + q^6*t^2 + q^10*t^3 + q^10*t^4 + q^12*t^4', + '2 + 2/q^2 + 1/(q^8*t^3) + 1/(q^6*t^2) + 1/(q^4*t^2) + 1/(q^2*t) + t + q^4*t^2', + '2 + 2/q^2 + 1/(q^8*t^3) + 1/(q^6*t^2) + 1/(q^4*t^2) + 1/(q^2*t) + t + q^4*t^2', + '1 + 2/q^2 + 1/(q^10*t^4) + 1/(q^8*t^4) + 1/(q^8*t^3) + 2/(q^6*t^2) + 1/(q^4*t^2) + 2/(q^2*t) + t + q^2*t + q^4*t^2', + 'q^2 + q^4 + q^4*t + 2*q^6*t^2 + q^8*t^2 + 2*q^10*t^3 + 2*q^10*t^4 + q^12*t^4 + q^12*t^5 + q^14*t^5 + q^16*t^6', + 'q^(-4) + q^(-2) + 1/(q^16*t^6) + 1/(q^14*t^6) + 1/(q^14*t^5) + 1/(q^12*t^4) + 1/(q^10*t^4) + 1/(q^10*t^3) + 1/(q^8*t^3) + 1/(q^8*t^2) + 1/(q^6*t^2) + 1/(q^4*t)', + 'q^2 + q^4 + q^4*t + q^6*t^2 + q^8*t^2 + q^8*t^3 + q^10*t^3 + q^10*t^4 + q^12*t^4 + q^14*t^5 + q^14*t^6 + q^16*t^6', + 'q^(-6) + q^(-4) + 1/(q^18*t^6) + 1/(q^16*t^6) + 1/(q^16*t^5) + 1/(q^12*t^4) + 1/(q^12*t^3) + 1/(q^8*t^2)'], + dc.khovanov_torsion_polynomial: [ + '', + 'Q^(-7)t^(-2)', + 'Q^(-3)t^(-1)+Q^3t^2', + 'Q^(-13)t^(-4)+Q^(-9)t^(-2)', + 'Q^(-11)t^(-4)+Q^(-7)t^(-2)+Q^(-5)t^(-1)', + 'Q^(-7)t^(-3)+Q^(-3)t^(-1)+Q^(-1)+Q^3t^2', + 'Q^(-9)t^(-3)+Q^(-7)t^(-2)+Q^(-5)t^(-1)+Q^(-3)+Qt^2', + 'Q^(-5)t^(-2)+Q^(-3)t^(-1)+Q^(-1)+Qt+Q^3t^2+Q^5t^3', + 'Q^(-19)t^(-6)+Q^(-15)t^(-4)+Q^(-11)t^(-2)', + 'Q^(-15)t^(-6)+Q^(-11)t^(-4)+Q^(-9)t^(-3)+Q^(-7)t^(-2)+Q^(-5)t^(-1)'] } diff --git a/src/sage/databases/oeis.py b/src/sage/databases/oeis.py index ca5b3e65290..a800db53df2 100644 --- a/src/sage/databases/oeis.py +++ b/src/sage/databases/oeis.py @@ -28,13 +28,13 @@ :: - sage: search = oeis([3, 7, 15, 1], max_results=4) ; search # optional -- internet + sage: search = oeis([3, 7, 15, 1], max_results=4) ; search # optional -- internet # random 0: A001203: Simple continued fraction expansion of Pi. 1: A240698: Partial sums of divisors of n, cf. A027750. 2: A082495: a(n) = (2^n - 1) mod n. 3: A165416: Irregular array read by rows: The n-th row contains those distinct positive integers that each, when written in binary, occurs as a substring in binary n. - sage: [u.id() for u in search] # optional -- internet + sage: [u.id() for u in search] # optional -- internet # random ['A001203', 'A240698', 'A082495', 'A165416'] sage: c = search[0] ; c # optional -- internet A001203: Simple continued fraction expansion of Pi. @@ -349,7 +349,7 @@ class OEIS: The database can be searched by description:: - sage: oeis('prime gap factorization', max_results=4) # optional --internet + sage: oeis('prime gap factorization', max_results=4) # optional --internet # random 0: A073491: Numbers having no prime gaps in their factorization. 1: A073485: Product of any number of consecutive primes; squarefree numbers with no gaps in their prime factorization. 2: A073490: Number of prime gaps in factorization of n. @@ -491,7 +491,7 @@ def find_by_description(self, description, max_results=3, first_result=0): 2: A...: ... sage: prime_gaps = _[2] ; prime_gaps # optional -- internet - A073490: Number of prime gaps in factorization of n. + A... sage: oeis('beaver') # optional -- internet 0: A...: ...eaver... @@ -535,7 +535,7 @@ def find_by_subsequence(self, subsequence, max_results=3, first_result=0): EXAMPLES:: - sage: oeis.find_by_subsequence([2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]) # optional -- internet + sage: oeis.find_by_subsequence([2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]) # optional -- internet # random 0: A000045: Fibonacci numbers: F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1. 1: A212804: Expansion of (1 - x)/(1 - x - x^2). 2: A020695: Pisot sequence E(2,3). diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index 5e29cad2685..087c494ef39 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -1259,8 +1259,10 @@ def get_skeleton(self, check=False): def query(self, *args, **kwds): """ - Create a ``SQLQuery`` on this database. For full class details, - type ``SQLQuery?`` and press shift+enter. + Create a ``SQLQuery`` on this database. + + For full class details, + type ``SQLQuery?`` and press :kbd:`Shift` + :kbd:`Enter`. EXAMPLES:: diff --git a/src/sage/doctest/parsing.py b/src/sage/doctest/parsing.py index 1752caa851a..27fb25a273a 100644 --- a/src/sage/doctest/parsing.py +++ b/src/sage/doctest/parsing.py @@ -29,35 +29,8 @@ from sage.repl.preparse import preparse, strip_string_literals from functools import reduce - from .external import available_software -float_regex = re.compile(r'\s*([+-]?\s*((\d*\.?\d+)|(\d+\.?))([eE][+-]?\d+)?)') -optional_regex = re.compile(r'(arb216|arb218|py2|long time|not implemented|not tested|known bug)|([^ a-z]\s*optional\s*[:-]*((\s|\w|[.])*))') -# Version 4.65 of glpk prints the warning "Long-step dual simplex will -# be used" frequently. When Sage uses a system installation of glpk -# which has not been patched, we need to ignore that message. -# See :trac:`29317`. -glpk_simplex_warning_regex = re.compile(r'(Long-step dual simplex will be used)') -# :trac:`31204` -- suppress warning about ld and OS version for dylib files. -ld_warning_regex = re.compile(r'^.*dylib.*was built for newer macOS version.*than being linked.*') -# :trac:`30845` -- suppress warning on conda about ld -ld_pie_warning_regex = re.compile(r'ld: warning: -pie being ignored. It is only used when linking a main executable') -# :trac:`34533` -- suppress warning on OS X 12.6 about chained fixups -chained_fixup_warning_regex = re.compile(r'ld: warning: -undefined dynamic_lookup may not work with chained fixups') -sympow_cache_warning_regex = re.compile(r'\*\*WARNING\*\* /var/cache/sympow/datafiles/le64 yields insufficient permissions') -find_sage_prompt = re.compile(r"^(\s*)sage: ", re.M) -find_sage_continuation = re.compile(r"^(\s*)\.\.\.\.:", re.M) -find_python_continuation = re.compile(r"^(\s*)\.\.\.([^\.])", re.M) -python_prompt = re.compile(r"^(\s*)>>>", re.M) -# The following are used to allow ... at the beginning of output -ellipsis_tag = "" -continuation_tag = "" -random_marker = re.compile('.*random', re.I) -tolerance_pattern = re.compile(r'\b((?:abs(?:olute)?)|(?:rel(?:ative)?))? *?tol(?:erance)?\b( +[0-9.e+-]+)?') -backslash_replacer = re.compile(r"""(\s*)sage:(.*)\\\ * -\ *(((\.){4}:)|((\.){3}))?\ *""") - _RIFtol = None @@ -107,32 +80,6 @@ def fake_RIFtol(*args): ansi_escape_sequence = re.compile(r'(\x1b[@-Z\\-~]|\x1b\[.*?[@-~]|\x9b.*?[@-~])') -# Collection of fixups applied in the SageOutputChecker. Each element in this -# this list a pair of functions applied to the actual test output ('g' for -# "got") and the expected test output ('w' for "wanted"). The first function -# should be a simple fast test on the expected and/or actual output to -# determine if a fixup should be applied. The second function is the actual -# fixup, which is applied if the test function passes. In most fixups only one -# of the expected or received outputs are normalized, depending on the -# application. -_repr_fixups = [ - (lambda g, w: "Long-step" in g, - lambda g, w: (glpk_simplex_warning_regex.sub('', g), w)), - - (lambda g, w: "chained fixups" in g, - lambda g, w: (chained_fixup_warning_regex.sub('', g), w)), - - (lambda g, w: "insufficient permissions" in g, - lambda g, w: (sympow_cache_warning_regex.sub('', g), w)), - - (lambda g, w: "dylib" in g, - lambda g, w: (ld_warning_regex.sub('', g), w)), - - (lambda g, w: "pie being ignored" in g, - lambda g, w: (ld_pie_warning_regex.sub('', g), w)) -] - - def parse_optional_tags(string): """ Return a set consisting of the optional tags from the following @@ -190,6 +137,8 @@ def parse_optional_tags(string): # strip_string_literals replaces comments comment = "#" + (literals[comment]).lower() + optional_regex = re.compile(r'(arb216|arb218|py2|long time|not implemented|not tested|known bug)|([^ a-z]\s*optional\s*[:-]*((\s|\w|[.])*))') + tags = [] for m in optional_regex.finditer(comment): cmd = m.group(1) @@ -231,6 +180,10 @@ def parse_tolerance(source, want): sage: marked.abs_tol 0.010000000000000000000...? """ + # regular expressions + random_marker = re.compile('.*random', re.I) + tolerance_pattern = re.compile(r'\b((?:abs(?:olute)?)|(?:rel(?:ative)?))? *?tol(?:erance)?\b( +[0-9.e+-]+)?') + safe, literals, state = strip_string_literals(source) first_line = safe.split('\n', 1)[0] if '#' not in first_line: @@ -644,6 +597,17 @@ def parse(self, string, *args): sage: dte.want '...00010\n' """ + # Regular expressions + find_sage_prompt = re.compile(r"^(\s*)sage: ", re.M) + find_sage_continuation = re.compile(r"^(\s*)\.\.\.\.:", re.M) + find_python_continuation = re.compile(r"^(\s*)\.\.\.([^\.])", re.M) + python_prompt = re.compile(r"^(\s*)>>>", re.M) + backslash_replacer = re.compile(r"""(\s*)sage:(.*)\\\ * +\ *(((\.){4}:)|((\.){3}))?\ *""") + + # The following are used to allow ... at the beginning of output + ellipsis_tag = "" + # Hack for non-standard backslash line escapes accepted by the current # doctest system. m = backslash_replacer.search(string) @@ -942,13 +906,16 @@ def check_output(self, want, got, optionflags): sage: OC.check_output(ex.want, 'Long-step dual simplex will be used\n1.3090169943749475', optflag) True """ + # Regular expression for floats + float_regex = re.compile(r'\s*([+-]?\s*((\d*\.?\d+)|(\d+\.?))([eE][+-]?\d+)?)') + got = self.human_readable_escape_sequences(got) if isinstance(want, MarkedOutput): if want.random: return True elif want.tol or want.rel_tol or want.abs_tol: - # First check that the number of float appearing match + # First check that the number of occurrences of floats appearing match want_str = [g[0] for g in float_regex.findall(want)] got_str = [g[0] for g in float_regex.findall(got)] if len(want_str) != len(got_str): @@ -993,10 +960,18 @@ def do_fixup(self, want, got): A tuple: - - bool, True when some fixup were performed - - string, (unchanged) wanted string + - bool, ``True`` when some fixup were performed and ``False`` otherwise + - string, edited wanted string - string, edited got string + .. NOTE:: + + Currently, the code only possibly changes the string ``got`` + while keeping ``want`` invariant. We keep open the possibility + of adding a regular expression which would also change the + ``want`` string. This is why ``want`` is an input and an output + of the method even if currently kept invariant. + EXAMPLES:: sage: from sage.doctest.parsing import SageOutputChecker @@ -1029,11 +1004,41 @@ def do_fixup(self, want, got): """ did_fixup = False - for quick_check, fixup in _repr_fixups: - do_fixup = quick_check(got, want) - if do_fixup: - got, want = fixup(got, want) - did_fixup = True + # The conditions in the below `if` are simple fast test on the expected + # and/or actual output to determine if a fixup should be applied. + + if "Long-step" in got: + # Version 4.65 of glpk prints the warning "Long-step dual + # simplex will be used" frequently. When Sage uses a system + # installation of glpk which has not been patched, we need to + # ignore that message. See :trac:`29317`. + glpk_simplex_warning_regex = re.compile(r'(Long-step dual simplex will be used)') + got = glpk_simplex_warning_regex.sub('', got) + did_fixup = True + + if "chained fixups" in got: + # :trac:`34533` -- suppress warning on OS X 12.6 about chained fixups + chained_fixup_warning_regex = re.compile(r'ld: warning: -undefined dynamic_lookup may not work with chained fixups') + got = chained_fixup_warning_regex.sub('', got) + did_fixup = True + + if "insufficient permissions" in got: + sympow_cache_warning_regex = re.compile(r'\*\*WARNING\*\* /var/cache/sympow/datafiles/le64 yields insufficient permissions') + got = sympow_cache_warning_regex.sub('', got) + did_fixup = True + + if "dylib" in got: + # :trac:`31204` -- suppress warning about ld and OS version for + # dylib files. + ld_warning_regex = re.compile(r'^.*dylib.*was built for newer macOS version.*than being linked.*') + got = ld_warning_regex.sub('', got) + did_fixup = True + + if "pie being ignored" in got: + # :trac:`30845` -- suppress warning on conda about ld + ld_pie_warning_regex = re.compile(r'ld: warning: -pie being ignored. It is only used when linking a main executable') + got = ld_pie_warning_regex.sub('', got) + did_fixup = True return did_fixup, want, got @@ -1166,6 +1171,9 @@ def output_difference(self, example, got, optionflags): Tolerance exceeded: 0.0 vs 10.05, tolerance +infinity > 1e-1 """ + # Regular expression for floats + float_regex = re.compile(r'\s*([+-]?\s*((\d*\.?\d+)|(\d+\.?))([eE][+-]?\d+)?)') + got = self.human_readable_escape_sequences(got) want = example.want diff = doctest.OutputChecker.output_difference(self, example, got, optionflags) diff --git a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py index 92f10c05a9a..7810a88fd7f 100644 --- a/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/berkovich_ds.py @@ -1,5 +1,5 @@ r""" -Dynamical systmes on Berkovich space over `\CC_p`. +Dynamical systems on Berkovich space over `\CC_p`. A dynamical system on Berkovich space over `\CC_p` is determined by a dynamical system on `A^1(\CC_p)` or `P^1(\CC_p)`, diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py index 8424b2fc505..72f63af7eac 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_automorphism_group.py @@ -1907,7 +1907,7 @@ def conjugating_set_initializer(f, g): repeated_mult_L[repeated] += [mult_to_point_L[mult_L]] more = True - # the n+2 points to be used to specificy PGL conjugations + # the n+2 points to be used to specify PGL conjugations source = [] # a list of tuples of the form ((multiplier, level), repeat) where the @@ -1997,9 +1997,10 @@ def conjugating_set_initializer(f, g): for r in sorted(repeated_mult_L.keys()): for point_lst in repeated_mult_L[r]: all_points += point_lst - # this loop is quite long, so we break after finding the first subset - # with the desired property. There is, however, no guarentee that the - # subset we found minimizes the combinatorics when checking conjugations + # this loop is quite long, so we break after finding the + # first subset with the desired property. There is, + # however, no guarantee that the subset we found minimizes + # the combinatorics when checking conjugations for subset in Subsets(range(len(all_points)), n+2): source = [] for i in subset: @@ -2166,10 +2167,10 @@ def conjugating_set_helper(f, g, num_cpus, source, possible_targets): subset_iterators.append(Subsets(range(len(lst[0])), lst[1])) # helper function for parallelization - # given a list of tuples which specify indicies of possible target points - # in possible_targets, check all arragements of those possible target points - # and if any of them define a conjugation which sends f to g, return - # those conjugations as a list + # given a list of tuples which specify indices of possible target + # points in possible_targets, check all arrangements of those + # possible target points and if any of them define a conjugation + # which sends f to g, return those conjugations as a list def find_conjugations_subset(tuples): conj = [] for tup in tuples: @@ -2195,9 +2196,9 @@ def find_conjugations_subset(tuples): return conj # helper function for parallelization - # given a list of tuples which specify indicies of possible target points - # in possible_targets, check all possible target points - # and if any of them define a conjugation which sends f to g, return + # given a list of tuples which specify indices of possible target + # points in possible_targets, check all possible target points and + # if any of them define a conjugation which sends f to g, return # those conjugations as a list def find_conjugations_arrangement(tuples): conj = [] @@ -2229,7 +2230,7 @@ def find_conjugations_arrangement(tuples): if ret[1]: Conj += ret[1] # otherwise, we need to first check linear independence of the subsets - # and then build a big list of all the arrangemenets to split among + # and then build a big list of all the arrangements to split among # the threads else: good_targets = [] @@ -2307,9 +2308,10 @@ def is_conjugate_helper(f, g, num_cpus, source, possible_targets): subset_iterators.append(Subsets(range(len(lst[0])), lst[1])) # helper function for parallelization - # given a list of tuples which specify indicies of possible target points - # in possible_targets, check all arragements of those possible target points - # and if any of them define a conjugation which sends f to g, return True + # given a list of tuples which specify indices of possible target + # points in possible_targets, check all arrangements of those + # possible target points and if any of them define a conjugation + # which sends f to g, return True def find_conjugations_subset(tuples): for tup in tuples: target_set = [] @@ -2334,7 +2336,7 @@ def find_conjugations_subset(tuples): return False # helper function for parallelization - # given a list of tuples which specify indicies of possible target points + # given a list of tuples which specify indices of possible target points # in possible_targets, check all possible target points # and if any of them define a conjugation which sends f to g, return True def find_conjugations_arrangement(tuples): @@ -2367,7 +2369,7 @@ def find_conjugations_arrangement(tuples): is_conj = True break # otherwise, we need to first check linear independence of the subsets - # and then build a big list of all the arrangemenets to split among + # and then build a big list of all the arrangements to split among # the threads else: good_targets = [] diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index cc5684832af..b1f5b45fe4a 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -52,6 +52,7 @@ class initialization directly. # https://www.gnu.org/licenses/ # **************************************************************************** +from typing_extensions import final from sage.arith.misc import is_prime from sage.misc.lazy_import import lazy_import lazy_import('sage.calculus.functions', 'jacobian') @@ -71,6 +72,7 @@ class initialization directly. from sage.rings.integer import Integer from sage.arith.all import gcd, lcm, next_prime, binomial, primes, moebius from sage.categories.finite_fields import FiniteFields +from sage.rings.algebraic_closure_finite_field import AlgebraicClosureFiniteField_generic from sage.rings.complex_mpfr import ComplexField from sage.rings.finite_rings.finite_field_constructor import (is_FiniteField, GF, is_PrimeFiniteField) @@ -1104,6 +1106,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 @@ -3073,13 +3372,18 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): sage: g = f.affine_preperiodic_model(0, 1); g Dynamical System of Projective Space of dimension 2 over Rational Field Defn: Defined on coordinates by sending (x : y : z) to - (-x^2 : 2*x^2 + 2*x*y + y^2 : 2*x^2 + 2*x*y + 2*y^2 - 2*y*z + z^2) + (-x^2 : -2*x^2 + 2*x*y - y^2 : 2*x^2 - 2*x*y + 2*y^2 + 2*y*z + z^2) We can check that ``g`` has affine fixed points:: sage: g.periodic_points(1) - [(-1 : 1 : 1), (-1/2 : 1/2 : 1), (-1/2 : 1 : 1), (-1/3 : 2/3 : 1), (0 : 0 : 1), - (0 : 1/2 : 1), (0 : 1 : 1)] + [(-1 : -1 : 1), + (-1/2 : -1 : 1), + (-1/2 : -1/2 : 1), + (-1/3 : -2/3 : 1), + (0 : -1 : 1), + (0 : -1/2 : 1), + (0 : 0 : 1)] :: @@ -3088,8 +3392,8 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): sage: f.affine_preperiodic_model(0, 1) Dynamical System of Projective Space of dimension 2 over Finite Field in z2 of size 3^2 Defn: Defined on coordinates by sending (x : y : z) to - ((z2 + 1)*x^2 : (z2 + 1)*x^2 + (z2 + 1)*x*y + (-z2 - 1)*y^2 : - (z2 - 1)*x^2 + (z2 - 1)*x*y - y^2 + (-z2)*y*z + z^2) + ((-z2)*x^2 : z2*x^2 + (-z2)*x*y + (-z2)*y^2 : + (-z2)*x^2 + z2*x*y + (z2 + 1)*y^2 - y*z + z^2) :: @@ -3100,9 +3404,8 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): Dynamical System of Projective Space of dimension 2 over Univariate Polynomial Ring in c over Finite Field of size 3 Defn: Defined on coordinates by sending (x : y : z) to - ((2*c^4 + c^3)*x^2 : (2*c^4 + c^3)*x^2 + (2*c^4 + c^3)*x*y + (c^4 + 2*c^3)*y^2 : - c^3*x^2 + c^3*x*y + (2*c^3 + 2*c^2)*y^2 + (c^3 + 2*c^2)*y*z + (2*c^4 + 2*c^3 + - 2*c^2)*z^2) + (2*c^3*x^2 : c^3*x^2 + 2*c^3*x*y + 2*c^3*y^2 : + 2*c^3*x^2 + c^3*x*y + (c^3 + c^2)*y^2 + 2*c^2*y*z + c^2*z^2) :: @@ -3113,8 +3416,7 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): Dynamical System of Projective Space of dimension 2 over Cyclotomic Field of order 3 and degree 2 Defn: Defined on coordinates by sending (x : y : z) to - (x^2 + y^2 + (-k + 2)*x*z - 2*y*z + (-k + 3)*z^2 : - -2*x^2 + (k - 4)*x*z + (k - 3)*z^2 : -x^2 + (k - 2)*x*z + (k - 2)*z^2) + (-y^2 : x^2 : x^2 + (-k)*x*z + z^2) :: @@ -3133,8 +3435,7 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): Dynamical System of Closed subscheme of Projective Space of dimension 2 over Rational Field defined by: 2*y - z Defn: Defined on coordinates by sending (x : y : z) to - (2*x^2 + y^2 + 4*x*z - 2*y*z + 4*z^2 : -x^2 - y^2 - 2*x*z + 2*y*z - 3*z^2 : - -x^2 - 2*x*z - 2*z^2) + (-x^2 - y^2 : y^2 : x^2 + z^2) TESTS:: @@ -4220,7 +4521,7 @@ def preperiodic_points(self, m, n, **kwds): f_deformed = DynamicalSystem(deformed_polys) # after deforming by the parameter, the preperiodic points with multiplicity - # will seperate into different points. we can now calculate the minimal preperiodic + # will separate into different points. we can now calculate the minimal preperiodic # points with the parameter, and then specialize to get the formal preperiodic points ideal = f_deformed.preperiodic_points(m, n, return_scheme=True).defining_ideal() L = [poly.specialization({t:0}) for poly in ideal.gens()] @@ -4570,7 +4871,7 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari f_deformed = DynamicalSystem(deformed_polys) # after deforming by the parameter, the preperiodic points with multiplicity - # will seperate into different points. we can now calculate the minimal preperiodic + # will separate into different points. we can now calculate the minimal preperiodic # points with the parameter, and then specialize to get the formal periodic points ideal = f_deformed.periodic_points(n, return_scheme=True).defining_ideal() L = [poly.specialization({t:0}) for poly in ideal.gens()] @@ -4627,20 +4928,22 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari else: raise ValueError("algorithm must be either 'variety' or 'cyclegraph'") - def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closure=True): + def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closure=True, check=True): r""" Computes the ``n`` multiplier spectra of this dynamical system. - This is the set of multipliers of the periodic points of formal + This is the set of multipliers of all peroidic points of period ``n`` included with the appropriate multiplicity. - User can also specify to compute the ``n`` multiplier spectra - instead which includes the multipliers of all periodic points - of period ``n``. The map must be defined over - projective space of dimension 1 over a number field or finite field. + User can also specify to compute the formal ``n`` multiplier spectra + instead which includes the multipliers of all formal periodic points + of period ``n`` with appropriate multiplicity. The map must be defined over + projective space over a number field or finite field. - The computations can be done either over the algebraic closure of the - base field or over the minimal extension of the base field that - contains the critical points. + By default, the computations are done over the algebraic closure of the + base field. If the map is defined over projective space of dimension 1, + the computation can be done over the minimal extension of the base field that + contains the periodic points. Otherwise, it will be done over the base ring + of the map. INPUT: @@ -4654,37 +4957,67 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur or ``'cycle'`` depending on whether you compute one multiplier per point or one per cycle - - ``use_algebraic_closure`` -- boolean (default: True) -- If True uses the - algebraic closure. If False, uses the smallest extension of the base field - containing all the critical points. + - ``use_algebraic_closure`` -- boolean (default: ``True``) -- If ``True`` uses the + algebraic closure. Using the algebraic closure can sometimes lead to numerical instability + and extraneous errors. For most accurate results in dimension 1, set to ``False``. + If ``False``, and the map is defined over projective space of + dimension 1, uses the smallest extension of the base field + containing all the periodic points. If the map is defined over projective space + of dimension greater than 1, then the base ring of the map is used. - OUTPUT: a list of field elements + - ``check`` -- (defualt: ``True``) whether to check if the + full multiplier spectra was computed. If ``False``, can lead to + mathematically incorrect answers in dimension greater than 1. Ignored + if ``use_algebraic_closure`` is ``True`` or if this dynamical system is defined + over projective space of dimension 1. + + OUTPUT: + + A list of field elements if the domain of the map is projective space of + dimension 1. If the domain of the map is projective space of dimension + greater than 1, a list of matrices EXAMPLES:: - sage: P. = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([4608*x^10 - 2910096*x^9*y + 325988068*x^8*y^2 + 31825198932*x^7*y^3 - 4139806626613*x^6*y^4\ - - 44439736715486*x^5*y^5 + 2317935971590902*x^4*y^6 - 15344764859590852*x^3*y^7 + 2561851642765275*x^2*y^8\ - + 113578270285012470*x*y^9 - 150049940203963800*y^10, 4608*y^10]) - sage: sorted(f.multiplier_spectra(1)) - [-119820502365680843999, - -7198147681176255644585/256, - -3086380435599991/9, - -3323781962860268721722583135/35184372088832, - -4290991994944936653/2097152, - 0, - 529278480109921/256, - 1061953534167447403/19683, - 848446157556848459363/19683, - 82911372672808161930567/8192, - 3553497751559301575157261317/8192] + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([x^2 - 3/4*y^2, y^2]) + sage: sorted(f.multiplier_spectra(2, type='point')) + [0, 1, 1, 1, 9] + sage: sorted(f.multiplier_spectra(2, type='cycle')) + [0, 1, 1, 9] + + :: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem_projective([x^2, z^2, y^2]) + sage: f.multiplier_spectra(1) + [ + [ 2 1 - 1.732050807568878?*I] + [ 0 -2], + [ 2 1 + 1.732050807568878?*I] [ 0 0] [ 0 0] + [ 0 -2], [ 0 -2], [ 0 -2], + [ 0 0] [0 0] [ 2 -2] + [ 0 -2], [0 0], [ 0 -2] + ] + + :: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem_projective([x^2, z^2, y^2]) + sage: f.multiplier_spectra(2, formal=True) + [ + [4 0] [4 0] [4 0] [4 0] [4 0] [4 0] [4 0] [4 0] [0 0] [0 0] + [0 4], [0 0], [0 0], [0 4], [0 4], [0 0], [0 0], [0 4], [0 0], [0 0], + [4 0] [4 0] [4 0] [4 0] + [0 4], [0 4], [0 0], [0 0] + ] :: sage: set_verbose(None) sage: z = QQ['z'].0 sage: K. = NumberField(z^4 - 4*z^2 + 1,'z') - sage: P. = ProjectiveSpace(K,1) + sage: P. = ProjectiveSpace(K, 1) sage: f = DynamicalSystem_projective([x^2 - w/4*y^2, y^2]) sage: sorted(f.multiplier_spectra(2, formal=False, type='cycle')) [0, @@ -4694,16 +5027,26 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur :: - sage: P. = ProjectiveSpace(QQ,1) - sage: f = DynamicalSystem_projective([x^2 - 3/4*y^2, y^2]) - sage: sorted(f.multiplier_spectra(2, formal=False, type='cycle')) - [0, 1, 1, 9] - sage: sorted(f.multiplier_spectra(2, formal=False, type='point')) - [0, 1, 1, 1, 9] + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = DynamicalSystem_projective([4608*x^10 - 2910096*x^9*y + 325988068*x^8*y^2 + 31825198932*x^7*y^3 - 4139806626613*x^6*y^4\ + - 44439736715486*x^5*y^5 + 2317935971590902*x^4*y^6 - 15344764859590852*x^3*y^7 + 2561851642765275*x^2*y^8\ + + 113578270285012470*x*y^9 - 150049940203963800*y^10, 4608*y^10]) + sage: sorted(f.multiplier_spectra(1)) + [-119820502365680843999, + -7198147681176255644585/256, + -3086380435599991/9, + -3323781962860268721722583135/35184372088832, + -4290991994944936653/2097152, + 0, + 529278480109921/256, + 1061953534167447403/19683, + 848446157556848459363/19683, + 82911372672808161930567/8192, + 3553497751559301575157261317/8192] :: - sage: P. = ProjectiveSpace(QQ,1) + sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([x^2 - 7/4*y^2, y^2]) sage: f.multiplier_spectra(3, formal=True, type='cycle') [1, 1] @@ -4712,7 +5055,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur :: - sage: P. = ProjectiveSpace(QQ,1) + sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([x^4 + 3*y^4, 4*x^2*y^2]) sage: f.multiplier_spectra(1, use_algebraic_closure=False) [0, @@ -4729,7 +5072,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur :: - sage: P. = ProjectiveSpace(GF(5),1) + sage: P. = ProjectiveSpace(GF(5), 1) sage: f = DynamicalSystem_projective([x^4 + 2*y^4, 4*x^2*y^2]) sage: f.multiplier_spectra(1, use_algebraic_closure=False) [0, 3*a + 3, 2*a + 1, 1, 1] @@ -4738,7 +5081,7 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur :: - sage: P. = ProjectiveSpace(QQbar,1) + sage: P. = ProjectiveSpace(QQbar, 1) sage: f = DynamicalSystem_projective([x^5 + 3*y^5, 4*x^3*y^2]) sage: f.multiplier_spectra(1) [0, @@ -4751,25 +5094,73 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur :: sage: K = GF(3).algebraic_closure() - sage: P. = ProjectiveSpace(K,1) + sage: P. = ProjectiveSpace(K, 1) sage: f = DynamicalSystem_projective([x^5 + 2*y^5, 4*x^3*y^2]) sage: f.multiplier_spectra(1) [0, z3 + 2, z3 + 1, z3, 1, 1] TESTS:: - sage: P. = ProjectiveSpace(QQ,1) + sage: P. = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([x^2 + y^2, x*y]) sage: f.multiplier_spectra(1) [1, 1, 1] + :: + + sage: K = GF(3).algebraic_closure() + sage: P. = ProjectiveSpace(K, 2) + sage: f = DynamicalSystem_projective([x^2 + 2*y^2, 4*x*y, z^2]) + sage: f.multiplier_spectra(1) + [ + [0 0] [1 0] [1 0] [1 0] [2 0] [2 0] [2 0] + [0 0], [0 0], [0 0], [0 0], [0 1], [0 1], [0 1] + ] + :: sage: F. = GF(7) - sage: P.=ProjectiveSpace(F,1) + sage: P.=ProjectiveSpace(F, 1) sage: f = DynamicalSystem_projective([x^2 + y^2, y^2]) sage: sorted(f.multiplier_spectra(1)) [0, 3, 6] + + :: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem_projective([x^2, z^2, y^2]) + sage: g = f.change_ring(QQbar) + sage: f.multiplier_spectra(1) == g.multiplier_spectra(1) + True + + :: + + sage: K. = QuadraticField(5) + sage: P. = ProjectiveSpace(K, 2) + sage: f = DynamicalSystem_projective([x^2 + w*x*y + y^2, y^2, z^2]) + sage: f.multiplier_spectra(1) + [ + [1.000000000000000? - 1.572302755514847?*I 0] + [1.000000000000000? - 1.572302755514847?*I 0.618033988749895? - 1.757887921270715?*I] + [1.000000000000000? + 1.572302755514847?*I 0] + [1.000000000000000? + 1.572302755514847?*I 0.618033988749895? + 1.757887921270715?*I] + [ 0 0], + [ 0 2], + [ 0 0], + [ 0 2], + [0 0] [0 0] [ 2 2.236067977499790?] + [0 0], [0 0], [ 0 0] + ] + + :: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: f = DynamicalSystem_projective([x^2, z^2, y^2]) + sage: f.multiplier_spectra(1, use_algebraic_closure=False) + Traceback (most recent call last): + ... + ValueError: failed to compute the full multiplier spectra. Try use_algebraic_closure=True + or extend the base ring of this dynamical system """ PS = self.domain() n = Integer(n) @@ -4778,43 +5169,138 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur raise ValueError("period must be a positive integer") if not is_ProjectiveSpace(PS): raise NotImplementedError("not implemented for subschemes") - if (PS.dimension_relative() > 1): - raise NotImplementedError("only implemented for dimension 1") - K = FractionField(self.codomain().base_ring()) - if use_algebraic_closure: - Kbar = K.algebraic_closure() - if Kbar.has_coerce_map_from(K): - f = self.change_ring(Kbar) + if PS.dimension_relative() > 1: + K = self.domain().base_ring() + + # if we are already using an algebraic closure, we move the + # map into a finite extension and set use_algebraic_closure to True + # in order to get a scheme defined over a finite extension + if K is QQbar or isinstance(K, AlgebraicClosureFiniteField_generic): + f = self.reduce_base_field() + K = f.base_ring() + use_algebraic_closure = True else: - embeds = K.embeddings(Kbar) - if embeds: - f = self.change_ring(embeds[0]) + f = self + + # in order to calculate multiplicity, we need to have a scheme defined + # over a finite extension, not an algebraic closure + X = f.periodic_points(n, minimal=False, formal=formal, return_scheme=True) + if use_algebraic_closure: + number_field = False + finite_field = False + if K in NumberFields(): + number_field = True + if K in FiniteFields(): + finite_field = True + if not(number_field or finite_field): + raise NotImplementedError('Only implemented for number fields, QQbar, finite fields, and algebraic closures of finite fields') + Kbar = K.algebraic_closure() + if Kbar.has_coerce_map_from(K): + f = f.change_ring(Kbar) + rat_points = X.rational_points(F=Kbar) else: - raise ValueError("no embeddings of base field to algebraic closure") + embeds = K.embeddings(Kbar) + if embeds: + X2 = X.change_ring(embeds[0]) + rat_points = X2.rational_points() + f = self.change_ring(embeds[0]) + else: + raise ValueError("no embeddings of base field to algebraic closure") + else: + rat_points = X.rational_points() + f = self + PS = f.domain() + points = [] + for point in rat_points: + if use_algebraic_closure: + if number_field: + # in order to calculate multiplicity, the point must be defined over a finite extension + K2, pnt_lst, _ = number_field_elements_from_algebraics(list(point)) + # we coerce if we can + if K.has_coerce_map_from(K2): + for i in range(X.multiplicity(pnt_lst)): + points.append(PS(point)) + elif K2.has_coerce_map_from(K): + X_k = X.change_ring(K2) + for i in range(X_k.multiplicity(pnt_lst)): + points.append(PS(point)) + # otherwise, we need to calculate a composite field + else: + _, K_embed, K2_embed, _ = K.composite_fields(K2, both_maps=True)[0] + X_k = X.change_ring(K_embed) + pnt_lst = [K2_embed(pnt) for pnt in pnt_lst] + new_point = X_k.ambient_space()(pnt_lst) + for i in range(X_k.multiplicity(new_point)): + points.append(PS(point)) + else: + # we find a finite extension which the current point + # and X coerce into + final_degree = K.degree() + new_point = [] + for num in list(point): + ff_num = num.as_finite_field_element()[1] + new_point.append(ff_num) + degree = ff_num.parent().degree() + final_degree = final_degree.lcm(degree) + K_prime = GF(K.characteristic()**final_degree) + X_k = X.change_ring(K_prime) + for i in range(X_k.multiplicity(new_point)): + points.append(PS(point)) + else: + for i in range(X.multiplicity(point)): + points.append(point) + if not use_algebraic_closure: + if check: + # we check if we computed the full multiplier spectra + d = self.degree() + N = self.domain().ambient_space().dimension_relative() + if not formal: + expected_number = sum(d**(n*i) for i in range(N+1)) + else: + expected_number = 0 + for D in n.divisors(): + u = moebius(n/D) + inner_sum = sum(d**(D*j) for j in range(N+1)) + expected_number += u*inner_sum + if len(points) != expected_number: + raise ValueError('failed to compute the full multiplier spectra. Try use_algebraic_closure=True' + + ' or extend the base ring of this dynamical system') else: - embedding = self.field_of_definition_periodic(n, formal=formal, return_embedding=True)[1] - f = self.change_ring(embedding) + K = FractionField(self.codomain().base_ring()) + if use_algebraic_closure: + Kbar = K.algebraic_closure() + if Kbar.has_coerce_map_from(K): + f = self.change_ring(Kbar) + else: + embeds = K.embeddings(Kbar) + if embeds: + f = self.change_ring(embeds[0]) + else: + raise ValueError("no embeddings of base field to algebraic closure") + else: + embedding = self.field_of_definition_periodic(n, formal=formal, return_embedding=True)[1] + f = self.change_ring(embedding) - PS = f.domain() - if not formal: - G = f.nth_iterate_map(n) - F = G[0]*PS.gens()[1] - G[1]*PS.gens()[0] - else: - # periodic points of formal period n are the roots of the nth dynatomic polynomial - F = f.dynatomic_polynomial(n) + PS = f.domain() + if not formal: + G = f.nth_iterate_map(n) + F = G[0]*PS.gens()[1] - G[1]*PS.gens()[0] + else: + # periodic points of formal period n are the roots of the nth dynatomic polynomial + F = f.dynatomic_polynomial(n) - other_roots = F.parent()(F([(f.domain().gens()[0]),1])).univariate_polynomial().roots(ring=f.base_ring()) + other_roots = F.parent()(F([(f.domain().gens()[0]),1])).univariate_polynomial().roots(ring=f.base_ring()) - points = [] + points = [] - minfty = min(ex[1] for ex in F.exponents()) # include the point at infinity with the right multiplicity - for i in range(minfty): - points.append(PS([1,0])) + minfty = min(ex[1] for ex in F.exponents()) # include the point at infinity with the right multiplicity + for i in range(minfty): + points.append(PS([1,0])) - for R in other_roots: - for i in range(R[1]): - points.append(PS([R[0],1])) # include copies of higher multiplicity roots + for R in other_roots: + for i in range(R[1]): + points.append(PS([R[0],1])) # include copies of higher multiplicity roots if type == 'cycle': # should include one representative point per cycle, included with the right multiplicity @@ -4833,7 +5319,10 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur Q = f(Q) points = newpoints - multipliers = [f.multiplier(pt,n)[0,0] for pt in points] + if PS.dimension_relative() > 1: + multipliers = [f.multiplier(pt,n) for pt in points] + else: + multipliers = [f.multiplier(pt,n)[0,0] for pt in points] return multipliers @@ -4902,7 +5391,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', - ``n`` periodic points are repeated, multipliers are all distinct -- to deal with this case, we deform the map by a formal parameter `k`. The deformation - seperates the ``n`` periodic points, making them distinct, and we can recover + separates the ``n`` periodic points, making them distinct, and we can recover the ``n`` periodic points of the original map by specializing `k` to 0. This corresponds to ``deform=True``. @@ -4953,7 +5442,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', - ``check`` -- (default: ``True``) boolean; when ``True`` the degree of the sigma polynomial is checked against the expected degree. This is - done as the sigma polynomial may drop degree if multiplicites of periodic + done as the sigma polynomial may drop degree if multiplicities of periodic points or multipliers are not correctly accounted for using ``chow`` or ``deform``. @@ -5237,8 +5726,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', # create polynomial ring for result R2 = PolynomialRing(F, var[:N] + var[-2:]) psi = R2.hom(N*[0]+list(newR.gens()), newR) - # create substition to set extra variables to 0 - R_zero = {R.gen(N):1} + # create substitution to set extra variables to 0 + R_zero = {R.gen(N): 1} for j in range(N+1, 2*N+1): R_zero[R.gen(j)] = 0 t = var.pop() @@ -5252,7 +5741,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', w = var.pop() sigma_polynomial = 1 # go through each affine patch to avoid repeating periodic points - # setting the visited coordiantes to 0 as we go + # setting the visited coordinates to 0 as we go for j in range(N,-1,-1): Xa = X.affine_patch(j) fa = Fn.dehomogenize(j) @@ -5309,7 +5798,7 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', 'try setting chow=True and/or deform=True') if return_polynomial: return sigma_polynomial - # if we are returing a numerical list, read off the coefficients + # if we are returning a numerical list, read off the coefficients # in order of degree adjusting sign appropriately sigmas = [] sigma_dictionary = dict([list(reversed(i)) for i in list(sigma_polynomial)]) @@ -6834,7 +7323,7 @@ def conjugating_set(self, other, R=None, num_cpus=2): by taking the fixed points of one map and mapping them to permutations of the fixed points of the other map. As conjugacy preserves the multipliers as a set, fixed points - are only maped to fixed points with the same multiplier. + are only mapped to fixed points with the same multiplier. If there are not enough fixed points the function compares the mapping between rational preimages of fixed points and the rational preimages of the preimages of diff --git a/src/sage/dynamics/cellular_automata/catalog.py b/src/sage/dynamics/cellular_automata/catalog.py index 480f073bf7a..44c28f07cb5 100644 --- a/src/sage/dynamics/cellular_automata/catalog.py +++ b/src/sage/dynamics/cellular_automata/catalog.py @@ -6,7 +6,7 @@ this object is an easy way to discover and quickly create the cellular automata that are available (as listed here). -Let ```` indicate pressing the tab key. So begin by typing +Let ```` indicate pressing the :kbd:`Tab` key. So begin by typing ``cellular_automata.`` to the see the currently implemented named cellular automata. diff --git a/src/sage/dynamics/complex_dynamics/mandel_julia.py b/src/sage/dynamics/complex_dynamics/mandel_julia.py index 224a484c7bb..ce67274c293 100644 --- a/src/sage/dynamics/complex_dynamics/mandel_julia.py +++ b/src/sage/dynamics/complex_dynamics/mandel_julia.py @@ -130,7 +130,7 @@ def mandelbrot_plot(f=None, **kwds): ``interact`` to ``True``. (This is only implemented for ``z^2 + c``):: sage: mandelbrot_plot(interact=True) - interactive(children=(FloatSlider(value=0.0, description='Real center', max=1.0, min=-1.0, step=1e-05), + ...interactive(children=(FloatSlider(value=0.0, description='Real center', max=1.0, min=-1.0, step=1e-05), FloatSlider(value=0.0, description='Imag center', max=1.0, min=-1.0, step=1e-05), FloatSlider(value=4.0, description='Width', max=4.0, min=1e-05, step=1e-05), IntSlider(value=500, description='Iterations', max=1000), @@ -144,7 +144,7 @@ def mandelbrot_plot(f=None, **kwds): sage: mandelbrot_plot(interact=True, x_center=-0.75, y_center=0.25, ....: image_width=1/2, number_of_colors=75) - interactive(children=(FloatSlider(value=-0.75, description='Real center', max=1.0, min=-1.0, step=1e-05), + ...interactive(children=(FloatSlider(value=-0.75, description='Real center', max=1.0, min=-1.0, step=1e-05), FloatSlider(value=0.25, description='Imag center', max=1.0, min=-1.0, step=1e-05), FloatSlider(value=0.5, description='Width', max=4.0, min=1e-05, step=1e-05), IntSlider(value=500, description='Iterations', max=1000), @@ -600,14 +600,14 @@ def julia_plot(f=None, **kwds): the form ``f = z^2 + c``):: sage: julia_plot(interact=True) - interactive(children=(FloatSlider(value=-1.0, description='Real c'... + ...interactive(children=(FloatSlider(value=-1.0, description='Real c'... :: sage: R. = CC[] sage: f = z^2 + 1/2 sage: julia_plot(f,interact=True) - interactive(children=(FloatSlider(value=0.5, description='Real c'... + ...interactive(children=(FloatSlider(value=0.5, description='Real c'... To return the Julia set of a random `c` value with (formal) cycle structure `(2,3)`, set ``period = [2,3]``:: diff --git a/src/sage/dynamics/finite_dynamical_system_catalog.py b/src/sage/dynamics/finite_dynamical_system_catalog.py index 3ba09eb9948..74217178a29 100755 --- a/src/sage/dynamics/finite_dynamical_system_catalog.py +++ b/src/sage/dynamics/finite_dynamical_system_catalog.py @@ -5,7 +5,7 @@ dynamical systems. These are accessible through :mod:`sage.dynamics.finite_dynamical_system_catalog. ` -or just through `finite_dynamical_systems.` +or just through ``finite_dynamical_systems.`` (type either of these in Sage and hit ``tab`` for a list). AUTHORS: diff --git a/src/sage/ext_data/pari/simon/ell.gp b/src/sage/ext_data/pari/simon/ell.gp index 4e9870eb13e..663df10a7c3 100644 --- a/src/sage/ext_data/pari/simon/ell.gp +++ b/src/sage/ext_data/pari/simon/ell.gp @@ -1503,7 +1503,7 @@ if( DEBUGLEVEL_ell >= 4, print(" end of bnfredquartique")); \\ si bigflag !=0 alors on applique bnfredquartique. \\ si flag3 ==1 alors on utilise bnfqfsolve2 (equation aux normes) pour resoudre Legendre \\ aut est une liste d'automorphismes connus de bnf -\\ (ca peut aider a factoriser certains discriminiants). +\\ (ca peut aider a factoriser certains discriminants). \\ ell est de la forme y^2=x^3+A*x^2+B*x+C \\ ie ell=[0,A,0,B,C], avec A,B et C entiers. \\ 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..95405c3d72f 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 @@ -1434,6 +1434,8 @@ def _derivative_(self, a, z, diff_param=None): def _print_latex_(self, a, z): """ + EXAMPLES:: + sage: latex(struve_L(2,x)) L_{{2}}({x}) """ 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/cone.py b/src/sage/geometry/cone.py index e3d84cac696..3d9cb0766fc 100644 --- a/src/sage/geometry/cone.py +++ b/src/sage/geometry/cone.py @@ -3017,6 +3017,13 @@ def intersection(self, other): N( 2, 5) in 2-d lattice N + The intersection can also be expressed using the operator ``&``:: + + sage: (cone1 & cone2).rays() + N(-1, 3), + N( 2, 5) + in 2-d lattice N + It is OK to intersect cones living in sublattices of the same ambient lattice:: @@ -3042,7 +3049,18 @@ def intersection(self, other): N(3, 1), N(0, 1) in 2-d lattice N + + An intersection with a polyhedron returns a polyhedron:: + + sage: cone = Cone([(1,0), (-1,0), (0,1)]) + sage: p = polytopes.hypercube(2) + sage: cone & p + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices + sage: sorted(_.vertices_list()) + [[-1, 0], [-1, 1], [1, 0], [1, 1]] """ + if not isinstance(other, ConvexRationalPolyhedralCone): + return self.polyhedron().intersection(other) if self._ambient is other._ambient: # Cones of the same ambient cone or fan intersect nicely/quickly. # Can we maybe even return an element of the cone lattice?.. @@ -3058,6 +3076,8 @@ def intersection(self, other): p.add_constraints(other._PPL_cone().constraints()) return _Cone_from_PPL(p, self.lattice().intersection(other.lattice())) + __and__ = intersection + def is_equivalent(self, other): r""" Check if ``self`` is "mathematically" the same as ``other``. @@ -3495,7 +3515,7 @@ def plot(self, **options): result += tp.plot_walls(walls) return result - def polyhedron(self): + def polyhedron(self, **kwds): r""" Return the polyhedron associated to ``self``. @@ -3523,7 +3543,7 @@ def polyhedron(self): A 0-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex """ - return Polyhedron(rays=self.rays(), vertices=[self.lattice()(0)]) + return Polyhedron(rays=self.rays(), vertices=[self.lattice()(0)], **kwds) def an_affine_basis(self): r""" diff --git a/src/sage/geometry/hyperplane_arrangement/affine_subspace.py b/src/sage/geometry/hyperplane_arrangement/affine_subspace.py index 83f7463d4b9..7c1065553c4 100644 --- a/src/sage/geometry/hyperplane_arrangement/affine_subspace.py +++ b/src/sage/geometry/hyperplane_arrangement/affine_subspace.py @@ -131,7 +131,7 @@ def __hash__(self): """ # note that the point is not canonically chosen, but the linear part is return hash(self._linear_part) - + def _repr_(self): r""" String representation for an :class:`AffineSubspace`. diff --git a/src/sage/geometry/hyperplane_arrangement/check_freeness.py b/src/sage/geometry/hyperplane_arrangement/check_freeness.py index cbf766c8f7e..30f963612ec 100644 --- a/src/sage/geometry/hyperplane_arrangement/check_freeness.py +++ b/src/sage/geometry/hyperplane_arrangement/check_freeness.py @@ -120,7 +120,7 @@ def next_step(indices, prev, T): ret = next_step(I, Y, U) if ret is not None: return [prev] + ret - return None + return None T = matrix.identity(S, r) for i in indices: diff --git a/src/sage/geometry/hyperplane_arrangement/hyperplane.py b/src/sage/geometry/hyperplane_arrangement/hyperplane.py index 491c88d176d..c431291a3a6 100644 --- a/src/sage/geometry/hyperplane_arrangement/hyperplane.py +++ b/src/sage/geometry/hyperplane_arrangement/hyperplane.py @@ -282,7 +282,7 @@ def __contains__(self, q): return self.A() * q + self._const == 0 @cached_method - def polyhedron(self): + def polyhedron(self, **kwds): """ Return the hyperplane as a polyhedron. @@ -304,8 +304,10 @@ def polyhedron(self): A vertex at (0, 0, 4/3)) """ from sage.geometry.polyhedron.constructor import Polyhedron - R = self.parent().base_ring() - return Polyhedron(eqns=[self.coefficients()], base_ring=R) + R = kwds.pop('base_ring', None) + if R is None: + R = self.parent().base_ring() + return Polyhedron(eqns=[self.coefficients()], base_ring=R, **kwds) @cached_method def linear_part(self): diff --git a/src/sage/geometry/hyperplane_arrangement/plot.py b/src/sage/geometry/hyperplane_arrangement/plot.py index afaf807e345..5b26829fdc8 100644 --- a/src/sage/geometry/hyperplane_arrangement/plot.py +++ b/src/sage/geometry/hyperplane_arrangement/plot.py @@ -410,7 +410,7 @@ def plot_hyperplane(hyperplane, **kwds): # the extra keywords have now been handled # now create the plot if hyperplane.dimension() == 0: # a point on a line - x, = hyperplane.A() + x, = hyperplane.A() d = hyperplane.b() p = point((d/x,0), size=pt_size, **kwds) if has_hyp_label: @@ -456,7 +456,7 @@ def plot_hyperplane(hyperplane, **kwds): s0, s1 = -3, 3 t0, t1 = -3, 3 p = parametric_plot3d(pnt+s*w[0]+t*w[1], (s,s0,s1), (t,t0,t1), **kwds) - if has_hyp_label: + if has_hyp_label: if has_offset: b0, b1, b2 = label_offset else: @@ -518,7 +518,7 @@ def legend_3d(hyperplane_arrangement, hyperplane_colors, length): for i in range(N): p += line([(0,0),(0,0)], color=hyperplane_colors[i], thickness=8, legend_label=labels[i], axes=False) - p.set_legend_options(title='Hyperplanes', loc='center', labelspacing=0.4, + p.set_legend_options(title='Hyperplanes', loc='center', labelspacing=0.4, fancybox=True, font_size='x-large', ncol=2) p.legend(True) return p diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index ff85c1724d8..083f817693e 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -3649,7 +3649,7 @@ def plot3d(self, pplot += text3d(i+self.nvertices(), bc+index_shift*(p-bc), rgbcolor=pindex_color) return pplot - def polyhedron(self): + def polyhedron(self, **kwds): r""" Return the Polyhedron object determined by this polytope's vertices. @@ -3660,7 +3660,7 @@ def polyhedron(self): A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices """ from sage.geometry.polyhedron.constructor import Polyhedron - return Polyhedron(vertices=[list(v) for v in self._vertices]) + return Polyhedron(vertices=[list(v) for v in self._vertices], **kwds) def show3d(self): """ 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/constructor.py b/src/sage/geometry/polyhedron/constructor.py index dbe00570c85..7f11ac13593 100644 --- a/src/sage/geometry/polyhedron/constructor.py +++ b/src/sage/geometry/polyhedron/constructor.py @@ -269,7 +269,7 @@ REFERENCES: Komei Fukuda's `FAQ in Polyhedral Computation - `_ + `_ AUTHORS: @@ -291,6 +291,8 @@ # https://www.gnu.org/licenses/ ######################################################################## +import sage.geometry.abc + from sage.rings.integer_ring import ZZ from sage.rings.real_double import RDF from sage.rings.real_mpfr import RR @@ -313,11 +315,16 @@ def Polyhedron(vertices=None, rays=None, lines=None, INPUT: - - ``vertices`` -- list of points. Each point can be specified as + - ``vertices`` -- iterable of points. Each point can be specified as any iterable container of ``base_ring`` elements. If ``rays`` or ``lines`` are specified but no ``vertices``, the origin is taken to be the single vertex. + Instead of vertices, the first argument can also be an object + that can be converted to a :func:`Polyhedron` via an :meth:`as_polyhedron` + or :meth:`polyhedron` method. In this case, the following 5 arguments + cannot be provided. + - ``rays`` -- list of rays. Each ray can be specified as any iterable container of ``base_ring`` elements. @@ -332,6 +339,10 @@ def Polyhedron(vertices=None, rays=None, lines=None, any iterable container of ``base_ring`` elements. An entry equal to ``[-1,7,3,4]`` represents the equality `7x_1+3x_2+4x_3= 1`. + - ``ambient_dim`` -- integer. The ambient space dimension. Usually + can be figured out automatically from the H/Vrepresentation + dimensions. + - ``base_ring`` -- a sub-field of the reals implemented in Sage. The field over which the polyhedron will be defined. For ``QQ`` and algebraic extensions, exact arithmetic will be @@ -339,10 +350,6 @@ def Polyhedron(vertices=None, rays=None, lines=None, point arithmetic is faster but might give the wrong result for degenerate input. - - ``ambient_dim`` -- integer. The ambient space dimension. Usually - can be figured out automatically from the H/Vrepresentation - dimensions. - - ``backend`` -- string or ``None`` (default). The backend to use. Valid choices are * ``'cdd'``: use cdd @@ -465,17 +472,45 @@ def Polyhedron(vertices=None, rays=None, lines=None, ... ValueError: invalid base ring - Create a mutable polyhedron:: - - sage: P = Polyhedron(vertices=[[0, 1], [1, 0]], mutable=True) - sage: P.is_mutable() - True - sage: hasattr(P, "_Vrepresentation") - False - sage: P.Vrepresentation() - (A vertex at (0, 1), A vertex at (1, 0)) - sage: hasattr(P, "_Vrepresentation") - True + Converting from a given polyhedron:: + + sage: cb = polytopes.cube(); cb + A 3-dimensional polyhedron in ZZ^3 defined as the convex hull of 8 vertices + sage: Polyhedron(cb, base_ring=QQ) + A 3-dimensional polyhedron in QQ^3 defined as the convex hull of 8 vertices + + Converting from other objects to a polyhedron:: + + sage: quadrant = Cone([(1,0), (0,1)]) + sage: Polyhedron(quadrant) + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 2 rays + sage: Polyhedron(quadrant, base_ring=QQ) + A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 2 rays + + sage: o = lattice_polytope.cross_polytope(2) + sage: Polyhedron(o) + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices + sage: Polyhedron(o, base_ring=QQ) + A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices + + sage: p = MixedIntegerLinearProgram(solver='PPL') + sage: x, y = p['x'], p['y'] + sage: p.add_constraint(x <= 1) + sage: p.add_constraint(x >= -1) + sage: p.add_constraint(y <= 1) + sage: p.add_constraint(y >= -1) + sage: Polyhedron(o) + A 2-dimensional polyhedron in ZZ^2 defined as the convex hull of 4 vertices + sage: Polyhedron(o, base_ring=QQ) + A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices + + sage: H. = HyperplaneArrangements(QQ) + sage: h = x + y - 1; h + Hyperplane x + y - 1 + sage: Polyhedron(h, base_ring=ZZ) + A 1-dimensional polyhedron in ZZ^2 defined as the convex hull of 1 vertex and 1 line + sage: Polyhedron(h) + A 1-dimensional polyhedron in QQ^2 defined as the convex hull of 1 vertex and 1 line .. NOTE:: @@ -486,7 +521,6 @@ def Polyhedron(vertices=None, rays=None, lines=None, input data - the results can depend upon the tolerance setting of cdd. - TESTS: Check that giving ``float`` input gets converted to ``RDF`` (see :trac:`22605`):: @@ -569,10 +603,53 @@ def Polyhedron(vertices=None, rays=None, lines=None, sage: Polyhedron(ambient_dim=2, vertices=[], rays=[], lines=[], base_ring=QQ) The empty polyhedron in QQ^2 + Create a mutable polyhedron:: + + sage: P = Polyhedron(vertices=[[0, 1], [1, 0]], mutable=True) + sage: P.is_mutable() + True + sage: hasattr(P, "_Vrepresentation") + False + sage: P.Vrepresentation() + (A vertex at (0, 1), A vertex at (1, 0)) + sage: hasattr(P, "_Vrepresentation") + True + .. SEEALSO:: :mod:`Library of polytopes ` """ + # Special handling for first argument, for coercion-like uses + constructor = None + first_arg = vertices + if isinstance(first_arg, sage.geometry.abc.Polyhedron): + constructor = first_arg.change_ring + try: + # PolyhedronFace.as_polyhedron (it also has a "polyhedron" method with a different purpose) + constructor = first_arg.as_polyhedron + except AttributeError: + try: + # ConvexRationalPolyhedralCone, LatticePolytopeClass, MixedIntegerLinearProgram, Hyperplane + constructor = first_arg.polyhedron + except AttributeError: + pass + if constructor: + if not all(x is None for x in (rays, lines, ieqs, eqns, ambient_dim)): + raise ValueError('if a polyhedron is given, cannot provide H- and V-representations objects') + # Only pass non-default arguments + kwds = {} + if base_ring is not None: + kwds['base_ring'] = base_ring + if verbose is not False: + kwds['verbose'] = verbose + if backend is not None: + kwds['backend'] = backend + if minimize is not True: + kwds['minimize'] = minimize + if mutable is not False: + kwds['mutable'] = mutable + return constructor(**kwds) + got_Vrep = not ((vertices is None) and (rays is None) and (lines is None)) got_Hrep = not ((ieqs is None) and (eqns is None)) diff --git a/src/sage/geometry/polyhedron/face.py b/src/sage/geometry/polyhedron/face.py index d9dd5a6c4d6..2166f016ba8 100644 --- a/src/sage/geometry/polyhedron/face.py +++ b/src/sage/geometry/polyhedron/face.py @@ -750,7 +750,7 @@ def is_compact(self): for V in self.ambient_Vrepresentation()) @cached_method - def as_polyhedron(self): + def as_polyhedron(self, **kwds): """ Return the face as an independent polyhedron. @@ -774,7 +774,12 @@ def as_polyhedron(self): P = self._polyhedron parent = P.parent() Vrep = (self.vertices(), self.rays(), self.lines()) - return P.__class__(parent, Vrep, None) + result = P.__class__(parent, Vrep, None) + if any(kwds.get(kwd) is not None + for kwd in ('base_ring', 'backend')): + from .constructor import Polyhedron + return Polyhedron(result, **kwds) + return result def _some_elements_(self): r""" @@ -1066,7 +1071,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/geometry/ribbon_graph.py b/src/sage/geometry/ribbon_graph.py index 60375b20ce2..d2a8d7de63a 100644 --- a/src/sage/geometry/ribbon_graph.py +++ b/src/sage/geometry/ribbon_graph.py @@ -460,16 +460,16 @@ def contract_edge(self, k): #the following two lines convert the list of tuples to list of lists aux_sigma = [list(x) for x in self._sigma.cycle_tuples(singletons=True)] aux_rho = [list(x) for x in self._rho.cycle_tuples()] - #The following ''if'' rules out the cases when we would be - #contracting a loop (which is not admissible since we would + #The following ''if'' rules out the cases when we would be + #contracting a loop (which is not admissible since we would #lose the topological type of the graph). - if (_find(aux_sigma, aux_rho[k][0])[0] == + if (_find(aux_sigma, aux_rho[k][0])[0] == _find(aux_sigma, aux_rho[k][1])[0]): raise ValueError("the edge is a loop and cannot be contracted") #We store in auxiliary variables the positions of the vertices #that are the ends of the edge to be contracted and we delete #from them the darts corresponding to the edge that is going - #to be contracted. We also delete the contracted edge + #to be contracted. We also delete the contracted edge #from aux_rho pos1 = _find(aux_sigma, aux_rho[k][0]) pos2 = _find(aux_sigma, aux_rho[k][1]) @@ -582,7 +582,7 @@ def extrude_edge(self, vertex, dart1, dart2): for val in val_one: repr_sigma += [[val]] - # We find which is the highest value a dart has, in order to + # We find which is the highest value a dart has, in order to # add new darts that do not conflict with previous ones. k = max(darts_rho) @@ -627,7 +627,7 @@ def genus(self): """ #We now use the same procedure as in _repr_ to get the vertices #of valency 1 and distinguish them from the extra singletons of - #the permutation sigma. + #the permutation sigma. repr_sigma = [list(x) for x in self._sigma.cycle_tuples()] repr_rho = [list(x) for x in self._rho.cycle_tuples()] darts_rho = flatten(repr_rho) @@ -637,10 +637,10 @@ def genus(self): #the total number of vertices of sigma is its number of cycles #of length >1 plus the number of singletons that are actually #vertices of valency 1 - + vertices = len(self._sigma.cycle_tuples()) + len(val_one) edges = len(self._rho.cycle_tuples()) - #formula for the genus using that the thickening is homotopically + #formula for the genus using that the thickening is homotopically #equivalent to the graph g = (-vertices + edges - self.number_boundaries() + 2) // 2 @@ -720,13 +720,13 @@ def boundary(self): bound = [] #since lists of tuples are not modifiable, we change the data to a - #list of lists + #list of lists aux_perm = (self._rho * self._sigma).cycle_tuples(singletons=True) - #the cycles of the permutation rho*sigma are in 1:1 correspondence with + #the cycles of the permutation rho*sigma are in 1:1 correspondence with #the boundary components of the thickening (see function number_boundaries()) #but they are not the labeled boundary components. - #With the next for, we convert the cycles of rho*sigma to actually + #With the next for, we convert the cycles of rho*sigma to actually #the labelling of the edges. Each edge, therefore, should appear twice for i,p in enumerate(aux_perm): @@ -799,16 +799,16 @@ def reduced(self): aux_sigma = [list(x) for x in aux_ribbon._sigma.cycle_tuples(singletons=True)] aux_rho = [list(x) for x in aux_ribbon._rho.cycle_tuples()] for j in range(len(aux_rho)): - if (_find(aux_sigma, aux_rho[j][0])[0] != + if (_find(aux_sigma, aux_rho[j][0])[0] != _find(aux_sigma, aux_rho[j][1])[0]): aux_ribbon = aux_ribbon.contract_edge(j) - aux_rho = [list(x) for + aux_rho = [list(x) for x in aux_ribbon._rho.cycle_tuples()] break #finally we change the data to a list of tuples and return the - #information as a ribbon graph. + #information as a ribbon graph. return aux_ribbon - + #the next function computes a basis of homology, it uses #the previous function. @@ -960,15 +960,15 @@ def homology_basis(self): basis = [[list(x)] for x in self.reduced()._rho.cycle_tuples()] - #Now we define center as the set of edges that were contracted - #in reduced() this set is contractible and can be define as the + #Now we define center as the set of edges that were contracted + #in reduced() this set is contractible and can be define as the #complement of reduced_rho in rho - center = [list(x) for x in self._rho.cycle_tuples() + center = [list(x) for x in self._rho.cycle_tuples() if (x not in self.reduced()._rho.cycle_tuples())] #We define an auxiliary list 'vertices' that will contain the - #vertices (cycles of sigma) corresponding to each half edge. + #vertices (cycles of sigma) corresponding to each half edge. vertices = [] @@ -1013,7 +1013,7 @@ def homology_basis(self): basis[i][j][0], basis[i][j][1] = \ basis[i][j][1], basis[i][j][0] - #the variable basis is a LIST of Lists of lists. Each List + #the variable basis is a LIST of Lists of lists. Each List #corresponds to an element of the basis and each list in a List #is just a 2-tuple which corresponds to an ''ordered'' edge of rho. @@ -1056,7 +1056,7 @@ def normalize(self): darts_rho = flatten(aux_rho) darts_sigma = flatten(aux_sigma) val_one = [x for x in darts_rho if x not in darts_sigma] - + #We add them to aux_sigma for i in range(len(val_one)): aux_sigma += [[val_one[i]]] @@ -1147,7 +1147,7 @@ def make_ribbon(g, r): repr_sigma[1].append(i+(2*g+2)+1) repr_rho += [[i+2,i+(2*g+2)+1]] - #finally we add an edge for each additional boundary component. + #finally we add an edge for each additional boundary component. max_dart = 4*g+2 for j in range(r-1): repr_sigma[0].insert(0, max_dart+2*(j+1)-1) diff --git a/src/sage/geometry/triangulation/point_configuration.py b/src/sage/geometry/triangulation/point_configuration.py index 8d05c3bcb19..4e86b8fc3e3 100644 --- a/src/sage/geometry/triangulation/point_configuration.py +++ b/src/sage/geometry/triangulation/point_configuration.py @@ -708,7 +708,7 @@ def _TOPCOM_triangulations(self, verbose=True): # points2triangs # [[0,0,1],[0,1,1],[1,0,1],[1,1,1],[-1,-1,1]] #### TOPCOM output #### - # T[0]:=[0->5,3:{{0,1,2},{1,2,3},{0,2,4},{0,1,4}}]; + # T[0] := {{0,1,2},{0,1,4},{0,2,4},{1,2,3}}; (<0,1,2>, <0,1,4>, <0,2,4>, <1,2,3>) """ command = 'points2' @@ -1899,7 +1899,7 @@ def contained_simplex(self, large=True, initial_point=None, point_order=None): # PointConfiguration are actually ignored. if not points: return tuple() - + if initial_point is None: origin = points.pop() else: @@ -2005,7 +2005,7 @@ def facets_of_simplex(simplex): # input verification self._assert_is_affine() - + point_order_is_given = point_order is not None if point_order is None: point_order = list(self.points()) 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/digraph.py b/src/sage/graphs/digraph.py index 7e2a59e4abc..3cccf81c956 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -192,7 +192,7 @@ class DiGraph(GenericGraph): pre-defined digraphs, see the :mod:`~sage.graphs.digraph_generators` module. A :class:`DiGraph` object has many methods whose list can be obtained by - typing ``g.`` (i.e. hit the 'tab' key) or by reading the documentation + typing ``g.`` (i.e. hit the :kbd:`Tab` key) or by reading the documentation of :mod:`~sage.graphs.digraph`, :mod:`~sage.graphs.generic_graph`, and :mod:`~sage.graphs.graph`. diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index cceb89df765..f1d88178ebb 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -12,7 +12,7 @@ sage: p = digraphs.Circulant(10,[2,3]) More interestingly, one can get the list of all digraphs that Sage knows how to -build by typing ``digraphs.`` in Sage and then hitting tab. +build by typing ``digraphs.`` in Sage and then hitting :kbd:`Tab`. .. csv-table:: :class: contentstable diff --git a/src/sage/graphs/edge_connectivity.pyx b/src/sage/graphs/edge_connectivity.pyx index 9b4c2533a40..54152821203 100644 --- a/src/sage/graphs/edge_connectivity.pyx +++ b/src/sage/graphs/edge_connectivity.pyx @@ -9,7 +9,6 @@ from a `2k` edge-connected graph or a `k` edge-connected digraph. .. TODO:: - - Add speedup methods proposed in [GKLP2021]_ for the edge connectivity - Implement the tree-packing algorithms proposed in [Gabow1995]_ and [BHKP2008]_ - Extend to digraphs with multiple edges @@ -62,7 +61,25 @@ cdef class GabowEdgeConnectivity: ....: D = DiGraph(graphs.RandomRegular(6, 50)) sage: GabowEdgeConnectivity(D).edge_connectivity() 6 + + A complete digraph with `n` vertices is `n-1`-edge-connected:: + sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity + sage: D = DiGraph(digraphs.Complete(10)) + sage: GabowEdgeConnectivity(D, use_rec = True).edge_connectivity() + 9 + + Check that we get the same result when with and without the DFS-based + speed-up initialization proposed in [GKLP2021]_:: + + sage: G = graphs.RandomBarabasiAlbert(100, 2) + sage: D = DiGraph(G) + sage: ec1 = GabowEdgeConnectivity(D, dfs_preprocessing=False).edge_connectivity() + sage: ec2 = GabowEdgeConnectivity(D, dfs_preprocessing=True).edge_connectivity() + sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True, use_rec=True).edge_connectivity() + sage: ec1 == ec2 and ec2 == ec3 + True + TESTS: :trac:`32169`:: @@ -120,6 +137,7 @@ cdef class GabowEdgeConnectivity: cdef vector[vector[int]] g_out cdef vector[vector[int]] g_in cdef vector[vector[int]] my_g # either g_out or g_in + cdef vector[vector[int]] my_g_reversed # either g_out or g_in # values associated to edges cdef int* tail # source of edge j @@ -169,7 +187,15 @@ cdef class GabowEdgeConnectivity: cdef queue[pair[int, int]] joining_edges # queue of tuples (edge id, edge state) cdef queue[int] incident_edges_Q # queue of edges - def __init__(self, G): + cdef int num_start_f_trees # number of f-trees at the beginning of an iteration + cdef int num_joins # number of joined vertices from dfs + cdef bint* T # whether an edge is in the proven k-intersection + cdef bint* visited # for method find_dfs_tree + cdef int * incident_edge_index # used for DFS initialization + cdef bint dfs_preprocessing # whether to use DFS-based fast initialization + cdef bint use_rec # whether to use the recursive DFS initialization + + def __init__(self, G, dfs_preprocessing=True, use_rec=False): r""" Initialize this object. @@ -177,6 +203,15 @@ cdef class GabowEdgeConnectivity: - ``G`` -- a :class:`~sage.graphs.digraph.DiGraph` + - ``dfs_preprocessing`` -- boolean (default: ``True``); whether to use + the DFS-based speed-up initialization proposed in [GKLP2021]_ + + - ``use_rec`` -- boolean (default: ``False``); whether to use a + recursive or non-recursive DFS for ``dfs_preprocessing``. The + recursive DFS tends to be faster than the non-recursive version on + complete digraphs and slower on other graphs. This parameter is + ignored when ``dfs_preprocessing`` is ``False``. + EXAMPLES:: sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity @@ -184,6 +219,8 @@ cdef class GabowEdgeConnectivity: sage: GabowEdgeConnectivity(D).edge_connectivity() 4 """ + self.dfs_preprocessing = dfs_preprocessing + self.use_rec = use_rec self.ec_checked = False from sage.graphs.digraph import DiGraph if not isinstance(G, DiGraph): @@ -199,9 +236,6 @@ cdef class GabowEdgeConnectivity: self.F.clear() return - # Set upper bound on the edge connectivity - self.max_ec = min(min(G.out_degree_iterator()), min(G.in_degree_iterator())) - # # Initialize some data structures # @@ -210,9 +244,22 @@ cdef class GabowEdgeConnectivity: self.m = G.size() self.mem = MemoryAllocator() - # Build compact graph data structure with out and in adjacencies + # Build compact graph data structure with out and in adjacencies. + # Loops are removed from the graph. self.build_graph_data_structure() # From now on, vertices are numbered in [0..n-1] and edges in [0..m-1] + # where m is the number of edges after the removal of the loops + + # Set upper bound on the edge connectivity + cdef int i, d + self.max_ec = INT_MAX + for i in range(self.n): + d = self.g_out[i].size() + if d < self.max_ec: + self.max_ec = d + d = self.g_in[i].size() + if d < self.max_ec: + self.max_ec = d self.labels = self.mem.calloc(self.m, sizeof(int)) self.tree_flag = self.mem.calloc(self.max_ec, sizeof(bint)) @@ -230,18 +277,21 @@ cdef class GabowEdgeConnectivity: self.depth_1 = self.mem.calloc(self.max_ec, sizeof(int*)) self.depth_2 = self.mem.calloc(self.max_ec, sizeof(int*)) self.stack = self.mem.calloc(self.n, sizeof(int)) + self.incident_edge_index = self.mem.calloc(self.n, sizeof(int)) self.tree_edges.resize(self.max_ec) self.tree_edges_incident.resize(self.n) + self.T = self.mem.calloc(self.m, sizeof(bint)) + self.visited = self.mem.calloc(self.n, sizeof(bint)) # Set some constants self.UNUSED = INT_MAX self.FIRSTEDGE = INT_MAX - 1 - cdef int i for i in range(self.m): self.edge_state_1[i] = self.UNUSED # edge i is unused self.edge_state_2[i] = self.UNUSED self.labels[i] = self.UNUSED # edge i is unlabeled + self.T[i] = False # edge i doesn't belong to any k-intersection yet _ = self.compute_edge_connectivity() sig_check() @@ -271,17 +321,20 @@ cdef class GabowEdgeConnectivity: for i in range(self.n): self.g_out[i].clear() self.g_in[i].clear() - + cdef int x, y cdef int e_id = 0 for x, u in enumerate(self.int_to_vertex): for v in self.G.neighbor_out_iterator(u): y = vertex_to_int[v] - self.g_out[x].push_back(e_id) - self.g_in[y].push_back(e_id) - self.tail[e_id] = x - self.head[e_id] = y - e_id += 1 + if x != y: + self.g_out[x].push_back(e_id) + self.g_in[y].push_back(e_id) + self.tail[e_id] = x + self.head[e_id] = y + e_id += 1 + # Loops have been removed, so we update the number of edges + self.m = e_id cdef bint compute_edge_connectivity(self) except -1: """ @@ -336,6 +389,7 @@ cdef class GabowEdgeConnectivity: if reverse: # Search for a spanning tree in g-reversed self.my_g = self.g_out + self.my_g_reversed = self.g_in self.my_from = self.head self.my_to = self.tail self.my_parent = self.parent_2 @@ -345,6 +399,7 @@ cdef class GabowEdgeConnectivity: else: # Search for a spanning tree in g using incoming arcs self.my_g = self.g_in + self.my_g_reversed = self.g_out self.my_from = self.tail self.my_to = self.head self.my_parent = self.parent_1 @@ -358,7 +413,15 @@ cdef class GabowEdgeConnectivity: cdef int njoins = 0 cdef int z - while njoins < self.n - 1: + self.num_start_f_trees = self.n - self.num_joins + # There are fewer than n f-trees. We prepare to join them. If there's + # only one f-tree, we just save the edges and advance to the next + # iteration + if self.dfs_preprocessing and self.num_start_f_trees < self.n - 1: + self.re_init(tree) + + # There are n f-trees, and we try to join them + while njoins < self.num_start_f_trees-1: # Get the root of an active subtree or INT_MAX if none exists z = self.choose_root() while z != INT_MAX: @@ -415,13 +478,133 @@ cdef class GabowEdgeConnectivity: self.labeled[tree][j] = False self.root[j] = j self.forests[j] = True + + self.num_joins = 0 + + # Initialize T_k to be a DFS spanning forest of G \ T + if self.dfs_preprocessing: + self.compute_dfs_tree() - # Set inactive the f_trees of the root vertex + # Set inactive the f-trees of the root vertex self.forests[self.root_vertex] = False self.L_roots[tree] = self.UNUSED self.tree_flag[tree] = False + + cdef void compute_dfs_tree(self): + r""" + Find a DFS spanning forest of `G \backslash T`. + + This is the DFS-based speed-up initialization proposed in [GKLP2021]_. + + EXAMPLES:: + + sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity + sage: D = digraphs.Complete(5) + sage: GabowEdgeConnectivity(D, dfs_preprocessing=True).edge_connectivity() + 4 + sage: GabowEdgeConnectivity(D, dfs_preprocessing=False).edge_connectivity() + 4 + """ + # Mark all vertices as unvisited + cdef int i + for i in range(self.n): + self.visited[i] = False + + cdef int r + for r in range(self.n): + if not self.visited[r]: + # Make this vertex the root of the following dfs tree + self.root[r] = r + # Make the f-tree rooted at this vertex active + self.forests[r] = True + # Find connected vertices of the f-tree rooted at r + if self.use_rec: + self.find_dfs_tree_rec(r, r) + else: + self.find_dfs_tree(r) + # Each call of find_dfs_tree creates an f-tree + self.num_start_f_trees += 1 + + cdef void find_dfs_tree(self, int r): + r""" + Find more vertices of the f-tree rooted at `r`. + This is part of the DFS-based speed-up initialization proposed in + [GKLP2021]_. + + EXAMPLES:: + + sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity + sage: D = digraphs.Complete(5) + sage: GabowEdgeConnectivity(D, dfs_preprocessing=True, use_rec=False).edge_connectivity() + 4 + """ + cdef int u, v, e_id + cdef int * stack = self.stack + cdef int * edge_index = self.incident_edge_index + # We initialize the stack and mark the root as visited + cdef int t = 0 # index pointing to the top of the stack + stack[0] = r + edge_index[r] = self.my_g_reversed[r].size() + self.visited[r] = True + + while t >= 0: + u = stack[t] + if edge_index[u]: + # Visit the next incident edge of u + edge_index[u] -= 1 + e_id = self.my_g_reversed[u][edge_index[u]] + if not self.T[e_id]: + v = self.my_to[e_id] + if not self.visited[v] and v != self.root_vertex: + # Make v belong to the f-tree rooted at r + self.root[v] = r + self.forests[v] = False + self.my_edge_state[e_id] = self.current_tree + self.num_joins += 1 + self.visited[v] = True + # add v to the stack + t += 1 + stack[t] = v + edge_index[v] = self.my_g_reversed[v].size() + # and proceed with v + else: + # We are done with u. We pop. + t -= 1 + + cdef void find_dfs_tree_rec(self, int u, int r): + r""" + Find more vertices of the f-tree rooted at `r`. + + This is part of the DFS-based speed-up initialization proposed in + [GKLP2021]_. + + EXAMPLES:: + + sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity + sage: D = digraphs.Complete(5) + sage: GabowEdgeConnectivity(D, dfs_preprocessing=True, use_rec=True).edge_connectivity() + 4 + """ + # Mark vertex u as visited to avoid visiting it multiple times + self.visited[u] = True + + # Visit outgoing arcs of current vertex + cdef int e_id, v + for e_id in self.my_g_reversed[u]: + v = self.my_to[e_id] + # Ensure a vertex is not visited, is not a proven k-intersection edge + # and root_vertex remains deficient + if not self.visited[v] and not self.T[e_id] and v != self.root_vertex: + # Make current vertex belong to the f_tree rooted at r + self.root[v] = r + self.forests[v] = False + self.my_edge_state[e_id] = self.current_tree + self.num_joins += 1 + # recursively find more vertices and grow the subtree rooted at r + self.find_dfs_tree_rec(v, r) + cdef int choose_root(self): """ Return the root of an active f_tree, or INT_MAX if none exists. @@ -728,7 +911,7 @@ cdef class GabowEdgeConnectivity: cdef bint label_step(self, int e_id, int e_label): """ - Label edge e_id with e_label and check wheteher edge e_id is joining. + Label edge e_id with e_label and check whether edge e_id is joining. EXAMPLES:: @@ -861,10 +1044,15 @@ cdef class GabowEdgeConnectivity: # Arrange the edges of each tree for j in range(tree + 1): + if self.dfs_preprocessing: + for e_id in self.tree_edges[j]: + self.T[e_id] = False self.tree_edges[j].clear() for j in range(self.m): if self.my_edge_state[j] != self.UNUSED: self.tree_edges[self.my_edge_state[j]].push_back(j) + if self.dfs_preprocessing: + self.T[j] = True for j in range(tree + 1): if not j or j == tree or self.tree_flag[j]: 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..f2c94041c51 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -3450,7 +3450,7 @@ def multiple_edges(self, to_undirected=False, labels=True, sort=False): else: multi_edges.extend((u, v) for _ in L_uv) multi_edges.extend((v, u) for _ in L_vu) - + elif not self.has_edge(v, u): L = self.edge_label(u, v) if len(L) > 1: @@ -3773,7 +3773,7 @@ def weighted(self, new=None): else: return bool(self._weighted) - ### Properties + # Properties def antisymmetric(self): r""" @@ -3928,8 +3928,9 @@ def is_bipartite(self, certificate=False): return False color = {} - tree = {} # inheritance of colors along the DFS to recover an odd - # cycle when certificate=True + # inheritance of colors along the DFS to recover an odd + # cycle when certificate=True + tree = {} # For any uncolored vertex in the graph (to ensure we do the right job # when the graph is not connected !) @@ -3989,7 +3990,6 @@ def is_bipartite(self, certificate=False): else: return True - def is_eulerian(self, path=False): r""" Check whether the graph is Eulerian. @@ -4077,7 +4077,7 @@ def is_eulerian(self, path=False): else: # if there was another vertex with the same sign of difference... if uv[(diff + 1) // 2] is not None: - return False # ... the graph is not semi-Eulerian + return False # ... the graph is not semi-Eulerian else: uv[(diff + 1) // 2] = v else: @@ -4140,7 +4140,7 @@ def size(self): num_edges = size - ### Orientations + # Orientations def eulerian_orientation(self): r""" @@ -4376,8 +4376,9 @@ def eulerian_circuit(self, return_vertices=False, labels=True, path=False): else: next_edge = next(g_edge_iter(v)) - if next_edge[0] == v: # in the undirected case we want to - # save the direction of traversal + if next_edge[0] == v: + # in the undirected case we want to save the + # direction of traversal next_edge_new = (next_edge[1], next_edge[0], next_edge[2]) else: next_edge_new = next_edge @@ -4654,7 +4655,10 @@ def wfunction_float(e): # contains fringe_vertex: (weight, vertex_in_tree) for each # fringe vertex. fringe_list = {e[0] if e[0] != v else e[1]: (wfunction_float(e), v) for e in self.edges_incident(v)} - cmp_fun = lambda x: fringe_list[x][0] + + def cmp_fun(x): + return fringe_list[x][0] + for i in range(self.order() - 1): # find the smallest-weight fringe vertex u = min(fringe_list, key=cmp_fun) @@ -4667,7 +4671,7 @@ def wfunction_float(e): fringe_list.pop(u) # update fringe list for e in self.edges_incident(u): - neighbor = e[0] if e[0] !=u else e[1] + neighbor = e[0] if e[0] != u else e[1] if neighbor in tree: continue w = wfunction_float(e) @@ -4712,7 +4716,7 @@ def wfunction_float(e): G = networkx.Graph([(e[0], e[1], {'weight': wfunction_float(e)}) for e in self.edge_iterator()]) E = networkx.minimum_spanning_edges(G, data=False) return [(u, v, self.edge_label(u, v)) if hash(u) < hash(v) else (v, u, self.edge_label(u, v)) - for u, v in E] + for u, v in E] else: raise NotImplementedError("minimum spanning tree algorithm '%s' is not implemented" % algorithm) @@ -4780,9 +4784,7 @@ def spanning_trees_count(self, root_vertex=None): 1 sage: D.spanning_trees_count(2) 2 - """ - if not self.order(): return 0 @@ -4797,7 +4799,7 @@ def spanning_trees_count(self, root_vertex=None): root_vertex = vertices[0] index = 0 elif root_vertex not in vertices: - raise ValueError("vertex (%s) not in the graph"%root_vertex) + raise ValueError("vertex (%s) not in the graph" % root_vertex) else: index = vertices.index(root_vertex) @@ -4934,8 +4936,7 @@ def cycle_basis(self, output='vertex'): raise ValueError('output must be either vertex or edge') if self.is_directed(): - raise NotImplementedError('not implemented for directed ' - 'graphs') + raise NotImplementedError('not implemented for directed graphs') if self.allows_multiple_edges(): if not self.is_connected(): @@ -5064,7 +5065,7 @@ def minimum_cycle_basis(self, algorithm=None, weight_function=None, by_weight=Fa else: raise NotImplementedError("only 'NetworkX' and Cython implementation is supported") - ### Planarity + # Planarity def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, set_pos=False): r""" @@ -5237,8 +5238,8 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, se """ # Quick check first if (on_embedding is None and not kuratowski and not set_embedding and not set_pos - and not self.allows_loops() and not self.allows_multiple_edges() - and not self.is_directed()): + and not self.allows_loops() and not self.allows_multiple_edges() + and not self.is_directed()): if self.order() > 4 and self.size() > 3 * self.order() - 6: return False @@ -5249,7 +5250,7 @@ def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, se return self.to_simple().is_planar(kuratowski=kuratowski) if on_embedding is not None: - self._check_embedding_validity(on_embedding,boolean=False) + self._check_embedding_validity(on_embedding, boolean=False) return (0 == self.genus(minimal=False, set_embedding=False, on_embedding=on_embedding)) else: from sage.graphs.planarity import is_planar @@ -5403,8 +5404,8 @@ def is_circular_planar(self, on_embedding=None, kuratowski=False, # Quick check first if (on_embedding is None and not kuratowski and set_embedding and - boundary is None and not ordered and not set_pos and - not self.allows_loops() and not self.allows_multiple_edges()): + boundary is None and not ordered and not set_pos and + not self.allows_loops() and not self.allows_multiple_edges()): if self.order() > 3 and self.size() > 2 * self.order() - 3: return False @@ -5630,11 +5631,11 @@ def layout_planar(self, set_embedding=False, on_embedding=None, embedding = dict() if len(G) >= 1: v1 = next(verts) - pos[v1] = [0,0] + pos[v1] = [0, 0] embedding[v1] = [] if len(G) == 2: v2 = next(verts) - pos[v2] = [0,1] + pos[v2] = [0, 1] embedding[v1] = [v2] embedding[v2] = [v1] if set_embedding: @@ -5666,25 +5667,29 @@ def layout_planar(self, set_embedding=False, on_embedding=None, embedding_copy = None if set_embedding: if not G.is_planar(set_embedding=True): - raise ValueError('%s is not a planar graph'%self) + raise ValueError('%s is not a planar graph' % self) embedding_copy = {v: neighbors[:] for v, neighbors in G._embedding.items()} else: if on_embedding is not None: G._check_embedding_validity(on_embedding, boolean=False) if not G.is_planar(on_embedding=on_embedding): - raise ValueError('provided embedding is not a planar embedding for %s'%self ) + raise ValueError('provided embedding is not a planar ' + 'embedding for %s' % self) G.set_embedding(on_embedding) else: - if hasattr(G,'_embedding'): + if hasattr(G, '_embedding'): if G._check_embedding_validity(): if not G.is_planar(on_embedding=G._embedding): - raise ValueError('%s has nonplanar _embedding attribute. Try putting set_embedding=True'%self) + raise ValueError('%s has nonplanar _embedding attribute. ' + 'Try putting set_embedding=True' % self) embedding_copy = {v: neighbors[:] for v, neighbors in G._embedding.items()} else: - raise ValueError('provided embedding is not a valid embedding for %s. Try putting set_embedding=True'%self) + raise ValueError('provided embedding is not a valid ' + 'embedding for %s. Try putting ' + 'set_embedding=True' % self) else: if not G.is_planar(set_embedding=True): - raise ValueError('%s is not a planar graph'%self) + raise ValueError('%s is not a planar graph' % self) if external_face: if not self.has_edge(external_face): @@ -5698,11 +5703,12 @@ def layout_planar(self, set_embedding=False, on_embedding=None, if test: if G._check_embedding_validity(): if not G.is_planar(on_embedding=G._embedding): - raise ValueError('%s has nonplanar _embedding attribute. Try putting set_embedding=True' % self) + raise ValueError('%s has nonplanar _embedding attribute. ' + 'Try putting set_embedding=True' % self) test_faces = G.faces(G._embedding) for face in test_faces: if len(face) != 3: - raise RuntimeError('BUG: Triangulation returned face: %s'%face) + raise RuntimeError('BUG: Triangulation returned face: %s' % face) faces = G.faces(G._embedding) outer_face = faces[0] @@ -5780,7 +5786,7 @@ def is_drawn_free_of_edge_crossings(self): t = (da * Rational(p1[1] - q1[1]) + db * Rational(q1[0] - p1[0])) / (db * dx - da * dy) if 0 <= s and s <= 1 and 0 <= t and t <= 1: - print('fail on', p1, p2, ' : ',q1, q2) + print('fail on', p1, p2, ' : ', q1, q2) print(edge1, edge2) return False return True @@ -5938,7 +5944,7 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal verts += 1 extra_edges = [] - if ordered: # WHEEL + if ordered: # WHEEL for e in zip(boundary[-1], boundary[1:]): if not G.has_edge(e): G.add_edge(e) @@ -5963,14 +5969,14 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal except AttributeError: raise AttributeError('graph must have attribute _embedding set to compute current (embedded) genus') return (2 - verts + edges - faces) // 2 - else: # then compute either maximal or minimal genus of all embeddings + else: # then compute either maximal or minimal genus of all embeddings from . import genus if set_embedding: if self.has_loops() or self.is_directed() or self.has_multiple_edges(): raise NotImplementedError("cannot work with embeddings of non-simple graphs") if minimal: - B,C = G.blocks_and_cut_vertices() + B, C = G.blocks_and_cut_vertices() embedding = {} g = 0 for block in B: @@ -5991,7 +5997,7 @@ def genus(self, set_embedding=True, on_embedding=None, minimal=True, maximal=Fal if maximal and (self.has_multiple_edges() or self.has_loops()): raise NotImplementedError("cannot compute the maximal genus of a graph with loops or multiple edges") if minimal: - B,C = G.blocks_and_cut_vertices() + B, C = G.blocks_and_cut_vertices() g = 0 for block in B: H = G.subgraph(block) @@ -6207,7 +6213,7 @@ def faces(self, embedding=None): # Establish set of possible edges edgeset = set() - for u,v in self.edge_iterator(labels=0): + for u, v in self.edge_iterator(labels=0): edgeset.add((u, v)) edgeset.add((v, u)) @@ -6219,7 +6225,7 @@ def faces(self, embedding=None): # Trace faces while edgeset: - u,v = path[-1] + u, v = path[-1] neighbors = embedding[v] next_node = neighbors[(neighbors.index(u) + 1) % len(neighbors)] e = (v, next_node) @@ -6417,8 +6423,7 @@ def planar_dual(self, embedding=None): edges.append([v1, v2, self.edge_label(e[0], e[1])]) return Graph([verts, edges]) - - ### Connectivity + # Connectivity def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -6520,7 +6525,9 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, cc = g.connected_component_containing_vertex(vertices[0]) if any(v not in cc for v in vertices): from sage.categories.sets_cat import EmptySetError - raise EmptySetError("the given vertices do not all belong to the same connected component. This problem has no solution !") + raise EmptySetError("the given vertices do not all belong to the " + "same connected component. This problem has " + "no solution !") # Can it be solved using the min spanning tree algorithm ? if not weighted: @@ -6551,22 +6558,22 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, p.add_constraint(p.sum(edges[frozenset(e)] for e in g.edges_incident(v, labels=False)), min=1) # The number of edges is equal to the number of vertices in our tree minus 1 - p.add_constraint( p.sum(vertex[v] for v in g) - - p.sum(edges[frozenset(e)] for e in g.edge_iterator(labels=False)), max=1, min=1) + p.add_constraint(p.sum(vertex[v] for v in g) + - p.sum(edges[frozenset(e)] for e in g.edge_iterator(labels=False)), max=1, min=1) # There are no cycles in our graph - for u,v in g.edge_iterator(labels=False): - p.add_constraint(r_edges[u,v]+ r_edges[v,u] - edges[frozenset((u,v))], min=0) + for u, v in g.edge_iterator(labels=False): + p.add_constraint(r_edges[u, v] + r_edges[v, u] - edges[frozenset((u, v))], min=0) - eps = 1/(5*Integer(g.order())) + eps = 1 / (5 * Integer(g.order())) for v in g: - p.add_constraint(p.sum(r_edges[u,v] for u in g.neighbor_iterator(v)), max=1-eps) - + p.add_constraint(p.sum(r_edges[u, v] for u in g.neighbor_iterator(v)), max=1 - eps) # Objective if weighted: - p.set_objective(p.sum((l if l is not None else 1)*edges[frozenset((u,v))] for u,v,l in g.edge_iterator())) + p.set_objective(p.sum((l if l is not None else 1) * edges[frozenset((u, v))] + for u, v, l in g.edge_iterator())) else: p.set_objective(p.sum(edges[frozenset(e)] for e in g.edge_iterator(labels=False))) @@ -6574,13 +6581,13 @@ def steiner_tree(self, vertices, weighted=False, solver=None, verbose=0, edges = p.get_values(edges, convert=bool, tolerance=integrality_tolerance) - st = g.subgraph(edges=[e for e in g.edge_iterator(labels=False) if edges[frozenset(e)]], - immutable=False) + st = g.subgraph(edges=[e for e in g.edge_iterator(labels=False) if edges[frozenset(e)]], + immutable=False) st.delete_vertices(v for v in g if not st.degree(v)) return st def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None, verbose=0, - *, integrality_tolerance=1e-3): + *, integrality_tolerance=1e-3): r""" Return the desired number of edge-disjoint spanning trees/arborescences. @@ -6815,8 +6822,8 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None # A vertex has at least one incident edge for u in D: p.add_constraint(p.sum(edge[e, c] for e in D.incoming_edge_iterator(u, labels=False)) - + p.sum(edge[e, c] for e in D.outgoing_edge_iterator(u, labels=False)) - >= 1) + + p.sum(edge[e, c] for e in D.outgoing_edge_iterator(u, labels=False)) + >= 1) # We use the Miller-Tucker-Zemlin subtour elimination constraints # combined with the Desrosiers-Langevin strengthening constraints @@ -6824,7 +6831,7 @@ def edge_disjoint_spanning_trees(self, k, algorithm=None, root=None, solver=None if D.has_edge(v, u): # DL p.add_constraint(pos[u, c] + (n - 1)*edge[(u, v), c] + (n - 3)*edge[(v, u), c] - <= pos[v, c] + n - 2) + <= pos[v, c] + n - 2) else: # MTZ: If edge uv is selected, v is after u in the partial ordering p.add_constraint(pos[u, c] + 1 - n * (1 - edge[(u, v), c]) <= pos[v, c]) @@ -7021,10 +7028,10 @@ def weight(x): flow_value, flow_graph = self.flow(s, t, value_only=value_only, use_edge_labels=use_edge_labels, algorithm=algorithm) - for u,v,l in flow_graph.edge_iterator(): + for u, v, l in flow_graph.edge_iterator(): g.add_edge(v, u) if (not use_edge_labels or - (weight(g.edge_label(u, v)) == weight(l))): + weight(g.edge_label(u, v)) == weight(l)): g.delete_edge(u, v) return_value = [flow_value] @@ -7067,22 +7074,22 @@ def good_edge(e): # Adjacent vertices can belong to different parts only if the # edge that connects them is part of the cut - for x,y in g.edge_iterator(labels=None): + for x, y in g.edge_iterator(labels=None): p.add_constraint(v[x] + b[good_edge((x, y))] - v[y], min=0) else: # we minimize the number of edges - p.set_objective(p.sum(weight(w) * b[good_edge((x,y))] for x, y, w in g.edge_iterator())) + p.set_objective(p.sum(weight(w) * b[good_edge((x, y))] for x, y, w in g.edge_iterator())) # Adjacent vertices can belong to different parts only if the # edge that connects them is part of the cut - for x,y in g.edge_iterator(labels=None): + for x, y in g.edge_iterator(labels=None): p.add_constraint(v[x] + b[good_edge((x, y))] - v[y], min=0) p.add_constraint(v[y] + b[good_edge((x, y))] - v[x], min=0) p.solve(log=verbose) b = p.get_values(b, convert=bool, tolerance=integrality_tolerance) if use_edge_labels: - obj = sum(weight(w) for x, y, w in g.edge_iterator() if b[good_edge((x,y))]) + obj = sum(weight(w) for x, y, w in g.edge_iterator() if b[good_edge((x, y))]) else: obj = Integer(sum(1 for e in g.edge_iterator(labels=False) if b[good_edge(e)])) @@ -7196,13 +7203,13 @@ def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose if g.is_directed(): # adjacent vertices belong to the same part except if one of them # belongs to the cut - for x,y in g.edge_iterator(labels=None): + for x, y in g.edge_iterator(labels=None): p.add_constraint(v[x] + b[y] - v[y], min=0) else: # adjacent vertices belong to the same part except if one of them # belongs to the cut - for x,y in g.edge_iterator(labels=None): + for x, y in g.edge_iterator(labels=None): p.add_constraint(v[x] + b[y] >= v[y]) p.add_constraint(v[y] + b[x] >= v[x]) @@ -7228,7 +7235,6 @@ def vertex_cut(self, s, t, value_only=True, vertices=False, solver=None, verbose answer.append([l0, l1]) return tuple(answer) - def multiway_cut(self, vertices, value_only=False, use_edge_labels=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" @@ -7337,29 +7343,29 @@ def weight(l): p.set_objective(p.sum(weight(l) * cut[good_edge((u, v))] for u, v, l in self.edge_iterator())) if self.is_directed(): - for s,t in chain(combinations(vertices, 2), [(y, x) for x, y in combinations(vertices, 2)]): + for s, t in chain(combinations(vertices, 2), [(y, x) for x, y in combinations(vertices, 2)]): # For each commodity, the source is at height 0 # and the destination is at height 1 - p.add_constraint(height[(s,t),s], min=0, max=0) - p.add_constraint(height[(s,t),t], min=1, max=1) + p.add_constraint(height[(s, t), s], min=0, max=0) + p.add_constraint(height[(s, t), t], min=1, max=1) # given a commodity (s,t), the height of two adjacent vertices u,v # can differ of at most the value of the edge between them - for u,v in self.edge_iterator(labels=False): - p.add_constraint(height[(s,t),u] - height[(s,t),v] - cut[good_edge((u, v))], max=0) + for u, v in self.edge_iterator(labels=False): + p.add_constraint(height[(s, t), u] - height[(s, t), v] - cut[good_edge((u, v))], max=0) else: - for s,t in combinations(vertices, 2): + for s, t in combinations(vertices, 2): # For each commodity, the source is at height 0 # and the destination is at height 1 - p.add_constraint(height[(s,t),s], min=0, max=0) - p.add_constraint(height[(s,t),t], min=1, max=1) + p.add_constraint(height[(s, t), s], min=0, max=0) + p.add_constraint(height[(s, t), t], min=1, max=1) # given a commodity (s,t), the height of two adjacent vertices u,v # can differ of at most the value of the edge between them - for u,v in self.edge_iterator(labels=False): - p.add_constraint(height[(s,t),u] - height[(s,t),v] - cut[good_edge((u,v))], max=0) - p.add_constraint(height[(s,t),v] - height[(s,t),u] - cut[good_edge((u,v))], max=0) + for u, v in self.edge_iterator(labels=False): + p.add_constraint(height[(s, t), u] - height[(s, t), v] - cut[good_edge((u, v))], max=0) + p.add_constraint(height[(s, t), v] - height[(s, t), u] - cut[good_edge((u, v))], max=0) p.solve(log=verbose) cut = p.get_values(cut, convert=bool, tolerance=integrality_tolerance) @@ -7372,7 +7378,6 @@ def weight(l): return [e for e in self.edge_iterator() if cut[good_edge((e[0], e[1]))]] - def max_cut(self, value_only=True, use_edge_labels=False, vertices=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" @@ -7469,30 +7474,30 @@ def good_edge(e): # A vertex has to be in some set for v in g: - p.add_constraint(in_set[0,v] + in_set[1,v], max=1, min=1) + p.add_constraint(in_set[0, v] + in_set[1, v], max=1, min=1) # There is no empty set - p.add_constraint(p.sum(in_set[1,v] for v in g), min=1) - p.add_constraint(p.sum(in_set[0,v] for v in g), min=1) + p.add_constraint(p.sum(in_set[1, v] for v in g), min=1) + p.add_constraint(p.sum(in_set[0, v] for v in g), min=1) if g.is_directed(): # There is no edge from set 0 to set 1 which is not in the cut. # Besides, an edge can only be in the cut if its vertices # belong to different sets - for u,v in g.edge_iterator(labels=None): - p.add_constraint(in_set[0,u] + in_set[1,v] - in_cut[u,v], max=1) - p.add_constraint(in_set[0,u] + in_set[0,v] + in_cut[u,v], max=2) - p.add_constraint(in_set[1,u] + in_set[1,v] + in_cut[u,v], max=2) + for u, v in g.edge_iterator(labels=None): + p.add_constraint(in_set[0, u] + in_set[1, v] - in_cut[u, v], max=1) + p.add_constraint(in_set[0, u] + in_set[0, v] + in_cut[u, v], max=2) + p.add_constraint(in_set[1, u] + in_set[1, v] + in_cut[u, v], max=2) else: # Two adjacent vertices are in different sets if and only if # the edge between them is in the cut - for u,v in g.edge_iterator(labels=None): + for u, v in g.edge_iterator(labels=None): fuv = good_edge((u, v)) - p.add_constraint(in_set[0,u] + in_set[1,v] - in_cut[fuv], max=1) - p.add_constraint(in_set[1,u] + in_set[0,v] - in_cut[fuv], max=1) - p.add_constraint(in_set[0,u] + in_set[0,v] + in_cut[fuv], max=2) - p.add_constraint(in_set[1,u] + in_set[1,v] + in_cut[fuv], max=2) + p.add_constraint(in_set[0, u] + in_set[1, v] - in_cut[fuv], max=1) + p.add_constraint(in_set[1, u] + in_set[0, v] - in_cut[fuv], max=1) + p.add_constraint(in_set[0, u] + in_set[0, v] + in_cut[fuv], max=2) + p.add_constraint(in_set[1, u] + in_set[1, v] + in_cut[fuv], max=2) p.set_objective(p.sum(weight(l) * in_cut[good_edge((u, v))] for u, v, l in g.edge_iterator())) @@ -7515,11 +7520,11 @@ def good_edge(e): a = [] b = [] for v in g: - if in_set[0,v]: + if in_set[0, v]: a.append(v) else: b.append(v) - val.append([a,b]) + val.append([a, b]) return val @@ -7764,9 +7769,11 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", # Associating a weight to a label if use_edge_labels: - weight = lambda x: x if (x is not None and x != {}) else 1 + def weight(x): + return x if (x is not None and x != {}) else 1 else: - weight = lambda x: 1 + def weight(x): + return 1 from sage.numerical.mip import MixedIntegerLinearProgram p = MixedIntegerLinearProgram(solver=solver) @@ -7786,62 +7793,54 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", # if edge uv is used, vu cannot be for u, v in self.edge_iterator(labels=False): if self.has_edge(v, u): - p.add_constraint(edge_used[u,v] + edge_used[v,u] <= 1) + p.add_constraint(edge_used[u, v] + edge_used[v, u] <= 1) # A vertex is used if one of its incident edges is - for u,v in self.edge_iterator(labels=False): - p.add_constraint(vertex_used[v] >= edge_used[u,v]) - p.add_constraint(vertex_used[u] >= edge_used[u,v]) + for u, v in self.edge_iterator(labels=False): + p.add_constraint(vertex_used[v] >= edge_used[u, v]) + p.add_constraint(vertex_used[u] >= edge_used[u, v]) # A path is a tree. If n vertices are used, at most n-1 edges are - p.add_constraint( - p.sum(vertex_used[v] for v in self) - - p.sum(edge_used[e] for e in self.edge_iterator(labels=False)) - == 1) + p.add_constraint(p.sum(vertex_used[v] for v in self) + - p.sum(edge_used[e] for e in self.edge_iterator(labels=False)) + == 1) # A vertex has at most one incoming used edge and at most # one outgoing used edge for v in self: - p.add_constraint( - p.sum(edge_used[u,v] for u in self.neighbor_in_iterator(v)) <= 1) - p.add_constraint( - p.sum(edge_used[v,u] for u in self.neighbor_out_iterator(v)) <= 1) + p.add_constraint(p.sum(edge_used[u, v] for u in self.neighbor_in_iterator(v)) <= 1) + p.add_constraint(p.sum(edge_used[v, u] for u in self.neighbor_out_iterator(v)) <= 1) # r_edge_used is "more" than edge_used, though it ignores # the direction - for u,v in self.edge_iterator(labels=False): - p.add_constraint(r_edge_used[u,v] + r_edge_used[v,u] - >= edge_used[u,v]) + for u, v in self.edge_iterator(labels=False): + p.add_constraint(r_edge_used[u, v] + r_edge_used[v, u] + >= edge_used[u, v]) # No cycles for v in self: - p.add_constraint( - p.sum(r_edge_used[u,v] for u in self.neighbor_iterator(v)) - <= 1-epsilon) + p.add_constraint(p.sum(r_edge_used[u, v] for u in self.neighbor_iterator(v)) + <= 1 - epsilon) # Enforcing the source if asked.. If s is set, it has no # incoming edge and exactly one son if s is not None: - p.add_constraint( - p.sum(edge_used[u,s] for u in self.neighbor_in_iterator(s)), - max=0, min=0) - p.add_constraint( - p.sum(edge_used[s,u] for u in self.neighbor_out_iterator(s)), - min=1, max=1) + p.add_constraint(p.sum(edge_used[u, s] for u in self.neighbor_in_iterator(s)), + max=0, min=0) + p.add_constraint(p.sum(edge_used[s, u] for u in self.neighbor_out_iterator(s)), + min=1, max=1) # Enforcing the destination if asked.. If t is set, it has # no outgoing edge and exactly one parent if t is not None: - p.add_constraint( - p.sum(edge_used[u,t] for u in self.neighbor_in_iterator(t)), - min=1, max=1) - p.add_constraint( - p.sum(edge_used[t,u] for u in self.neighbor_out_iterator(t)), - max=0, min=0) + p.add_constraint(p.sum(edge_used[u, t] for u in self.neighbor_in_iterator(t)), + min=1, max=1) + p.add_constraint(p.sum(edge_used[t, u] for u in self.neighbor_out_iterator(t)), + max=0, min=0) # Defining the objective - p.set_objective( - p.sum(weight(l) * edge_used[u,v] for u, v, l in self.edge_iterator())) + p.set_objective(p.sum(weight(l) * edge_used[u, v] + for u, v, l in self.edge_iterator())) else: # We use edge_used[frozenset((u, v))] to avoid having two different # variables for edge (u, v) @@ -7849,40 +7848,37 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", # A vertex is used if one of its incident edges is for v in self: for u in self.neighbor_iterator(v): - p.add_constraint(vertex_used[v] - edge_used[frozenset((u,v))], min=0) + p.add_constraint(vertex_used[v] - edge_used[frozenset((u, v))], min=0) # A path is a tree. If n vertices are used, at most n-1 edges are - p.add_constraint( - p.sum(vertex_used[v] for v in self) - - p.sum(edge_used[frozenset((u,v))] for u, v in self.edge_iterator(labels=False)), - min=1, max=1) + p.add_constraint(p.sum(vertex_used[v] for v in self) + - p.sum(edge_used[frozenset((u, v))] + for u, v in self.edge_iterator(labels=False)), + min=1, max=1) # A vertex has at most two incident edges used for v in self: - p.add_constraint( - p.sum(edge_used[frozenset((u,v))] for u in self.neighbor_iterator(v)), max=2) + p.add_constraint(p.sum(edge_used[frozenset((u, v))] for u in self.neighbor_iterator(v)), + max=2) # r_edge_used is "more" than edge_used for u, v in self.edge_iterator(labels=False): - p.add_constraint(r_edge_used[u,v] - + r_edge_used[v,u] - - edge_used[frozenset((u,v))], + p.add_constraint(r_edge_used[u, v] + + r_edge_used[v, u] + - edge_used[frozenset((u, v))], min=0) # No cycles for v in self: - p.add_constraint( - p.sum(r_edge_used[u,v] for u in self.neighbor_iterator(v)), - max=1-epsilon) + p.add_constraint(p.sum(r_edge_used[u, v] for u in self.neighbor_iterator(v)), + max=1 - epsilon) # Enforcing the destination if asked.. If s or t are set, # they have exactly one incident edge if s is not None: - p.add_constraint( - p.sum(edge_used[frozenset((s,u))] for u in self.neighbor_iterator(s)), - max=1, min=1) + p.add_constraint(p.sum(edge_used[frozenset((s, u))] for u in self.neighbor_iterator(s)), + max=1, min=1) if t is not None: - p.add_constraint( - p.sum(edge_used[frozenset((t,u))] for u in self.neighbor_iterator(t)), - max=1, min=1) + p.add_constraint(p.sum(edge_used[frozenset((t, u))] for u in self.neighbor_iterator(t)), + max=1, min=1) # Defining the objective - p.set_objective(p.sum(weight(l) * edge_used[frozenset((u,v))] - for u, v, l in self.edge_iterator())) + p.set_objective(p.sum(weight(l) * edge_used[frozenset((u, v))] + for u, v, l in self.edge_iterator())) # Computing the result. No exception has to be raised, as this # problem always has a solution (there is at least one edge, @@ -7891,15 +7887,14 @@ def longest_path(self, s=None, t=None, use_edge_labels=False, algorithm="MILP", edge_used = p.get_values(edge_used, convert=bool, tolerance=integrality_tolerance) vertex_used = p.get_values(vertex_used, convert=bool, tolerance=integrality_tolerance) if self._directed: - g = self.subgraph( - vertices=(v for v in self if vertex_used[v]), - edges=((u,v,l) for u, v, l in self.edge_iterator() - if edge_used[u,v])) + g = self.subgraph(vertices=(v for v in self if vertex_used[v]), + edges=((u, v, l) for u, v, l in self.edge_iterator() + if edge_used[u, v])) else: g = self.subgraph( vertices=(v for v in self if vertex_used[v]), - edges=((u,v,l) for u, v, l in self.edge_iterator() - if edge_used[frozenset((u,v))])) + edges=((u, v, l) for u, v, l in self.edge_iterator() + if edge_used[frozenset((u, v))])) if use_edge_labels: return sum(map(weight, g.edge_labels())), g else: @@ -8058,7 +8053,6 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, else: g = self.copy(immutable=False) - new_s, new_t = s, t if g.is_directed(): # @@ -8098,7 +8092,7 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, # Set new_s and new_t if possible if new_s is None and new_t is None: - new_s,new_t = ones + new_s, new_t = ones elif new_s is not None and new_t is None: new_t = ones[1] if new_s == ones[0] else ones[0] elif new_s is None and new_t is not None: @@ -8128,7 +8122,7 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, # source and an edge from it to each vertex of the (di)graph. new_s = g.add_vertex() extra_vertices.append(new_s) - for u in self: # in original set of vertices + for u in self: # in original set of vertices g.add_edge(new_s, u, 0) if new_t is None: @@ -8152,22 +8146,23 @@ def hamiltonian_path(self, s=None, t=None, use_edge_labels=False, from sage.categories.sets_cat import EmptySetError try: tsp = g.traveling_salesman_problem(use_edge_labels=use_edge_labels, - maximize=maximize, - solver=solver, verbose=verbose, - integrality_tolerance=integrality_tolerance) + maximize=maximize, + solver=solver, verbose=verbose, + integrality_tolerance=integrality_tolerance) except EmptySetError: return (0, None) if use_edge_labels else None tsp.delete_vertices(extra_vertices) tsp.name("Hamiltonian path from {}".format(self.name())) - weight = lambda l: 1 if l is None else l - return (sum(map(weight,tsp.edge_labels())), tsp) if use_edge_labels else tsp + def weight(label): + return 1 if label is None else label + return (sum(map(weight, tsp.edge_labels())), tsp) if use_edge_labels else tsp def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, - solver=None, constraint_generation=None, - verbose=0, verbose_constraints=False, - *, integrality_tolerance=1e-3): + solver=None, constraint_generation=None, + verbose=0, verbose_constraints=False, + *, integrality_tolerance=1e-3): r""" Solve the traveling salesman problem (TSP) @@ -8392,9 +8387,11 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, # Associating a weight to a label if use_edge_labels: - weight = lambda l: 1 if l is None else l + def weight(label): + return 1 if label is None else label else: - weight = lambda l: 1 + def weight(label): + return 1 ######################## # 0 or 1 vertex graphs # @@ -8408,7 +8405,7 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, ##################### if self.order() == 2: - uu,vv = list(self) + uu, vv = list(self) if self.is_directed(): if self.has_edge(uu, vv) and self.has_edge(vv, uu): if self.allows_multiple_edges(): @@ -8433,7 +8430,7 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, edges = self.edges(sort=True, key=weight)[:2] answer = self.subgraph(edges=edges, immutable=self.is_immutable()) answer.set_pos(self.get_pos()) - answer.name("TSP from "+self.name()) + answer.name("TSP from " + self.name()) return answer raise EmptySetError("the given graph is not Hamiltonian") @@ -8466,7 +8463,6 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, else: g = self - if constraint_generation is None: if g.density() > .7: constraint_generation = False @@ -8495,13 +8491,13 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, # Objective function if use_edge_labels: - p.set_objective(p.sum(weight(l)*b[u,v] for u,v,l in g.edge_iterator())) + p.set_objective(p.sum(weight(l) * b[u, v] for u, v, l in g.edge_iterator())) # All the vertices have in-degree 1 and out-degree 1 for v in g: - p.add_constraint(p.sum(b[u,v] for u in g.neighbor_in_iterator(v)), + p.add_constraint(p.sum(b[u, v] for u in g.neighbor_in_iterator(v)), min=1, max=1) - p.add_constraint(p.sum(b[v,u] for u in g.neighbor_out_iterator(v)), + p.add_constraint(p.sum(b[v, u] for u in g.neighbor_out_iterator(v)), min=1, max=1) # Initial Solve @@ -8514,9 +8510,9 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, # We build the DiGraph representing the current solution h = DiGraph() b_val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - for u,v,l in g.edge_iterator(): - if b_val[u,v]: - h.add_edge(u,v,l) + for u, v, l in g.edge_iterator(): + if b_val[u, v]: + h.add_edge(u, v, l) # If there is only one circuit, we are done ! cc = h.connected_components(sort=False) @@ -8527,12 +8523,11 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, for c in cc: if verbose_constraints: print("Adding a constraint on set", c) - p.add_constraint(p.sum(b[u,v] for u,v in - g.edge_boundary(c, labels=False)), - min=1) + p.add_constraint(p.sum(b[u, v] for u, v in g.edge_boundary(c, labels=False)), + min=1) try: - p.solve(log = verbose) + p.solve(log=verbose) except MIPSolverException: raise EmptySetError("the given graph is not Hamiltonian") @@ -8545,16 +8540,16 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, # Objective function if use_edge_labels: - p.set_objective(p.sum(weight(l) * b[frozenset((u,v))] for u,v,l in g.edge_iterator())) + p.set_objective(p.sum(weight(l) * b[frozenset((u, v))] for u, v, l in g.edge_iterator())) # All the vertices have degree 2 for v in g: - p.add_constraint(p.sum(b[frozenset((u,v))] for u in g.neighbor_iterator(v)), + p.add_constraint(p.sum(b[frozenset((u, v))] for u in g.neighbor_iterator(v)), min=2, max=2) # Initial Solve try: - p.solve(log = verbose) + p.solve(log=verbose) except MIPSolverException: raise EmptySetError("the given graph is not Hamiltonian") @@ -8562,7 +8557,7 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, # We build the DiGraph representing the current solution h = Graph() b_val = p.get_values(b, convert=bool, tolerance=integrality_tolerance) - h.add_edges((u,v,l) for u,v,l in g.edge_iterator() if b_val[frozenset((u,v))]) + h.add_edges((u, v, l) for u, v, l in g.edge_iterator() if b_val[frozenset((u, v))]) # If there is only one circuit, we are done ! cc = h.connected_components(sort=False) @@ -8573,8 +8568,8 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, for c in cc: if verbose_constraints: print("Adding a constraint on set", c) - p.add_constraint(p.sum(b[frozenset((u,v))] for u,v in g.edge_boundary(c, labels=False)), - min=2) + p.add_constraint(p.sum(b[frozenset((u, v))] for u, v in g.edge_boundary(c, labels=False)), + min=2) try: p.solve(log=verbose) @@ -8602,27 +8597,27 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, if g.is_directed(): # All the vertices have in-degree 1 and out-degree 1 for v in g: - p.add_constraint(p.sum(f[u,v] for u in g.neighbor_in_iterator(v)), + p.add_constraint(p.sum(f[u, v] for u in g.neighbor_in_iterator(v)), min=1, max=1) - p.add_constraint(p.sum(f[v,u] for u in g.neighbor_out_iterator(v)), + p.add_constraint(p.sum(f[v, u] for u in g.neighbor_out_iterator(v)), min=1, max=1) # r is greater than f vertex_to_int = {u: i for i, u in enumerate(g)} - for u,v in g.edge_iterator(labels=None): - if g.has_edge(v,u): + for u, v in g.edge_iterator(labels=None): + if g.has_edge(v, u): if vertex_to_int[u] < vertex_to_int[v]: - p.add_constraint(r[u,v] + r[v,u]- f[u,v] - f[v,u], min=0) + p.add_constraint(r[u, v] + r[v, u] - f[u, v] - f[v, u], min=0) # no 2-cycles - p.add_constraint(f[u,v] + f[v,u], max=1) + p.add_constraint(f[u, v] + f[v, u], max=1) else: - p.add_constraint(r[u,v] + r[v,u] - f[u,v], min=0) + p.add_constraint(r[u, v] + r[v, u] - f[u, v], min=0) if use_edge_labels: - p.set_objective(p.sum(weight(l) * f[u,v] for u,v,l in g.edge_iterator())) + p.set_objective(p.sum(weight(l) * f[u, v] for u, v, l in g.edge_iterator())) # defining the answer when g is directed from sage.graphs.digraph import DiGraph @@ -8631,44 +8626,42 @@ def traveling_salesman_problem(self, use_edge_labels=False, maximize=False, else: # All the vertices have degree 2 for v in g: - p.add_constraint(p.sum(f[frozenset((u,v))] for u in g.neighbor_iterator(v)), + p.add_constraint(p.sum(f[frozenset((u, v))] for u in g.neighbor_iterator(v)), min=2, max=2) # r is greater than f - for u,v in g.edge_iterator(labels = None): - p.add_constraint( r[u,v] + r[v,u] - f[frozenset((u,v))], min=0) + for u, v in g.edge_iterator(labels=None): + p.add_constraint(r[u, v] + r[v, u] - f[frozenset((u, v))], min=0) if use_edge_labels: - p.set_objective(p.sum(weight(l) * f[frozenset((u,v))] for u,v,l in g.edge_iterator())) + p.set_objective(p.sum(weight(l) * f[frozenset((u, v))] for u, v, l in g.edge_iterator())) from sage.graphs.graph import Graph # defining the answer when g is not directed tsp = Graph() - # no cycle which does not contain x for v in g: if v != x: - p.add_constraint(p.sum(r[u,v] for u in g.neighbor_iterator(v)), max=1-eps) + p.add_constraint(p.sum(r[u, v] for u in g.neighbor_iterator(v)), max=1 - eps) try: p.solve(log=verbose) f_val = p.get_values(f, convert=bool, tolerance=integrality_tolerance) tsp.add_vertices(g.vertex_iterator()) tsp.set_pos(g.get_pos()) - tsp.name("TSP from "+g.name()) + tsp.name("TSP from " + g.name()) if g.is_directed(): - tsp.add_edges((u,v,l) for u,v,l in g.edge_iterator() if f_val[u,v] == 1) + tsp.add_edges((u, v, l) for u, v, l in g.edge_iterator() if f_val[u, v] == 1) else: - tsp.add_edges((u,v,l) for u,v,l in g.edge_iterator() if f_val[frozenset((u,v))] == 1) + tsp.add_edges((u, v, l) for u, v, l in g.edge_iterator() if f_val[frozenset((u, v))] == 1) return tsp except MIPSolverException: raise EmptySetError("the given graph is not Hamiltonian") - def hamiltonian_cycle(self, algorithm='tsp', solver=None, constraint_generation=None, verbose=0, verbose_constraints=False, *, integrality_tolerance=1e-3): @@ -8943,7 +8936,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, # It would be a pity to start a LP if the graph is already acyclic if ((not self.is_directed() and self.is_forest()) or - ( self.is_directed() and self.is_directed_acyclic())): + (self.is_directed() and self.is_directed_acyclic())): if value_only: return 0 return [] @@ -9003,9 +8996,9 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, else: - ###################################### - # Ordering-based MILP Implementation # - ###################################### + ###################################### + # Ordering-based MILP Implementation # + ###################################### p = MixedIntegerLinearProgram(maximization=False, solver=solver) @@ -9014,7 +9007,7 @@ def feedback_vertex_set(self, value_only=False, solver=None, verbose=0, n = self.order() # The removed vertices cover all the back arcs ( third condition ) - for u,v in self.edge_iterator(labels=None): + for u, v in self.edge_iterator(labels=None): p.add_constraint(d[u] - d[v] + n * (b[u] + b[v]), min=1) for u in self: @@ -9222,14 +9215,15 @@ def capacity(z): algorithm = "FF" if (algorithm == "FF"): - return self._ford_fulkerson(x,y, value_only=value_only, integer=integer, use_edge_labels=use_edge_labels) + return self._ford_fulkerson(x, y, value_only=value_only, integer=integer, use_edge_labels=use_edge_labels) elif (algorithm == 'igraph'): vertices = list(self) x_int = vertices.index(x) y_int = vertices.index(y) if use_edge_labels: g_igraph = self.igraph_graph(vertex_list=vertices, - edge_attrs={'capacity':[float(capacity(e[2])) for e in self.edge_iterator()]}) + edge_attrs={'capacity': [float(capacity(e[2])) + for e in self.edge_iterator()]}) maxflow = g_igraph.maxflow(x_int, y_int, 'capacity') else: g_igraph = self.igraph_graph(vertex_list=vertices) @@ -9263,7 +9257,6 @@ def capacity(z): raise ValueError("the algorithm argument has to be equal to either " "\"FF\", \"LP\", \"igraph\", or None") - from sage.numerical.mip import MixedIntegerLinearProgram g = self p = MixedIntegerLinearProgram(maximization=True, solver=solver) @@ -9272,24 +9265,30 @@ def capacity(z): if g.is_directed(): # This function return the balance of flow at X - flow_sum = lambda X: (p.sum(flow[X,v] for u,v in g.outgoing_edge_iterator([X], labels=None)) - - p.sum(flow[u,X] for u,v in g.incoming_edge_iterator([X], labels=None))) + def flow_sum(X): + return (p.sum(flow[X, v] for u, v in g.outgoing_edge_iterator([X], labels=None)) + - p.sum(flow[u, X] for u, v in g.incoming_edge_iterator([X], labels=None))) # The flow leaving x - flow_leaving = lambda X: p.sum(flow[uu,vv] for uu,vv in g.outgoing_edge_iterator([X], labels=None)) + def flow_leaving(X): + return p.sum(flow[uu, vv] for uu, vv in g.outgoing_edge_iterator([X], labels=None)) # The flow to be considered when defining the capacity constraints - capacity_sum = lambda u,v: flow[u,v] + def capacity_sum(u, v): + return flow[u, v] else: # This function return the balance of flow at X - flow_sum = lambda X: p.sum(flow[X,v] - flow[v,X] for v in g[X]) + def flow_sum(X): + return p.sum(flow[X, v] - flow[v, X] for v in g[X]) # The flow leaving x - flow_leaving = lambda X: p.sum(flow[X,vv] for vv in g[X]) + def flow_leaving(X): + return p.sum(flow[X, vv] for vv in g[X]) # The flow to be considered when defining the capacity constraints - capacity_sum = lambda u,v: flow[u,v] + flow[v,u] + def capacity_sum(u, v): + return flow[u, v] + flow[v, u] # Maximizes the flow leaving x p.add_constraint(flow_sum(x) == obj[0]) @@ -9301,8 +9300,8 @@ def capacity(z): p.add_constraint(flow_sum(v), min=0, max=0) # Capacity constraints - for u,v,w in g.edge_iterator(): - p.add_constraint(capacity_sum(u,v), max=capacity(w)) + for u, v, w in g.edge_iterator(): + p.add_constraint(capacity_sum(u, v), max=capacity(w)) # No vertex except the sources can send more than 1 if vertex_bound: @@ -9477,7 +9476,7 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler ValueError: parameter 'k' must be at least 2 """ if k is None: - k = 6 # See [Sey1981]_ + k = 6 # See [Sey1981]_ elif k < 2: raise ValueError("parameter 'k' must be at least 2") @@ -9496,8 +9495,8 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler return solution # If the (di)graph has bridges, the problem is not feasible - if ( (self.is_directed() and not self.is_strongly_connected() and next(self.to_undirected().bridges(), False)) - or (not self.is_directed() and next(self.bridges(), False)) ): + if ((self.is_directed() and not self.is_strongly_connected() and next(self.to_undirected().bridges(), False)) + or (not self.is_directed() and next(self.bridges(), False))): raise EmptySetError("(di)graphs with bridges have no feasible solution") # @@ -9507,13 +9506,13 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler G = copy(self) if self.is_directed() else next(self.orientations()) # We assign flow 1 to loops, if any - solution = DiGraph([list(G), [(u,v,1) for u,v in G.loops(labels=0)]], + solution = DiGraph([list(G), [(u, v, 1) for u, v in G.loops(labels=False)]], loops=G.has_loops(), multiedges=G.has_multiple_edges()) G.allow_loops(False) # We ensure that multiple edges have distinct labels - multiedges = {(u,v,i) for i,(u,v) in enumerate(G.multiple_edges(labels=0))} + multiedges = {(u, v, i) for i, (u, v) in enumerate(G.multiple_edges(labels=0))} G.delete_edges(G.multiple_edges()) G.add_edges(multiedges) @@ -9527,20 +9526,20 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler # # We use a MIP formulation to solve the problem # - from sage.numerical.mip import MixedIntegerLinearProgram,MIPSolverException + from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException p = MixedIntegerLinearProgram(solver=solver) f = p.new_variable(nonnegative=False, integer=True) b = p.new_variable(nonnegative=True, binary=True) # flow conservation constraints for u in G: - p.add_constraint( p.sum(f[e] for e in G.incoming_edge_iterator(u)) - == p.sum(f[e] for e in G.outgoing_edge_iterator(u))) + p.add_constraint(p.sum(f[e] for e in G.incoming_edge_iterator(u)) == + p.sum(f[e] for e in G.outgoing_edge_iterator(u))) # The flow on edge e has value in {-k+1,..., -1, 1, ..., k-1} for e in G.edge_iterator(): - p.add_constraint(p.sum(b[e,i] for i in range(-k+1, k) if i) == 1) - p.add_constraint(f[e] == p.sum(i * b[e,i] for i in range(-k+1, k) if i)) + p.add_constraint(p.sum(b[e, i] for i in range(1 - k, k) if i) == 1) + p.add_constraint(f[e] == p.sum(i * b[e, i] for i in range(1 - k, k) if i)) # We solve the MIP. try: @@ -9551,7 +9550,7 @@ def nowhere_zero_flow(self, k=None, solver=None, verbose=0, *, integrality_toler # Extract and return the solution. If the graph is not directed, we # reverse edges with a negative flow to obtain a positive k-NZF f_val = p.get_values(f, convert=True, tolerance=integrality_tolerance) - for (u,v,_), val in f_val.items(): + for (u, v, _), val in f_val.items(): if self.is_directed() or val > 0: solution.add_edge(u, v, val) else: @@ -9631,9 +9630,11 @@ def _ford_fulkerson(self, s, t, use_edge_labels=False, integer=False, value_only # Whether we should consider the edges labeled if use_edge_labels: - l_capacity=lambda x: 1 if (x is None or x == {}) else (floor(x) if integer else x) + def l_capacity(x): + return 1 if (x is None or x == {}) else (floor(x) if integer else x) else: - l_capacity=lambda x: 1 + def l_capacity(x): + return 1 directed = self.is_directed() @@ -9652,7 +9653,7 @@ def _ford_fulkerson(self, s, t, use_edge_labels=False, integer=False, value_only # Initializing the variables if directed: - for u,v,l in self.edge_iterator(): + for u, v, l in self.edge_iterator(): if l_capacity(l) > 0: capacity[u, v] = l_capacity(l) + capacity.get((u, v), 0) capacity[v, u] = capacity.get((v, u), 0) @@ -9660,7 +9661,7 @@ def _ford_fulkerson(self, s, t, use_edge_labels=False, integer=False, value_only flow[u, v] = 0 flow[v, u] = 0 else: - for u,v,l in self.edge_iterator(): + for u, v, l in self.edge_iterator(): if l_capacity(l) > 0: capacity[u, v] = l_capacity(l) + capacity.get((u, v), 0) capacity[v, u] = l_capacity(l) + capacity.get((v, u), 0) @@ -9671,11 +9672,14 @@ def _ford_fulkerson(self, s, t, use_edge_labels=False, integer=False, value_only # Rewrites a path as a list of edges : # ex : [0,1,2,3,4,5] becomes [(0,1), (1,2), (2,3), (3,4), (4,5)] - path_to_edges = lambda P: zip(P[:-1], P[1:]) + def path_to_edges(P): + return zip(P[:-1], P[1:]) # Rewrites a path as a list of edges labeled with their # available capacity - path_to_labelled_edges = lambda P : [(x_y[0], x_y[1], capacity[x_y[0], x_y[1]] - flow[x_y[0], x_y[1]] + flow[x_y[1], x_y[0]]) for x_y in path_to_edges(P)] + def path_to_labelled_edges(P): + return [(x_y[0], x_y[1], capacity[x_y[0], x_y[1]] - flow[x_y[0], x_y[1]] + flow[x_y[1], x_y[0]]) + for x_y in path_to_edges(P)] # Total flow going from s to t flow_intensity = 0 @@ -9697,7 +9701,7 @@ def _ford_fulkerson(self, s, t, use_edge_labels=False, integer=False, value_only flow_intensity = flow_intensity + epsilon # Updating variables - for uu,vv,ll in edges: + for uu, vv, ll in edges: # The flow on the back arc other = flow[vv, uu] @@ -9817,7 +9821,7 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, # defining the set of terminals set_terminals = set() - for s,t,_ in terminals: + for s, t, _ in terminals: set_terminals.add(s) set_terminals.add(t) @@ -9827,34 +9831,42 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, # Whether to use edge labels if use_edge_labels: from sage.rings.real_mpfr import RR - capacity = lambda x: x if x in RR else 1 + + def capacity(x): + return x if x in RR else 1 else: - capacity = lambda x: 1 + def capacity(x): + return 1 if g.is_directed(): # This function return the balance of flow at X - flow_sum = lambda i,X: (p.sum(flow[i,(X,v)] for u,v in g.outgoing_edge_iterator([X], labels=None)) - - p.sum(flow[i,(u,X)] for u,v in g.incoming_edge_iterator([X], labels=None))) + def flow_sum(i, X): + return (p.sum(flow[i, (X, v)] for u, v in g.outgoing_edge_iterator([X], labels=None)) + - p.sum(flow[i, (u, X)] for u, v in g.incoming_edge_iterator([X], labels=None))) # The flow leaving x - flow_leaving = lambda i,X: p.sum(flow[i,(uu,vv)] for uu,vv in g.outgoing_edge_iterator([X], labels=None)) + def flow_leaving(i, X): + return p.sum(flow[i, (uu, vv)] for uu, vv in g.outgoing_edge_iterator([X], labels=None)) # the flow to consider when defining the capacity constraints - capacity_sum = lambda i,u,v: flow[i,(u,v)] + def capacity_sum(i, u, v): + return flow[i, (u, v)] else: # This function return the balance of flow at X - flow_sum = lambda i,X: p.sum(flow[i,(X,v)] - flow[i,(v,X)] for v in g.neighbor_iterator(X)) + def flow_sum(i, X): + return p.sum(flow[i, (X, v)] - flow[i, (v, X)] for v in g.neighbor_iterator(X)) # The flow leaving x - flow_leaving = lambda i, X: p.sum(flow[i,(X,vv)] for vv in g.neighbor_iterator(X)) + def flow_leaving(i, X): + return sum(flow[i, (X, vv)] for vv in g.neighbor_iterator(X)) # the flow to consider when defining the capacity constraints - capacity_sum = lambda i,u,v: flow[i,(u,v)] + flow[i,(v,u)] - + def capacity_sum(i, u, v): + return flow[i, (u, v)] + flow[i, (v, u)] # Flow constraints - for i,(s,t,l) in enumerate(terminals): + for i, (s, t, l) in enumerate(terminals): for v in g: if v == s: p.add_constraint(flow_sum(i, v), min=l, max=l) @@ -9864,7 +9876,7 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, p.add_constraint(flow_sum(i, v), min=0, max=0) # Capacity constraints - for u,v,w in g.edge_iterator(): + for u, v, w in g.edge_iterator(): p.add_constraint(p.sum(capacity_sum(i, u, v) for i in range(len(terminals))), max=capacity(w)) if vertex_bound: @@ -9874,7 +9886,7 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, # which is an endpoint if v in set_terminals: - for i,(s,t,_) in enumerate(terminals): + for i, (s, t, _) in enumerate(terminals): # only tolerates the commodities of which it is an endpoint if not (v == s or v == t): @@ -9883,7 +9895,7 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, # which is not an endpoint else: # can stand at most 1 unit of flow through itself - p.add_constraint(p.sum(flow_leaving(i,v) for i in range(len(terminals))), max=1) + p.add_constraint(p.sum(flow_leaving(i, v) for i in range(len(terminals))), max=1) p.set_objective(None) @@ -9900,7 +9912,7 @@ def multicommodity_flow(self, terminals, integer=True, use_edge_labels=False, flow = p.get_values(flow, convert=True, tolerance=integrality_tolerance) # building clean flow digraphs - flow_graphs = [g._build_flow_graph({e: f for (ii,e),f in flow.items() if ii == i}, integer=integer) + flow_graphs = [g._build_flow_graph({e: f for (ii, e), f in flow.items() if ii == i}, integer=integer) for i in range(len(terminals))] # which could be .. graphs ! @@ -9959,7 +9971,7 @@ def _build_flow_graph(self, flow, integer): g = DiGraph() # add significant edges - for (u,v),l in flow.items(): + for (u, v), l in flow.items(): if l: g.add_edge(u, v, l) @@ -10338,10 +10350,10 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, algorithm = algorithm.lower() if algorithm == 'networkx' or algorithm == 'scipy': import networkx - return networkx.pagerank(self.networkx_graph - (weight_function=weight_function), alpha=alpha, - personalization=personalization, weight=weight, - dangling=dangling) + gnx = self.networkx_graph(weight_function=weight_function) + return networkx.pagerank(gnx, alpha=alpha, + personalization=personalization, + weight=weight, dangling=dangling) elif algorithm == 'igraph': # An error will be raised if igraph is not installed if personalization: @@ -10358,7 +10370,7 @@ def pagerank(self, alpha=0.85, personalization=None, by_weight=False, else: raise NotImplementedError("only 'NetworkX', 'Scipy', and 'igraph' are supported") - ### Vertex handlers + # Vertex handlers def add_vertex(self, name=None): r""" @@ -10493,7 +10505,7 @@ def delete_vertex(self, vertex, in_order=False): if in_order: vertex = self.vertices(sort=True)[vertex] if vertex not in self: - raise ValueError("vertex (%s) not in the graph"%str(vertex)) + raise ValueError("vertex (%s) not in the graph" % str(vertex)) # TODO: remove this update from this method which should be as fast # as possible @@ -10544,7 +10556,7 @@ def delete_vertices(self, vertices): vertices = list(vertices) for v in vertices: if v not in self: - raise ValueError("vertex (%s) not in the graph"%str(v)) + raise ValueError("vertex (%s) not in the graph" % str(v)) # TODO: remove this update from this method which should be as fast # as possible @@ -11226,7 +11238,6 @@ def neighbors(self, vertex, closed=False): __getitem__ = neighbors - def merge_vertices(self, vertices): r""" Merge vertices. @@ -11324,14 +11335,14 @@ def merge_vertices(self, vertices): if self.is_directed(): out_edges = self.edge_boundary(vertices) in_edges = self.edge_boundary([v for v in self - if v not in vertices]) + if v not in vertices]) self.delete_vertices(vertices[1:]) self.add_edges((u, v0, l) for (u0, v0, l) in out_edges if u0 != u) self.add_edges((v0, u, l) for (v0, u0, l) in in_edges if u0 != u) else: edges = self.edge_boundary(vertices) self.delete_vertices(vertices[1:]) - add_edges=[] + add_edges = [] for u0, v0, l in edges: if v0 in vertices and v0 != u: add_edges.append((u, u0, l)) @@ -11339,7 +11350,7 @@ def merge_vertices(self, vertices): add_edges.append((u, v0, l)) self.add_edges(add_edges) - ### Edge handlers + # Edge handlers def add_edge(self, u, v=None, label=None): r""" @@ -11518,7 +11529,10 @@ def subdivide_edge(self, *args): sage: g.subdivide_edge(1, 2, "label2", 5) sage: print(g.edges(sort=True)) - [(0, 3, 'label1'), (1, 5, 'label1'), (1, 6, 'label2'), (2, 10, 'label2'), (3, 4, 'label1'), (4, 5, 'label1'), (6, 7, 'label2'), (7, 8, 'label2'), (8, 9, 'label2'), (9, 10, 'label2')] + [(0, 3, 'label1'), (1, 5, 'label1'), (1, 6, 'label2'), + (2, 10, 'label2'), (3, 4, 'label1'), (4, 5, 'label1'), + (6, 7, 'label2'), (7, 8, 'label2'), (8, 9, 'label2'), + (9, 10, 'label2')] If too many arguments are given, an exception is raised :: @@ -11816,8 +11830,8 @@ def contract_edge(self, u, v=None, label=None): if u == v: return - if (self.allows_loops() and (self.allows_multiple_edges() or - not self.has_edge(u, u))): + if (self.allows_loops() and + (self.allows_multiple_edges() or not self.has_edge(u, u))): # add loops for x, y, l in self.edges_incident(v): if set([x, y]) == set([u, v]): @@ -12000,7 +12014,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 +12031,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 +12088,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 +12125,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 +12186,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 +12320,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 +12379,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 +12566,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 +12668,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 +12703,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 +13001,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 +13284,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 +13311,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 +13466,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 +13906,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 +14113,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 +14157,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 +14202,6 @@ def is_chordal(self, certificate=False, algorithm="B"): else: return False - # Returning values # ---------------- @@ -14161,7 +14217,6 @@ def is_chordal(self, certificate=False, algorithm="B"): return (False, hole) - # 2- The graph is chordal if certificate: return True, peo @@ -14253,9 +14308,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 +14323,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 +14424,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 +14690,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 +14931,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 +14997,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 +15190,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 +15215,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 +15238,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 +15359,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 +15701,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 +15786,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 +15808,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 +15898,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 +16347,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 +16769,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 +16784,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 +16977,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 +17199,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 +17443,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 +17467,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 +17705,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 +17787,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 +18138,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 +18643,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 +18664,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 +18820,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 +18833,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 +18978,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 +18992,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 +19172,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 +19273,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 +19343,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 +19465,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 +19477,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 +19613,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 +19628,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 +20069,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 +20169,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 +20487,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 +20685,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.py b/src/sage/graphs/graph.py index af93c60a7a2..3bd3983579e 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -440,7 +440,7 @@ class Graph(GenericGraph): pre-defined graphs, see the :mod:`~sage.graphs.graph_generators` module. A :class:`Graph` object has many methods whose list can be obtained by - typing ``g.`` (i.e. hit the 'tab' key) or by reading the documentation + typing ``g.`` (i.e. hit the :kbd:`Tab` key) or by reading the documentation of :mod:`~sage.graphs.graph`, :mod:`~sage.graphs.generic_graph`, and :mod:`~sage.graphs.digraph`. diff --git a/src/sage/graphs/graph_database.py b/src/sage/graphs/graph_database.py index f416d7c04ee..a875f00396d 100644 --- a/src/sage/graphs/graph_database.py +++ b/src/sage/graphs/graph_database.py @@ -967,7 +967,8 @@ def query(self, query_dict=None, display_cols=None, **kwds): """ Create a GraphQuery on this database. - For full class details, type ``GraphQuery?`` and press ``shift+enter``. + For full class details, type ``GraphQuery?`` + and press :kbd:`Shift` + :kbd:`Enter`. EXAMPLES:: diff --git a/src/sage/graphs/graph_decompositions/modular_decomposition.py b/src/sage/graphs/graph_decompositions/modular_decomposition.py index 9aef9721fc8..0c1ae4da5b3 100644 --- a/src/sage/graphs/graph_decompositions/modular_decomposition.py +++ b/src/sage/graphs/graph_decompositions/modular_decomposition.py @@ -1278,7 +1278,7 @@ def permute_decomposition(trials, algorithm, vertices, prob, verbose=False): t1p = relabel_tree(t1, random_perm) assert(equivalent_trees(t1p, t2)) if verbose: - print("Passses!") + print("Passes!") def random_md_tree(max_depth, max_fan_out, leaf_probability): diff --git a/src/sage/graphs/graph_generators.py b/src/sage/graphs/graph_generators.py index 9a8c0877d3d..df88bbe2713 100644 --- a/src/sage/graphs/graph_generators.py +++ b/src/sage/graphs/graph_generators.py @@ -13,7 +13,7 @@ sage: h = graphs.HouseGraph() More interestingly, one can get the list of all graphs that Sage knows how to -build by typing ``graphs.`` in Sage and then hitting tab. +build by typing ``graphs.`` in Sage and then hitting :kbd:`Tab`. """ import subprocess @@ -484,7 +484,7 @@ class GraphGenerators(): A list of all graphs and graph structures (other than isomorphism class representatives) in this database is available via tab completion. Type - "graphs." and then hit the tab key to see which graphs are available. + "graphs." and then hit the :kbd:`Tab` key to see which graphs are available. The docstrings include educational information about each named graph with the hopes that this class can be used as a reference. @@ -1014,8 +1014,10 @@ def nauty_genbg(self, options="", debug=False): The possible options, obtained as output of ``genbg --help``:: - n1 : the number of vertices in the first class - n2 : the number of vertices in the second class + n1 : the number of vertices in the first class. + We must have n1=1..24. + n2 : the number of vertices in the second class. + We must have n2=0..32 and n1+n2=1..32. mine:maxe : : a range for the number of edges :0 means ' or more' except in the case 0:0 res/mod : only generate subset res out of subsets 0..mod-1 @@ -1129,6 +1131,27 @@ def nauty_genbg(self, options="", debug=False): ['>E Usage: ...genbg [-c -ugs -vq -lzF] [-Z#] [-D#] [-A] [-d#|-d#:#] [-D#|-D#:#] n1 n2... sage: list(graphs.nauty_genbg("-c 1 2", debug=True)) ['>A ...genbg n=1+2 e=2:2 d=1:1 D=2:1 c\n', Bipartite graph on 3 vertices] + + We must have n1=1..24, n2=0..32 and n1+n2=1..32 (:trac:`34179`):: + + sage: next(graphs.nauty_genbg("25 1", debug=False)) + Traceback (most recent call last): + ... + ValueError: wrong format of parameter options + sage: next(graphs.nauty_genbg("25 1", debug=True)) + '>E ...genbg: must have n1=1..24, n1+n2=1..32... + sage: next(graphs.nauty_genbg("24 9", debug=True)) + '>E ...genbg: must have n1=1..24, n1+n2=1..32... + sage: next(graphs.nauty_genbg("1 31", debug=False)) + Bipartite graph on 32 vertices + sage: next(graphs.nauty_genbg("1 32", debug=True)) + '>E ...genbg: must have n1=1..24, n1+n2=1..32... + sage: next(graphs.nauty_genbg("0 32", debug=True)) + '>E ...genbg: must have n1=1..24, n1+n2=1..32... + sage: next(graphs.nauty_genbg("2 0", debug=False)) + Bipartite graph on 2 vertices + sage: next(graphs.nauty_genbg("2 -1", debug=True)) + '>E Usage: ...genbg [-c -ugs -vq -lzF] [-Z#] [-D#] [-A] [-d#|-d#:#] [-D#|-D#:#] n1 n2... """ import shlex from sage.features.nauty import NautyExecutable diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 9b571953fed..fe1de72dcc5 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. @@ -371,6 +371,8 @@ def from_oriented_incidence_matrix(G, M, loops=False, multiedges=False, weighted - ``loops``, ``multiedges``, ``weighted`` -- booleans (default: ``False``); whether to consider the graph as having loops, multiple edges, or weights + .. NOTE:: ``weighted`` is currently ignored. + EXAMPLES:: sage: from sage.graphs.graph_input import from_oriented_incidence_matrix @@ -426,8 +428,6 @@ def from_oriented_incidence_matrix(G, M, loops=False, multiedges=False, weighted positions.append(tuple(NZ)) else: positions.append((NZ[1], NZ[0])) - if weighted is None: - weighted = False if multiedges is None: total = len(positions) multiedges = len(set(positions)) < total 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/isgci.py b/src/sage/graphs/isgci.py index 2ea1adce781..147e2ba2778 100644 --- a/src/sage/graphs/isgci.py +++ b/src/sage/graphs/isgci.py @@ -869,6 +869,7 @@ def update_db(self): EXAMPLES:: sage: graph_classes.update_db() # optional - internet + Database downloaded """ self._download_db() 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/partial_cube.py b/src/sage/graphs/partial_cube.py index 0831df402e2..bce06dee677 100644 --- a/src/sage/graphs/partial_cube.py +++ b/src/sage/graphs/partial_cube.py @@ -166,7 +166,6 @@ def depth_first_traversal(G, start): sage: t = list(sage.graphs.partial_cube.depth_first_traversal(H, '00')) sage: len(t) 16 - """ neighbors = G.neighbor_out_iterator seen = set() @@ -286,7 +285,7 @@ def is_partial_cube(G, certificate=False): # Initial sanity check: are there few enough edges? # Needed so that we don't try to use union-find on a dense # graph and incur superquadratic runtimes. - if 1 << (2*G.size()//n) > n: + if 1 << (2 * G.size() // n) > n: return fail # Check for bipartiteness. @@ -399,13 +398,13 @@ def is_partial_cube(G, certificate=False): # Rest of data structure: point from states to list and list to states state_to_active_token = {v: -1 for v in g} - token_to_states = [[] for i in activeTokens] # (i.e. vertices on which each token acts) + token_to_states = [[] for _ in activeTokens] # (i.e. vertices on which each token acts) def scan(v): """ Find the next token that is effective for v. """ - a = next(i for i in range(state_to_active_token[v]+1, len(activeTokens)) + a = next(i for i in range(state_to_active_token[v] + 1, len(activeTokens)) if activeTokens[i] is not None and activeTokens[i] in action[v]) state_to_active_token[v] = a token_to_states[a].append(v) 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..8a33cc8c70e 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 @@ -213,7 +213,6 @@ def _normal_label(g, comb_emb, external_face): except Exception: raise RuntimeError('Contractible list is empty but graph still has %d vertices. (Expected 3.)' % g.order()) - break # going to contract v v_neighbors = Set(g.neighbors(v)) contracted.append((v, v_neighbors, 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/graphs/weakly_chordal.pyx b/src/sage/graphs/weakly_chordal.pyx index 45c692d8955..79e574fc4f5 100644 --- a/src/sage/graphs/weakly_chordal.pyx +++ b/src/sage/graphs/weakly_chordal.pyx @@ -53,7 +53,7 @@ cdef inline is_long_hole_free_process(g, short_digraph sd, bitset_t dense_graph, bint certificate, int a, int b, int c, int n): """ - This method is part of method `is_long_hole_free`. + This method is part of method ``is_long_hole_free``. EXAMPLES:: @@ -285,7 +285,7 @@ cdef inline is_long_antihole_free_process(g, short_digraph sd, bitset_t dense_gr bint certificate, int a, int b, int c, int n): """ - This method is part of method `is_long_antihole_free`. + This method is part of method ``is_long_antihole_free``. EXAMPLES:: diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index 8a6afa76bbb..215b516b464 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -646,9 +646,9 @@ def is_trivial(self): """ return self.elementary_divisors() == () - def __bool__(self): + def __bool__(self) -> bool: """ - Returns True if this group is nontrivial. + Return ``True`` if this group is nontrivial. EXAMPLES:: @@ -662,8 +662,6 @@ def __bool__(self): """ return not self.is_trivial() - - @cached_method def dual_group(self, names="X", base_ring=None): """ diff --git a/src/sage/groups/abelian_gps/dual_abelian_group_element.py b/src/sage/groups/abelian_gps/dual_abelian_group_element.py index aaabe107781..18fac135c94 100644 --- a/src/sage/groups/abelian_gps/dual_abelian_group_element.py +++ b/src/sage/groups/abelian_gps/dual_abelian_group_element.py @@ -41,7 +41,6 @@ - Volker Braun (2012-11) port to new Parent base. Use tuples for immutables. Default to cyclotomic base ring. """ - # **************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2006 David Joyner @@ -53,62 +52,21 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - -import operator - from sage.arith.all import LCM -from sage.misc.misc_c import prod from sage.groups.abelian_gps.element_base import AbelianGroupElementBase -from functools import reduce -def add_strings(x, z=0): - """ - This was in sage.misc.misc but commented out. Needed to add - lists of strings in the word_problem method below. - - Return the sum of the elements of x. If x is empty, - return z. - - INPUT: - - - ``x`` -- iterable - - - ``z`` -- the ``0`` that will be returned if ``x`` is empty. - - OUTPUT: - - The sum of the elements of ``x``. - - EXAMPLES:: - - sage: from sage.groups.abelian_gps.dual_abelian_group_element import add_strings - sage: add_strings([], z='empty') - 'empty' - sage: add_strings(['a', 'b', 'c']) - 'abc' - """ - if len(x) == 0: - return z - if not isinstance(x, list): - m = iter(x) - y = next(m) - return reduce(operator.add, m, y) - else: - return reduce(operator.add, x[1:], x[0]) - - -def is_DualAbelianGroupElement(x): +def is_DualAbelianGroupElement(x) -> bool: """ Test whether ``x`` is a dual Abelian group element. INPUT: - - ``x`` -- anything. + - ``x`` -- anything OUTPUT: - Boolean. + Boolean EXAMPLES:: @@ -169,10 +127,10 @@ def __call__(self, g): N = LCM(order) order_not = [N / o for o in order] zeta = F.zeta(N) - return F.prod(zeta ** (expsX[i] * expsg[i] * order_not[i]) + return F.prod(zeta**(expsX[i] * expsg[i] * order_not[i]) for i in range(len(expsX))) - def word_problem(self, words, display=True): + def word_problem(self, words): """ This is a rather hackish method and is included for completeness. @@ -196,43 +154,21 @@ def word_problem(self, words, display=True): sage: w = a^7*b^3*c^5*d^4*e^4 sage: x = a^3*b^2*c^2*d^3*e^5 sage: y = a^2*b^4*c^2*d^4*e^5 - sage: e.word_problem([u,v,w,x,y],display=False) + sage: e.word_problem([u,v,w,x,y]) [[b^2*c^2*d^3*e^5, 245]] - - The command e.word_problem([u,v,w,x,y],display=True) returns - the same list but also prints ``e = (b^2*c^2*d^3*e^5)^245``. """ - ## First convert the problem to one using AbelianGroups - import copy - from sage.groups.abelian_gps.abelian_group import AbelianGroup - from sage.interfaces.gap import gap - M = self.parent() - G = M.group() - gens = M.variable_names() - g = prod([G.gen(i)**(self.list()[i]) for i in range(G.ngens())]) - gap.eval("l:=One(Rationals)") ## trick needed for LL line below to keep Sage from parsing - s1 = "gens := GeneratorsOfGroup(%s)"%G._gap_init_() - gap.eval(s1) - for i in range(len(gens)): - cmd = ("%s := gens["+str(i+1)+"]") % gens[i] - gap.eval(cmd) - s2 = "g0:=%s; gensH:=%s" % (str(g), words) - gap.eval(s2) - s3 = 'G:=Group(gens); H:=Group(gensH)' - gap.eval(s3) - phi = gap.eval("hom:=EpimorphismFromFreeGroup(H)") - l1 = gap.eval("ans:=PreImagesRepresentative(hom,g0)") - l2 = copy.copy(l1) - l4 = [] - l3 = l1.split("*") - for i in range(1,len(words)+1): - l2 = l2.replace("x"+str(i),"("+str(words[i-1])+")") - l3 = eval(gap.eval("L3:=ExtRepOfObj(ans)")) - nn = eval(gap.eval("n:=Int(Length(L3)/2)")) - LL1 = eval(gap.eval("L4:=List([l..n],i->L3[2*i])")) ## note the l not 1 - LL2 = eval(gap.eval("L5:=List([l..n],i->L3[2*i-1])")) ## note the l not 1 - if display: - s = str(g)+" = "+add_strings(["("+str(words[LL2[i]-1])+")^"+str(LL1[i])+"*" for i in range(nn)]) - m = len(s) - print(" ", s[:m-1], "\n") - return [[words[LL2[i]-1],LL1[i]] for i in range(nn)] + from sage.libs.gap.libgap import libgap + A = libgap.AbelianGroup(self.parent().gens_orders()) + gens = A.GeneratorsOfGroup() + gap_g = libgap.Product([gi**Li for gi, Li in zip(gens, self.list())]) + gensH = [libgap.Product([gi**Li for gi, Li in zip(gens, w.list())]) + for w in words] + H = libgap.Group(gensH) + + hom = H.EpimorphismFromFreeGroup() + ans = hom.PreImagesRepresentative(gap_g) + + resu = ans.ExtRepOfObj().sage() # (indice, power, indice, power, etc) + indices = resu[0::2] + powers = resu[1::2] + return [[words[indi - 1], powi] for indi, powi in zip(indices, powers)] diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 2cab0958526..fdc76c01e90 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -2199,7 +2199,7 @@ def reduced_word(self): .. TODO:: - Paralellize this function, calculating all summands in the sum + Parallelize this function, calculating all summands in the sum in parallel. """ M = self._algebra._indices @@ -2244,7 +2244,7 @@ def eps(self, N): .. TODO:: - Paralellize this function, calculating all summands in the sum + Parallelize this function, calculating all summands in the sum in parallel. """ def eps_monom(q_tuple): 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/finitely_presented.py b/src/sage/groups/finitely_presented.py index d7843b18976..50bf3975bf4 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -147,9 +147,9 @@ class GroupMorphismWithGensImages(SetMorphism): Class used for morphisms from finitely presented groups to other groups. It just adds the images of the generators at the end of the representation. - + EXAMPLES:: - + sage: F = FreeGroup(3) sage: G = F / [F([1, 2, 3, 1, 2, 3]), F([1, 1, 1])] sage: H = AlternatingGroup(3) @@ -167,9 +167,9 @@ class GroupMorphismWithGensImages(SetMorphism): def _repr_defn(self): r""" Return the part of the representation that includes the images of the generators. - + EXAMPLES:: - + sage: F = FreeGroup(3) sage: G = F / [F([1,2,3,1,2,3]),F([1,1,1])] sage: H = AlternatingGroup(3) @@ -1428,17 +1428,17 @@ def simplified(self): Finitely presented group < e0 | e0^2 > """ return self.simplification_isomorphism().codomain() - + def epimorphisms(self, H): r""" Return the epimorphisms from `self` to `H`, up to automorphism of `H`. - + INPUT: - + - `H` -- Another group - + EXAMPLES:: - + sage: F = FreeGroup(3) sage: G = F / [F([1, 2, 3, 1, 2, 3]), F([1, 1, 1])] sage: H = AlternatingGroup(3) @@ -1469,7 +1469,7 @@ def epimorphisms(self, H): x2 |--> (1,2,3)] ALGORITHM: - + Uses libgap's GQuotients function. """ from sage.misc.misc_c import prod diff --git a/src/sage/groups/finitely_presented_named.py b/src/sage/groups/finitely_presented_named.py index f1a6b223bfb..ef34854de8b 100644 --- a/src/sage/groups/finitely_presented_named.py +++ b/src/sage/groups/finitely_presented_named.py @@ -214,7 +214,7 @@ def FinitelyGeneratedHeisenbergPresentation(n=1, p=0): - ``p`` -- (optional) a prime number, where we construct the Heisenberg group over the finite field `\ZZ/p\ZZ` - + OUTPUT: Finitely generated Heisenberg group over the finite field @@ -249,7 +249,7 @@ def FinitelyGeneratedHeisenbergPresentation(n=1, p=0): [0 0 1] sage: p = 3 sage: Hp = groups.presentation.Heisenberg(p=3) - sage: Hp.order() == p**3 + sage: Hp.order() == p**3 True sage: Hnp = groups.presentation.Heisenberg(n=2, p=3) sage: len(Hnp.relations()) diff --git a/src/sage/groups/groups_catalog.py b/src/sage/groups/groups_catalog.py index 1bdd1a46346..e3da7f10780 100644 --- a/src/sage/groups/groups_catalog.py +++ b/src/sage/groups/groups_catalog.py @@ -5,7 +5,7 @@ Using tab-completion on this object is an easy way to discover and quickly create the groups that are available (as listed here). -Let ```` indicate pressing the tab key. So begin by typing +Let ```` indicate pressing the :kbd:`Tab` key. So begin by typing ``groups.`` to the see primary divisions, followed by (for example) ``groups.matrix.`` to access various groups implemented as sets of matrices. diff --git a/src/sage/groups/matrix_gps/group_element.pyx b/src/sage/groups/matrix_gps/group_element.pyx index e1bd8b15248..777b141beb0 100644 --- a/src/sage/groups/matrix_gps/group_element.pyx +++ b/src/sage/groups/matrix_gps/group_element.pyx @@ -823,4 +823,3 @@ def _unpickle_generic_element(G, mat): True """ return G.element_class(G, mat, False, False) - diff --git a/src/sage/groups/matrix_gps/symplectic.py b/src/sage/groups/matrix_gps/symplectic.py index 40c99099b5f..3715f531913 100644 --- a/src/sage/groups/matrix_gps/symplectic.py +++ b/src/sage/groups/matrix_gps/symplectic.py @@ -74,9 +74,9 @@ def Sp(n, R, var='a', invariant_form=None): - ``var`` -- (optional, default: ``'a'``) variable used to represent generator of the finite field, if needed - - ``invariant_form`` -- (optional) instances being accepted by + - ``invariant_form`` -- (optional) instances being accepted by the matrix-constructor which define a `n \times n` square matrix - over ``R`` describing the alternating form to be kept invariant + over ``R`` describing the alternating form to be kept invariant by the symplectic group EXAMPLES:: 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/all.py b/src/sage/groups/perm_gps/all.py index 999f0bbfb2c..83afad7c691 100644 --- a/src/sage/groups/perm_gps/all.py +++ b/src/sage/groups/perm_gps/all.py @@ -1,17 +1,20 @@ from .permgroup_named import (SymmetricGroup, AlternatingGroup, - DihedralGroup, SplitMetacyclicGroup, SemidihedralGroup, CyclicPermutationGroup, - DiCyclicGroup, TransitiveGroup, PGL, PSL, PSp,PSU,PGU, - MathieuGroup, KleinFourGroup, QuaternionGroup, - PrimitiveGroup, PrimitiveGroups, - SuzukiGroup, TransitiveGroups, GeneralDihedralGroup) + DihedralGroup, SplitMetacyclicGroup, + SemidihedralGroup, CyclicPermutationGroup, + DiCyclicGroup, TransitiveGroup, + PGL, PSL, PSp, PSU, PGU, + MathieuGroup, KleinFourGroup, QuaternionGroup, + PrimitiveGroup, PrimitiveGroups, + SuzukiGroup, TransitiveGroups, + GeneralDihedralGroup) -from .permgroup import PermutationGroup, PermutationGroup_generic, PermutationGroup_subgroup, direct_product_permgroups +from .permgroup import PermutationGroup, PermutationGroup_generic, PermutationGroup_subgroup, direct_product_permgroups from .constructor import PermutationGroupElement from .permgroup_morphism import (PermutationGroupMorphism as PermutationGroupMap, - PermutationGroupMorphism_im_gens, - PermutationGroupMorphism_id) + PermutationGroupMorphism_im_gens, + PermutationGroupMorphism_id) PermutationGroupMorphism = PermutationGroupMorphism_im_gens from .cubegroup import CubeGroup, RubiksCube diff --git a/src/sage/groups/perm_gps/constructor.py b/src/sage/groups/perm_gps/constructor.py index 1992679efd3..73dc5f94c41 100644 --- a/src/sage/groups/perm_gps/constructor.py +++ b/src/sage/groups/perm_gps/constructor.py @@ -7,7 +7,7 @@ objects have a more group theoretic flavor than the more combinatorial :class:`~sage.combinat.permutation.Permutation`. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 William Stein # Copyright (C) 2006 David Joyner # Copyright (C) 2019 Vincent Delecroix <20100.delecroix@gmail.com> @@ -16,16 +16,17 @@ # 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 . import permgroup_element from sage.misc.sage_eval import sage_eval from sage.misc.lazy_import import lazy_import from sage.interfaces.gap import GapElement -lazy_import('sage.combinat.permutation', ['Permutation', 'from_cycles']) from sage.libs.pari.all import pari_gen from sage.libs.gap.element import GapElement_Permutation +lazy_import('sage.combinat.permutation', ['Permutation', 'from_cycles']) + def PermutationGroupElement(g, parent=None, check=True): r""" @@ -118,6 +119,7 @@ def PermutationGroupElement(g, parent=None, check=True): return parent.element_class(g, parent, check) + def string_to_tuples(g): """ EXAMPLES:: @@ -136,10 +138,11 @@ def string_to_tuples(g): raise ValueError("g (= %s) must be a string" % g) elif g == '()': return [] - g = g.replace('\n','').replace(' ', '').replace(')(', '),(').replace(')', ',)') + g = g.replace('\n', '').replace(' ', '').replace(')(', '),(').replace(')', ',)') g = '[' + g + ']' return sage_eval(g, preparse=False) + def standardize_generator(g, convert_dict=None, as_cycles=False): r""" Standardize the input for permutation group elements to a list @@ -258,6 +261,6 @@ def standardize_generator(g, convert_dict=None, as_cycles=False): if convert_dict is not None and needs_conversion: g = [tuple([convert_dict[x] for x in cycle]) for cycle in g] if not as_cycles: - degree = max([1] + [max(cycle+(1,)) for cycle in g]) + degree = max([1] + [max(cycle + (1,)) for cycle in g]) g = from_cycles(degree, g) return g diff --git a/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx b/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx index eb3263d914d..ad30101e161 100644 --- a/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx +++ b/src/sage/groups/perm_gps/partn_ref/automorphism_group_canonical_label.pyx @@ -99,15 +99,15 @@ REFERENCE: """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 - 2011 Robert L. Miller # # 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 libc.string cimport memcmp, memcpy from cysignals.memory cimport sig_malloc, sig_realloc, sig_free @@ -134,24 +134,25 @@ cdef int compare_structures_trivial(int *gamma_1, int *gamma_2, void *S1, void * def test_get_aut_gp_and_can_lab_trivially(int n=6, list partition=[[0,1,2],[3,4],[5]], canonical_label=True, base=False): """ - sage: tttt = sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label.test_get_aut_gp_and_can_lab_trivially - sage: tttt() - 12 - sage: tttt(canonical_label=False, base=False) - 12 - sage: tttt(canonical_label=False, base=True) - 12 - sage: tttt(canonical_label=True, base=True) - 12 - sage: tttt(n=0, partition=[]) - 1 - sage: tttt(n=0, partition=[], canonical_label=False, base=False) - 1 - sage: tttt(n=0, partition=[], canonical_label=False, base=True) - 1 - sage: tttt(n=0, partition=[], canonical_label=True, base=True) - 1 + TESTS:: + sage: tttt = sage.groups.perm_gps.partn_ref.automorphism_group_canonical_label.test_get_aut_gp_and_can_lab_trivially + sage: tttt() + 12 + sage: tttt(canonical_label=False, base=False) + 12 + sage: tttt(canonical_label=False, base=True) + 12 + sage: tttt(canonical_label=True, base=True) + 12 + sage: tttt(n=0, partition=[]) + 1 + sage: tttt(n=0, partition=[], canonical_label=False, base=False) + 1 + sage: tttt(n=0, partition=[], canonical_label=False, base=True) + 1 + sage: tttt(n=0, partition=[], canonical_label=True, base=True) + 1 """ cdef aut_gp_and_can_lab *output cdef Integer I = Integer(0) @@ -894,17 +895,3 @@ cdef aut_gp_and_can_lab *get_aut_gp_and_can_lab(void *S, deallocate_agcl_work_space(work_space) return output - - - - - - - - - - - - - - diff --git a/src/sage/groups/perm_gps/partn_ref/double_coset.pyx b/src/sage/groups/perm_gps/partn_ref/double_coset.pyx index 6daef964ebc..3f726879292 100644 --- a/src/sage/groups/perm_gps/partn_ref/double_coset.pyx +++ b/src/sage/groups/perm_gps/partn_ref/double_coset.pyx @@ -733,8 +733,3 @@ cdef int double_coset(void *S1, void *S2, PartitionStack *partition1, int *order if work_space_prealloc is NULL: deallocate_dc_work_space(work_space) return 1 if (possible and not unknown) else 0 - - - - - diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx index f13fccf891a..e18fdf5f41a 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_binary.pyx @@ -1148,5 +1148,3 @@ def random_tests(num=50, n_max=50, k_max=6, nwords_max=200, perms_per_code=10, d num_codes += 2 print("All passed: %d random tests on %d codes." % (num_tests, num_codes)) - - diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx index 4ab08bd6ba7..1acb46201a0 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_graphs.pyx @@ -7,10 +7,9 @@ EXAMPLES:: REFERENCE: -- [1] McKay, Brendan D. Practical Graph Isomorphism. Congressus Numerantium, +- [1] McKay, Brendan D. *Practical Graph Isomorphism*. Congressus Numerantium, Vol. 30 (1981), pp. 45-87. """ - # **************************************************************************** # Copyright (C) 2006 - 2011 Robert L. Miller # @@ -643,9 +642,8 @@ cdef int compare_graphs(int *gamma_1, int *gamma_2, void *S1, void *S2, int degr r""" Compare gamma_1(S1) and gamma_2(S2). - Return return -1 if gamma_1(S1) < gamma_2(S2), 0 if gamma_1(S1) == - gamma_2(S2), 1 if gamma_1(S1) > gamma_2(S2). (Just like the python - \code{cmp}) function. + Return -1 if gamma_1(S1) < gamma_2(S2), 0 if gamma_1(S1) == + gamma_2(S2), 1 if gamma_1(S1) > gamma_2(S2). INPUT: diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx index 815b3bcc89d..a24b0499888 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_python.pyx @@ -582,6 +582,3 @@ def double_coset_python(S1, S2, partition1, ordering2, n, output_py = False sig_free(output) return output_py - - - diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx b/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx index 6e80294db3c..912c9a31a0d 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx +++ b/src/sage/groups/perm_gps/partn_ref/refinement_sets.pyx @@ -854,9 +854,3 @@ def sets_modulo_perm_group(list generators, int max_size, else: out_list.append(MemoryError()) return out_list - - - - - - 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_morphism.py b/src/sage/groups/perm_gps/permgroup_morphism.py index d190df81614..917ddd01865 100644 --- a/src/sage/groups/perm_gps/permgroup_morphism.py +++ b/src/sage/groups/perm_gps/permgroup_morphism.py @@ -30,24 +30,26 @@ Cyclic group of order 4 as a permutation group """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 David Joyner and William Stein # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.categories.morphism import Morphism from sage.groups.perm_gps.permgroup import PermutationGroup, PermutationGroup_generic + class PermutationGroupMorphism(Morphism): """ A set-theoretic map between PermutationGroups. """ def _repr_type(self): """ - Returns the type of this morphism. This is used for printing - the morphism. + Return the type of this morphism. + + This is used for printing the morphism. EXAMPLES:: @@ -60,7 +62,7 @@ def _repr_type(self): def kernel(self): """ - Returns the kernel of this homomorphism as a permutation group. + Return the kernel of this homomorphism as a permutation group. EXAMPLES:: @@ -134,7 +136,7 @@ def image(self, J): def __call__(self, g): """ Some python code for wrapping GAP's Images function but only for - permutation groups. Returns an error if g is not in G. + permutation groups. This returns an error if g is not in G. EXAMPLES:: @@ -148,9 +150,11 @@ def __call__(self, g): """ return self.image(g) + class PermutationGroupMorphism_id(PermutationGroupMorphism): pass + class PermutationGroupMorphism_from_gap(PermutationGroupMorphism): def __init__(self, G, H, gap_hom): """ @@ -201,7 +205,7 @@ def _repr_defn(self): def _gap_(self, gap=None): """ - Returns a GAP version of this morphism. + Return a GAP version of this morphism. EXAMPLES:: @@ -217,7 +221,7 @@ def _gap_(self, gap=None): def __call__(self, g): """ Some python code for wrapping GAP's Images function but only for - permutation groups. Returns an error if g is not in G. + permutation groups. This returns an error if g is not in G. EXAMPLES:: @@ -236,7 +240,7 @@ def __init__(self, G, H, gens=None): """ Some python code for wrapping GAP's GroupHomomorphismByImages function but only for permutation groups. Can be expensive if G is - large. Returns "fail" if gens does not generate self or if the map + large. This returns "fail" if gens does not generate self or if the map does not extend to a group homomorphism, self - other. EXAMPLES:: @@ -270,8 +274,9 @@ def __init__(self, G, H, gens=None): def _repr_defn(self): """ - Returns the definition of this morphism. This is used when - printing the morphism. + Return the definition of this morphism. + + This is used when printing the morphism. EXAMPLES:: @@ -281,11 +286,11 @@ def _repr_defn(self): sage: phi._repr_defn() '[(1,2,3,4)] -> [(1,2,3,4)]' """ - return "%s -> %s"%(list(self.domain().gens()), self._images) + return "%s -> %s" % (list(self.domain().gens()), self._images) def _gap_(self): """ - Returns a GAP representation of this morphism. + Return a GAP representation of this morphism. EXAMPLES:: @@ -298,9 +303,10 @@ def _gap_(self): """ return self.domain()._gap_().GroupHomomorphismByImages(self.codomain(), self.domain().gens(), self._images) -def is_PermutationGroupMorphism(f): + +def is_PermutationGroupMorphism(f) -> bool: """ - Returns True if the argument ``f`` is a PermutationGroupMorphism. + Return True if the argument ``f`` is a PermutationGroupMorphism. EXAMPLES:: 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/perm_gps/permutation_groups_catalog.py b/src/sage/groups/perm_gps/permutation_groups_catalog.py index ae3a0ebf33a..52f99920307 100644 --- a/src/sage/groups/perm_gps/permutation_groups_catalog.py +++ b/src/sage/groups/perm_gps/permutation_groups_catalog.py @@ -26,6 +26,6 @@ from .permgroup_named import JankoGroup as Janko from .permgroup_named import SuzukiSporadicGroup as SuzukiSporadic from .permgroup_named import SuzukiGroup as Suzuki -from .permgroup_named import (PGL, PSL, PSp,PSU,PGU,) +from .permgroup_named import (PGL, PSL, PSp, PSU, PGU) from .permgroup_named import TransitiveGroup as Transitive from .cubegroup import CubeGroup as RubiksCube diff --git a/src/sage/groups/perm_gps/symgp_conjugacy_class.py b/src/sage/groups/perm_gps/symgp_conjugacy_class.py index b338d616b70..d6112df67af 100644 --- a/src/sage/groups/perm_gps/symgp_conjugacy_class.py +++ b/src/sage/groups/perm_gps/symgp_conjugacy_class.py @@ -48,7 +48,7 @@ def _repr_(self): Conjugacy class of cycle type [4] in Symmetric group of order 4! as a permutation group """ - return "Conjugacy class of cycle type %s in %s"%(self._part, self._parent) + return "Conjugacy class of cycle type %s in %s" % (self._part, self._parent) def __eq__(self, other): r""" @@ -167,9 +167,10 @@ def set(self): """ if not self._set: self._set = Set(self._parent.element_class(x, self._parent, check=False) - for x in conjugacy_class_iterator(self._part, self._domain) ) + for x in conjugacy_class_iterator(self._part, self._domain)) return self._set + class PermutationsConjugacyClass(SymmetricGroupConjugacyClassMixin, ConjugacyClass): """ A conjugacy class of the permutations of `n`. @@ -197,7 +198,7 @@ def __init__(self, P, part): part = elt.cycle_type() else: elt = P.element_in_conjugacy_classes(part) - SymmetricGroupConjugacyClassMixin.__init__(self, range(1, P.n+1), part) + SymmetricGroupConjugacyClassMixin.__init__(self, range(1, P.n + 1), part) ConjugacyClass.__init__(self, P, elt) def __iter__(self): @@ -241,11 +242,12 @@ def set(self): """ if not self._set: self._set = Set(from_cycles(self._parent.n, x, self._parent) - for x in conjugacy_class_iterator(self._part, self._domain) ) + for x in conjugacy_class_iterator(self._part, self._domain)) return self._set + ##################################################################### -## Helper functions +# Helper functions def default_representative(part, G): r""" @@ -284,7 +286,7 @@ def default_representative(part, G): total = 0 cycles = [] for p in part: - cycles.append(tuple(D[total:total+p])) + cycles.append(tuple(D[total:total + p])) total += p return G.element_class(cycles, G, check=False) diff --git a/src/sage/groups/raag.py b/src/sage/groups/raag.py index 59b78c6d757..736430e8af2 100644 --- a/src/sage/groups/raag.py +++ b/src/sage/groups/raag.py @@ -656,7 +656,7 @@ def __init__(self, R, A): if R not in Fields(): raise NotImplementedError("only implemented with coefficients in a field") self._group = A - + names = tuple(['e' + name[1:] for name in A.variable_names()]) from sage.graphs.independent_sets import IndependentSets from sage.sets.finite_enumerated_set import FiniteEnumeratedSet @@ -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/chain_complex_morphism.py b/src/sage/homology/chain_complex_morphism.py index a29ccaae1a7..b049b534e0b 100644 --- a/src/sage/homology/chain_complex_morphism.py +++ b/src/sage/homology/chain_complex_morphism.py @@ -140,7 +140,7 @@ def __init__(self, matrices, C, D, check=True): d = C.degree_of_differential() if d != D.degree_of_differential(): raise ValueError('degree of differential does not match') - + degrees = list(C.differential()) + list(D.differential()) degrees = sorted(set(degrees)) initial_matrices = dict(matrices) diff --git a/src/sage/homology/chain_homotopy.py b/src/sage/homology/chain_homotopy.py index 16a1c385edc..afeaee2430c 100644 --- a/src/sage/homology/chain_homotopy.py +++ b/src/sage/homology/chain_homotopy.py @@ -269,7 +269,7 @@ def is_homology_gradient_vector_field(self): if matrices[i] * self.domain().differential(i-deg) * matrices[i] != matrices[i]: return False return True - + def in_degree(self, n): """ The matrix representing this chain homotopy in degree ``n``. 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/homology/hochschild_complex.py b/src/sage/homology/hochschild_complex.py index ef68448c685..f372a08e0e8 100644 --- a/src/sage/homology/hochschild_complex.py +++ b/src/sage/homology/hochschild_complex.py @@ -669,7 +669,7 @@ def arrow_art(d): def _add_(self, other): """ Module addition - + EXAMPLES:: sage: F. = FreeAlgebra(ZZ) diff --git a/src/sage/homology/simplicial_complex_morphism.py b/src/sage/homology/simplicial_complex_morphism.py index 4673be7d414..889c266dc0a 100644 --- a/src/sage/homology/simplicial_complex_morphism.py +++ b/src/sage/homology/simplicial_complex_morphism.py @@ -3,11 +3,10 @@ The current version is :mod:`sage.topology.simplicial_complex_morphism`. """ - from sage.misc.superseded import deprecated_function_alias import sage.topology.simplicial_complex_morphism -is_SimplicialComplexMorphism = deprecated_function_alias(31925, +is_SimplicialComplexMorphism = deprecated_function_alias(31925, sage.topology.simplicial_complex_morphism.is_SimplicialComplexMorphism) SimplicialComplexMorphism = deprecated_function_alias(31925, sage.topology.simplicial_complex_morphism.SimplicialComplexMorphism) diff --git a/src/sage/homology/simplicial_set_examples.py b/src/sage/homology/simplicial_set_examples.py index 8a19cef5a86..8945e2b51de 100644 --- a/src/sage/homology/simplicial_set_examples.py +++ b/src/sage/homology/simplicial_set_examples.py @@ -4,7 +4,6 @@ The current version is :mod:`sage.topology.simplicial_set_examples`. """ - from sage.misc.superseded import deprecated_function_alias import sage.topology.simplicial_set_examples @@ -22,4 +21,3 @@ 'simplicial_data_from_kenzo_output', 'HopfMap']: exec('{} = deprecated_function_alias(31925, sage.topology.simplicial_set_examples.{})'.format(f, f)) - diff --git a/src/sage/interacts/library.py b/src/sage/interacts/library.py index ea860a052c6..41dc97cd074 100644 --- a/src/sage/interacts/library.py +++ b/src/sage/interacts/library.py @@ -12,7 +12,7 @@ HTML and Sage code which creates the mathlet:: sage: interacts.calculus.taylor_polynomial() - Interactive function with 3 widgets + ...Interactive function with 3 widgets title: HTMLText(value='

Taylor polynomial

') f: EvalText(value='e^(-x)*sin(x)', description='$f(x)=$', layout=Layout(max_width='81em')) order: SelectionSlider(description='order', options=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), value=1) @@ -103,7 +103,7 @@ def library_interact( ....: def f(n): ....: print(n) sage: f() # an interact appears if using the notebook, else code - Interactive function with 1 widget + ...Interactive function with 1 widget n: TransformIntSlider(value=5, description='n', max=15, min=-5) TESTS: @@ -119,7 +119,7 @@ def library_interact( DeprecationWarning: Use decorator factory @library_interact(widgets) instead of @library_interact without any arguments. See https://trac.sagemath.org/33382 for details. sage: f() # an interact appears if using the notebook, else code - Interactive function with 1 widget + ...Interactive function with 1 widget n: TransformIntSlider(value=5, description='n', max=15, min=-5) .. NOTE:: @@ -185,7 +185,7 @@ def demo(n: int, m: int): creates the mathlet:: sage: interacts.demo() - Interactive function with 2 widgets + ...Interactive function with 2 widgets n: SelectionSlider(description='n', options=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), value=0) m: SelectionSlider(description='m', options=(0, 1, 2, 3, 4, 5, 6, 7, 8, 9), value=0) """ @@ -215,7 +215,7 @@ def taylor_polynomial(title, f, order: int): creates the mathlet:: sage: interacts.calculus.taylor_polynomial() - Interactive function with 3 widgets + ...Interactive function with 3 widgets title: HTMLText(value='

Taylor polynomial

') f: EvalText(value='e^(-x)*sin(x)', description='$f(x)=$', layout=Layout(max_width='81em')) order: SelectionSlider(description='order', options=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), value=1) @@ -261,7 +261,7 @@ def definite_integral(title, f, g, interval, x_range, selection): creates the mathlet:: sage: interacts.calculus.definite_integral() - Interactive function with 6 widgets + ...Interactive function with 6 widgets title: HTMLText(value='

Definite integral

') f: EvalText(value='3*x', description='$f(x)=$', layout=Layout(max_width='81em')) g: EvalText(value='x^2', description='$g(x)=$', layout=Layout(max_width='81em')) @@ -347,7 +347,7 @@ def function_derivative(title, function, x_range, y_range): creates the mathlet:: sage: interacts.calculus.function_derivative() - Interactive function with 4 widgets + ...Interactive function with 4 widgets title: HTMLText(value='

Derivative grapher

') function: EvalText(value='x^5-3*x^3+1', description='Function:', layout=Layout(max_width='81em')) x_range: FloatRangeSlider(value=(-2.0, 2.0), description='Range (x)', max=15.0, min=-15.0) @@ -395,7 +395,7 @@ def difference_quotient(title, f, interval, a, x0): creates the mathlet:: sage: interacts.calculus.difference_quotient() - Interactive function with 5 widgets + ...Interactive function with 5 widgets title: HTMLText(value='

Difference quotient

') f: EvalText(value='sin(x)', description='f(x)', layout=Layout(max_width='81em')) interval: FloatRangeSlider(value=(0.0, 10.0), description='Range', max=10.0) @@ -460,7 +460,7 @@ def quadratic_equation(A, B, C): creates the mathlet:: sage: interacts.calculus.quadratic_equation() - Interactive function with 3 widgets + ...Interactive function with 3 widgets A: IntSlider(value=1, description='A', max=7, min=-7) B: IntSlider(value=1, description='B', max=7, min=-7) C: IntSlider(value=-2, description='C', max=7, min=-7) @@ -522,7 +522,7 @@ def trigonometric_properties_triangle(a0, a1, a2): creates the mathlet:: sage: interacts.geometry.trigonometric_properties_triangle() - Interactive function with 3 widgets + ...Interactive function with 3 widgets a0: IntSlider(value=30, description='A', max=360) a1: IntSlider(value=180, description='B', max=360) a2: IntSlider(value=300, description='C', max=360) @@ -603,7 +603,7 @@ def unit_circle(function, x): creates the mathlet:: sage: interacts.geometry.unit_circle() - Interactive function with 2 widgets + ...Interactive function with 2 widgets function: Dropdown(description='function', options=(('sin(x)', 0), ('cos(x)', 1), ('tan(x)', 2)), value=0) x: TransformFloatSlider(value=0.0, description='x', max=6.283185307179586, step=0.015707963267948967) """ @@ -704,7 +704,7 @@ def special_points( creates the mathlet:: sage: interacts.geometry.special_points() - Interactive function with 10 widgets + ...Interactive function with 10 widgets title: HTMLText(value='

Special points in triangle

') a0: IntSlider(value=30, description='A', max=360) a1: IntSlider(value=180, description='B', max=360) @@ -877,7 +877,7 @@ def coin(n, interval): creates the mathlet:: sage: interacts.statistics.coin() - Interactive function with 2 widgets + ...Interactive function with 2 widgets n: IntSlider(value=1000, description='Number of Tosses', max=10000, min=2, step=100) interval: IntRangeSlider(value=(0, 0), description='Plotting range (y)', max=1) """ @@ -917,7 +917,7 @@ def bisection_method(title, f, interval, d, maxn): creates the mathlet:: sage: interacts.calculus.secant_method() - Interactive function with 5 widgets + ...Interactive function with 5 widgets title: HTMLText(value='

Secant method for numerical root finding

') f: EvalText(value='x^2-2', description='f(x)', layout=Layout(max_width='81em')) interval: IntRangeSlider(value=(0, 4), description='range', max=5, min=-5) @@ -997,7 +997,7 @@ def secant_method(title, f, interval, d, maxn): creates the mathlet:: sage: interacts.calculus.secant_method() - Interactive function with 5 widgets + ...Interactive function with 5 widgets title: HTMLText(value='

Secant method for numerical root finding

') f: EvalText(value='x^2-2', description='f(x)', layout=Layout(max_width='81em')) interval: IntRangeSlider(value=(0, 4), description='range', max=5, min=-5) @@ -1070,7 +1070,7 @@ def newton_method(title, f, c, d, maxn, interval, list_steps): creates the mathlet:: sage: interacts.calculus.newton_method() - Interactive function with 7 widgets + ...Interactive function with 7 widgets title: HTMLText(value='

Newton method

') f: EvalText(value='x^2 - 2', description='f', layout=Layout(max_width='81em')) c: IntSlider(value=6, description='Start ($x$)', max=10, min=-10) @@ -1154,7 +1154,7 @@ def trapezoid_integration( creates the mathlet:: sage: interacts.calculus.trapezoid_integration() - Interactive function with 7 widgets + ...Interactive function with 7 widgets title: HTMLText(value='

Trapezoid integration

') f: EvalText(value='x^2-5*x + 10', description='$f(x)=$', layout=Layout(max_width='81em')) n: IntSlider(value=5, description='# divisions', min=1) @@ -1287,7 +1287,7 @@ def simpson_integration( creates the mathlet:: sage: interacts.calculus.simpson_integration() - Interactive function with 7 widgets + ...Interactive function with 7 widgets title: HTMLText(value='

Simpson integration

') f: EvalText(value='x*sin(x)+x+1', description='$f(x)=$', layout=Layout(max_width='81em')) n: IntSlider(value=6, description='# divisions', min=2, step=2) @@ -1551,7 +1551,7 @@ def function_tool(f, g, xrange, yrange, a, action, do_plot): creates the mathlet:: sage: interacts.calculus.function_tool() - Interactive function with 7 widgets + ...Interactive function with 7 widgets f: EvalText(value='sin(x)', description='f') g: EvalText(value='cos(x)', description='g') xrange: IntRangeSlider(value=(0, 1), description='x-range', max=3, min=-3) @@ -1681,7 +1681,7 @@ def julia(expo, c_real, c_imag, iterations, zoom_x, zoom_y, plot_points, dpi): creates the mathlet:: sage: interacts.fractals.julia() - Interactive function with 8 widgets + ...Interactive function with 8 widgets expo: FloatSlider(value=2.0, description='expo', max=10.0, min=-10.0) c_real: FloatSlider(value=0.5, description='real part const.', max=2.0, min=-2.0, step=0.01) c_imag: FloatSlider(value=0.5, description='imag part const.', max=2.0, min=-2.0, step=0.01) @@ -1733,7 +1733,7 @@ def mandelbrot(expo, iterations, zoom_x, zoom_y, plot_points, dpi): creates the mathlet:: sage: interacts.fractals.mandelbrot() - Interactive function with 6 widgets + ...Interactive function with 6 widgets expo: FloatSlider(value=2.0, description='expo', max=10.0, min=-10.0) iterations: IntSlider(value=20, description='# iterations', min=1) zoom_x: FloatRangeSlider(value=(-2.0, 1.0), description='Zoom X', max=2.0, min=-2.0, step=0.01) @@ -1778,7 +1778,7 @@ def cellular_automaton(N, rule_number, size): creates the mathlet:: sage: interacts.fractals.cellular_automaton() - Interactive function with 3 widgets + ...Interactive function with 3 widgets N: IntSlider(value=100, description='Number of iterations', max=500, min=1) rule_number: IntSlider(value=110, description='Rule number', max=255) size: IntSlider(value=6, description='size of graphic', max=11, min=1) @@ -1837,7 +1837,7 @@ def polar_prime_spiral(interval, show_factors, highlight_primes, show_curves, n, creates the mathlet:: sage: sage.interacts.algebra.polar_prime_spiral() - Interactive function with 6 widgets + ...Interactive function with 6 widgets interval: IntRangeSlider(value=(1, 1000), description='range', max=4000, min=1, step=10) show_factors: Checkbox(value=True, description='show_factors') highlight_primes: Checkbox(value=True, description='highlight_primes') diff --git a/src/sage/interacts/test_jupyter.rst b/src/sage/interacts/test_jupyter.rst index 0228ea227c1..3335a7423c3 100644 --- a/src/sage/interacts/test_jupyter.rst +++ b/src/sage/interacts/test_jupyter.rst @@ -40,7 +40,7 @@ This is just to test that failures in the interact are actually seen:: Test all interacts from the Sage interact library:: sage: test(interacts.algebra.polar_prime_spiral) # long time - Interactive function with 6 widgets + ...Interactive function with 6 widgets interval: IntRangeSlider(value=(1, 1000), description='range', max=4000, min=1, step=10) show_factors: Checkbox(value=True, description='show_factors') highlight_primes: Checkbox(value=True, description='highlight_primes') @@ -53,7 +53,7 @@ Test all interacts from the Sage interact library:: Green Curve: \(n^2 + n + -1\) sage: test(interacts.calculus.taylor_polynomial) - Interactive function with 3 widgets + ...Interactive function with 3 widgets title: HTMLText(value='

Taylor polynomial

') f: EvalText(value='e^(-x)*sin(x)', description='$f(x)=$', layout=Layout(max_width='81em')) order: SelectionSlider(description='order', options=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), value=1) @@ -61,7 +61,7 @@ Test all interacts from the Sage interact library:: \(\hat{f}(x;0)\;=\;x+\mathcal{O}(x^{2})\) sage: test(interacts.calculus.definite_integral) - Interactive function with 6 widgets + ...Interactive function with 6 widgets title: HTMLText(value='

Definite integral

') f: EvalText(value='3*x', description='$f(x)=$', layout=Layout(max_width='81em')) g: EvalText(value='x^2', description='$g(x)=$', layout=Layout(max_width='81em')) @@ -71,7 +71,7 @@ Test all interacts from the Sage interact library:: \(\int_{0.00}^{3.00}(\color{Blue}{f(x)})\,\mathrm{d}x=\int_{0.00}^{3.00}(3 \, x)\,\mathrm{d}x=13.50\)
\(\int_{0.00}^{3.00}(\color{Green}{g(x)})\,\mathrm{d}x=\int_{0.00}^{3.00}(x^{2})\,\mathrm{d}x=9.00\) sage: test(interacts.calculus.function_derivative) - Interactive function with 4 widgets + ...Interactive function with 4 widgets title: HTMLText(value='

Derivative grapher

') function: EvalText(value='x^5-3*x^3+1', description='Function:', layout=Layout(max_width='81em')) x_range: FloatRangeSlider(value=(-2.0, 2.0), description='Range (x)', max=15.0, min=-15.0) @@ -81,7 +81,7 @@ Test all interacts from the Sage interact library::
\(\color{Red}{f''(x) = 20 \, x^{3} - 18 \, x}\)
sage: test(interacts.calculus.difference_quotient) - Interactive function with 5 widgets + ...Interactive function with 5 widgets title: HTMLText(value='

Difference quotient

') f: EvalText(value='sin(x)', description='f(x)', layout=Layout(max_width='81em')) interval: FloatRangeSlider(value=(0.0, 10.0), description='Range', max=10.0) @@ -96,7 +96,7 @@ Test all interacts from the Sage interact library:: \(k = \frac{f(x_0)-f(a)}{x_0-a} = -0.62274\)
sage: test(interacts.calculus.quadratic_equation) - Interactive function with 3 widgets + ...Interactive function with 3 widgets A: IntSlider(value=1, description='A', max=7, min=-7) B: IntSlider(value=1, description='B', max=7, min=-7) C: IntSlider(value=-2, description='C', max=7, min=-7) @@ -106,7 +106,7 @@ Test all interacts from the Sage interact library:: \(x = \frac{-B\pm\sqrt{B^2-4AC}}{2A} = \frac{-1\pm\sqrt{1^2-4*1*-2}}{2*1} = \frac{-1\pm\sqrt{\color{Green}{9}}}{2} = \begin{cases}1\\-2\end{cases}\) sage: test(interacts.calculus.secant_method) - Interactive function with 5 widgets + ...Interactive function with 5 widgets title: HTMLText(value='

Secant method for numerical root finding

') f: EvalText(value='x^2-2', description='f(x)', layout=Layout(max_width='81em')) interval: IntRangeSlider(value=(0, 4), description='range', max=5, min=-5) @@ -118,7 +118,7 @@ Test all interacts from the Sage interact library:: \(6 \text{ iterations}\) sage: test(interacts.calculus.newton_method) - Interactive function with 7 widgets + ...Interactive function with 7 widgets title: HTMLText(value='

Newton method

') f: EvalText(value='x^2 - 2', description='f', layout=Layout(max_width='81em')) c: IntSlider(value=6, description='Start ($x$)', max=10, min=-10) @@ -132,7 +132,7 @@ Test all interacts from the Sage interact library:: \(6 \text{ iterations}\) sage: test(interacts.calculus.trapezoid_integration) - Interactive function with 7 widgets + ...Interactive function with 7 widgets title: HTMLText(value='

Trapezoid integration

') f: EvalText(value='x^2-5*x + 10', description='$f(x)=$', layout=Layout(max_width='81em')) n: IntSlider(value=5, description='# divisions', min=1) @@ -155,7 +155,7 @@ Test all interacts from the Sage interact library:: sage: test(interacts.calculus.simpson_integration) - Interactive function with 7 widgets + ...Interactive function with 7 widgets title: HTMLText(value='

Simpson integration

') f: EvalText(value='x*sin(x)+x+1', description='$f(x)=$', layout=Layout(max_width='81em')) n: IntSlider(value=6, description='# divisions', min=2, step=2) @@ -178,7 +178,7 @@ Test all interacts from the Sage interact library:: sage: test(interacts.calculus.bisection_method) - Interactive function with 5 widgets + ...Interactive function with 5 widgets title: HTMLText(value='

Bisection method

') f: EvalText(value='x^2-2', description='f(x)', layout=Layout(max_width='81em')) interval: IntRangeSlider(value=(0, 4), description='range', max=5, min=-5) @@ -190,7 +190,7 @@ Test all interacts from the Sage interact library:: \(9 \text{ iterations}\) sage: test(interacts.calculus.riemann_sum) - Manual interactive function with 9 widgets + ...Manual interactive function with 9 widgets title: HTMLText(value='

Riemann integral with random sampling

') f: EvalText(value='x^2+1', description='$f(x)=$', layout=Layout(max_width='41em')) n: IntSlider(value=5, description='# divisions', max=30, min=1) @@ -206,7 +206,7 @@ Test all interacts from the Sage interact library:: 1\,\mathrm{d}x=4.666666666666668\) sage: test(interacts.calculus.function_tool) - Interactive function with 7 widgets + ...Interactive function with 7 widgets f: EvalText(value='sin(x)', description='f') g: EvalText(value='cos(x)', description='g') xrange: IntRangeSlider(value=(0, 1), description='x-range', max=3, min=-3) @@ -219,7 +219,7 @@ Test all interacts from the Sage interact library::
\(h = f = \sin\left(x\right)\)
sage: test(interacts.fractals.mandelbrot) - Interactive function with 6 widgets + ...Interactive function with 6 widgets expo: FloatSlider(value=2.0, description='expo', max=10.0, min=-10.0) iterations: IntSlider(value=20, description='# iterations', min=1) zoom_x: FloatRangeSlider(value=(-2.0, 1.0), description='Zoom X', max=2.0, min=-2.0, step=0.01) @@ -230,7 +230,7 @@ Test all interacts from the Sage interact library:: Recursive Formula: \(z \leftarrow z^{2.00} + c\) for \(c \in \mathbb{C}\) sage: test(interacts.fractals.julia) - Interactive function with 8 widgets + ...Interactive function with 8 widgets expo: FloatSlider(value=2.0, description='expo', max=10.0, min=-10.0) c_real: FloatSlider(value=0.5, description='real part const.', max=2.0, min=-2.0, step=0.01) c_imag: FloatSlider(value=0.5, description='imag part const.', max=2.0, min=-2.0, step=0.01) @@ -243,20 +243,20 @@ Test all interacts from the Sage interact library:: Recursive Formula: \(z \leftarrow z^{2.00} + (0.50+0.50*\mathbb{I})\) sage: test(interacts.fractals.cellular_automaton) - Interactive function with 3 widgets + ...Interactive function with 3 widgets N: IntSlider(value=100, description='Number of iterations', max=500, min=1) rule_number: IntSlider(value=110, description='Rule number', max=255) size: IntSlider(value=6, description='size of graphic', max=11, min=1)

Cellular Automaton

Rule 110 expands to 01110110
sage: test(interacts.geometry.unit_circle) - Interactive function with 2 widgets + ...Interactive function with 2 widgets function: Dropdown(description='function', options=(('sin(x)', 0), ('cos(x)', 1), ('tan(x)', 2)), value=0) x: TransformFloatSlider(value=0.0, description='x', max=6.283185307179586, step=0.015707963267948967)
Lines of the same color have the same length
sage: test(interacts.geometry.trigonometric_properties_triangle) - Interactive function with 3 widgets + ...Interactive function with 3 widgets a0: IntSlider(value=30, description='A', max=360) a1: IntSlider(value=180, description='B', max=360) a2: IntSlider(value=300, description='C', max=360) @@ -266,7 +266,7 @@ Test all interacts from the Sage interact library:: Area of triangle \(ABC = 1.183013\) sage: test(interacts.geometry.special_points) - Interactive function with 10 widgets + ...Interactive function with 10 widgets title: HTMLText(value='

Special points in triangle

') a0: IntSlider(value=30, description='A', max=360) a1: IntSlider(value=180, description='B', max=360) @@ -279,10 +279,9 @@ Test all interacts from the Sage interact library:: show_euler: Checkbox(value=False, description="Euler's Line") sage: test(interacts.statistics.coin) - Interactive function with 2 widgets + ...Interactive function with 2 widgets n: IntSlider(value=1000, description='Number of Tosses', max=10000, min=2, step=100) interval: IntRangeSlider(value=(0, 0), description='Plotting range (y)', max=1) - doctest:...: UserWarning: Attempting to set identical bottom == top == 0.0 results in singular transformations; automatically expanding. Test matrix control (see :trac:`27735`):: @@ -291,7 +290,7 @@ Test matrix control (see :trac:`27735`):: ....: print(A) ....: print(parent(A)) sage: test(matrix_test) - Interactive function with 1 widget + ...Interactive function with 1 widget A: Grid(value=[[0, 1], [2, 3]], children=(Label(value='A'), VBox(children=(EvalText(value='0', layout=Layout(max_width='5em')), EvalText(value='2', layout=Layout(max_width='5em')))), VBox(children=(EvalText(value='1', layout=Layout(max_width='5em')), EvalText(value='3', layout=Layout(max_width='5em')))))) [0 1] [2 3] diff --git a/src/sage/interfaces/giac.py b/src/sage/interfaces/giac.py index 87ff828edec..98381afeea3 100644 --- a/src/sage/interfaces/giac.py +++ b/src/sage/interfaces/giac.py @@ -133,7 +133,7 @@ Another important feature of giac is its online help. We can access this through sage as well. After reading the description of -the command, you can press q to immediately get back to your +the command, you can press :kbd:`q` to immediately get back to your original prompt. Incidentally you can always get into a giac console by the diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index 47ccd0cdbff..7e612f049f2 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -173,7 +173,9 @@ def set_seed(self, seed=None): def interact(self): r""" This allows you to interactively interact with the child - interpreter. Press Ctrl-D or type 'quit' or 'exit' to exit and + interpreter. + + Press :kbd:`Ctrl` + :kbd:`D` or type 'quit' or 'exit' to exit and return to Sage. .. note:: diff --git a/src/sage/interfaces/kash.py b/src/sage/interfaces/kash.py index ce837b87737..bc389c74a07 100644 --- a/src/sage/interfaces/kash.py +++ b/src/sage/interfaces/kash.py @@ -38,14 +38,13 @@ Issues ------ -For some reason hitting Control-C to interrupt a calculation -doesn't work correctly. (TODO) +For some reason hitting :kbd:`Control` + :kbd:`C` to interrupt a calculation +does not work correctly. (TODO) Tutorial -------- -The examples in this tutorial require that kash -be installed. +The examples in this tutorial require that kash be installed. Basics ~~~~~~ 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/interfaces/maple.py b/src/sage/interfaces/maple.py index b3818b73dec..50a2d803d25 100644 --- a/src/sage/interfaces/maple.py +++ b/src/sage/interfaces/maple.py @@ -105,7 +105,7 @@ Another important feature of maple is its online help. We can access this through sage as well. After reading the description of -the command, you can press q to immediately get back to your +the command, you can press :kbd:`q` to immediately get back to your original prompt. Incidentally you can always get into a maple console by the diff --git a/src/sage/interfaces/maxima_abstract.py b/src/sage/interfaces/maxima_abstract.py index 3c563149393..3fb1a53a893 100644 --- a/src/sage/interfaces/maxima_abstract.py +++ b/src/sage/interfaces/maxima_abstract.py @@ -1523,7 +1523,7 @@ def nintegral(self, var='x', a=0, b=1, EXAMPLES:: sage: maxima('exp(-sqrt(x))').nintegral('x',0,1) - (0.5284822353142306, 4.1633141378838...e-11, 231, 0) + (0.5284822353142306, 4.163...e-11, 231, 0) Note that GP also does numerical integration, and can do so to very high precision very quickly:: diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index cc526a292a2..0ec81f224dd 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -159,14 +159,14 @@ (mterpri)))))))) """) -## Redirection of ECL and Maxima stdout to /dev/null +# Redirection of ECL and Maxima stdout to /dev/null ecl_eval(r"""(defparameter *dev-null* (make-two-way-stream (make-concatenated-stream) (make-broadcast-stream)))""") ecl_eval("(setf original-standard-output *standard-output*)") ecl_eval("(setf *standard-output* *dev-null*)") #ecl_eval("(setf *error-output* *dev-null*)") -## Default options set in Maxima +# Default options set in Maxima # display2d -- no ascii art output # keepfloat -- don't automatically convert floats to rationals @@ -184,48 +184,21 @@ init_code.append('nolabels : true') for l in init_code: ecl_eval("#$%s$"%l) -## To get more debug information uncomment the next line -## should allow to do this through a method +# To get more debug information uncomment the next line +# should allow to do this through a method #ecl_eval("(setf *standard-output* original-standard-output)") -## This is the main function (ECL object) used for evaluation +# This is the main function (ECL object) used for evaluation # This returns an EclObject maxima_eval=ecl_eval(""" (defun maxima-eval( form ) - (let ((result (catch 'macsyma-quit (cons 'maxima_eval (meval form))))) - ;(princ (list "result=" result)) - ;(terpri) - ;(princ (list "$error=" $error)) - ;(terpri) - (cond - ((and (consp result) (eq (car result) 'maxima_eval)) (cdr result)) - ((eq result 'maxima-error) - (let ((the-jig (process-error-argl (cddr $error)))) - (mapc #'set (car the-jig) (cadr the-jig)) - (error (concatenate 'string - "Error executing code in Maxima: " - (with-output-to-string (stream) - (apply #'mformat stream (cadr $error) - (caddr the-jig))))) - )) - (t - (let ((the-jig (process-error-argl (cddr $error)))) - (mapc #'set (car the-jig) (cadr the-jig)) - (error (concatenate 'string "Maxima condition. result:" - (princ-to-string result) "$error:" - (with-output-to-string (stream) - (apply #'mformat stream (cadr $error) - (caddr the-jig))))) - )) - ) - ) -) + (with-$error (meval form))) """) -## Number of instances of this interface +# Number of instances of this interface maxima_lib_instances = 0 -## Here we define several useful ECL/Maxima objects +# Here we define several useful ECL/Maxima objects # The Maxima string function can change the structure of its input #maxprint=EclObject("$STRING") maxprint=EclObject(r"""(defun mstring-for-sage (form) @@ -679,10 +652,10 @@ def _object_function_class(self): """ return MaximaLibElementFunction - ## some helper functions to wrap the calculus use of the maxima interface. - ## these routines expect arguments living in the symbolic ring - ## and return something that is hopefully coercible into the symbolic - ## ring again. + # some helper functions to wrap the calculus use of the maxima interface. + # these routines expect arguments living in the symbolic ring + # and return something that is hopefully coercible into the symbolic + # ring again. def sr_integral(self,*args): """ @@ -865,7 +838,7 @@ def sr_sum(self,*args): sage: sum(1/(m^4 + 2*m^3 + 3*m^2 + 2*m)^2, m, 0, infinity) Traceback (most recent call last): ... - RuntimeError: ECL says: Error executing code in Maxima: Zero to negative power computed. + RuntimeError: ECL says: Zero to negative power computed. Similar situation for :trac:`12410`:: @@ -873,8 +846,7 @@ def sr_sum(self,*args): sage: sum(1/x*(-1)^x, x, 0, oo) Traceback (most recent call last): ... - RuntimeError: ECL says: Error executing code in Maxima: Zero to negative power computed. - + RuntimeError: ECL says: Zero to negative power computed. """ try: return max_to_sr(maxima_eval([[max_ratsimp],[[max_simplify_sum],([max_sum],[sr_to_max(SR(a)) for a in args])]])) @@ -1203,7 +1175,7 @@ def reduce_load_MaximaLib(): NIL=EclObject("NIL") lisp_length=EclObject("length") -## Dictionaries for standard operators +# Dictionaries for standard operators sage_op_dict = { sage.functions.other.abs : "MABS", add_vararg : "MPLUS", @@ -1232,7 +1204,7 @@ def reduce_load_MaximaLib(): max_op_dict = dict([(sage_op_dict[k],k) for k in sage_op_dict]) -## Here we correct the dictionaries for some simple operators +# Here we correct the dictionaries for some simple operators def sage_rat(x,y): r""" @@ -1262,7 +1234,7 @@ def sage_rat(x,y): max_op_dict[rat]=sage_rat -## Here we build dictionaries for operators needing special conversions. +# Here we build dictionaries for operators needing special conversions. ratdisrep = EclObject("ratdisrep") mrat = EclObject("MRAT") mqapply = EclObject("MQAPPLY") @@ -1510,12 +1482,12 @@ def max_pochhammer_to_sage(expr): } -## Dictionaries for symbols +# Dictionaries for symbols sage_sym_dict={} max_sym_dict={} -## Generic conversion functions +# Generic conversion functions max_i=EclObject("$%I") def pyobject_to_max(obj): diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index ae1b87c55cb..b22c2fb1d3a 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -156,14 +156,17 @@ class Octave(Expect): EXAMPLES:: - sage: octave.eval("a = [ 1, 1, 2; 3, 5, 8; 13, 21, 33 ]") # optional - octave - 'a =\n\n 1 1 2\n 3 5 8\n 13 21 33\n' - sage: octave.eval("b = [ 1; 3; 13]") # optional - octave - 'b =\n\n 1\n 3\n 13\n' - sage: octave.eval(r"c=a \ b") # solves linear equation: a*c = b # optional - octave; random output - 'c =\n\n 1\n 7.21645e-16\n -7.21645e-16\n' - sage: octave.eval("c") # optional - octave; random output - 'c =\n\n 1\n 7.21645e-16\n -7.21645e-16\n' + sage: octave.eval("a = [ 1, 1, 2; 3, 5, 8; 13, 21, 33 ]").strip() # optional - octave + 'a =\n\n 1 1 2\n 3 5 8\n 13 21 33' + sage: octave.eval("b = [ 1; 3; 13]").strip() # optional - octave + 'b =\n\n 1\n 3\n 13' + + The following solves the linear equation: a*c = b:: + + sage: octave.eval(r"c=a \ b").strip() # optional - octave # abs tol 0.01 + 'c =\n\n 1\n -0\n 0' + sage: octave.eval("c").strip() # optional - octave # abs tol 0.01 + 'c =\n\n 1\n -0\n 0' TESTS: diff --git a/src/sage/interfaces/qepcad.py b/src/sage/interfaces/qepcad.py index d4b10353e0c..8adddead331 100644 --- a/src/sage/interfaces/qepcad.py +++ b/src/sage/interfaces/qepcad.py @@ -595,16 +595,15 @@ - Carl Witty (2008-03): initial version - Thierry Monteil (2015-07) repackaging + noncommutative doctests. """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Carl Witty # # 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/ +# **************************************************************************** +import os from sage.env import SAGE_LOCAL import pexpect import re @@ -1676,10 +1675,9 @@ def qepcad(formula, assume=None, interact=False, solution=None, raise ValueError("Unknown solution type ({})".format(solution)) -import os def qepcad_console(memcells=None): r""" - Run QEPCAD directly. To exit early, press Control-C. + Run QEPCAD directly. To exit early, press :kbd:`Control` + :kbd:`C`. EXAMPLES:: diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index df893a488f6..cefd33aebb4 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -117,7 +117,7 @@ sage: l6sn.sage_link().is_isotopic(l6) # optional - snappy True -But observe that the name conversion to SnapPy does not distingiush orientation +But observe that the name conversion to SnapPy does not distinguish orientation types:: sage: L6b = KnotInfo.L6a1_1 @@ -188,12 +188,12 @@ True To see all the properties available in this interface you can use "tab-completion". -For example type ``K.items.`` and than hit the "tab-key". You can select the item +For example type ``K.items.`` and than hit the :kbd:`Tab` key. You can select the item you want from the list. If you know some first letters type them first to obtain a reduced selection list. In a similar way you may select the knots and links. Here you have to type ``KnotInfo.`` -or ``KnotInfo.L7`` before stroking the "tab-key". In the latter case the selection list +or ``KnotInfo.L7`` before stroking the :kbd:`Tab` key. In the latter case the selection list will be reduced to proper links with 7 crossings. Finally there is a method :meth:`Link.get_knotinfo` of class :class:`Link` to find an instance @@ -216,6 +216,7 @@ AUTHORS: - Sebastian Oehms August 2020: initial version +- Sebastian Oehms June 2022: add :meth:`conway_polynomial` and :meth:`khovanov_polynomial` (:trac:`33969`) Thanks to Chuck Livingston and Allison Moore for their support. For further acknowledgments see the correspondig hompages. """ @@ -374,25 +375,27 @@ def items(self): @cached_method def __getitem__(self, item): r""" - sage: from sage.knots.knotinfo import KnotInfo - sage: L = KnotInfo.L4a1_0 - sage: L[L.items.alternating] - 'Y' - sage: L[L.items.arc_notation] - '{{6, 4}, {3, 5}, {4, 2}, {1, 3}, {2, 6}, {5, 1}}' - sage: L[L.items.braid_notation] - '{3, {-2, -2, -1, 2, -1}}' - sage: L[0] - Traceback (most recent call last): - ... - KeyError: "Item must be an instance of " + EXAMPLES:: + + sage: from sage.knots.knotinfo import KnotInfo + sage: L = KnotInfo.L4a1_0 + sage: L[L.items.alternating] + 'Y' + sage: L[L.items.arc_notation] + '{{6, 4}, {3, 5}, {4, 2}, {1, 3}, {2, 6}, {5, 1}}' + sage: L[L.items.braid_notation] + '{3, {-2, -2, -1, 2, -1}}' + sage: L[0] + Traceback (most recent call last): + ... + KeyError: "Item must be an instance of " """ if not isinstance(item, KnotInfoColumns): - raise KeyError('Item must be an instance of %s' %(KnotInfoColumns)) + raise KeyError('Item must be an instance of %s' % (KnotInfoColumns)) if item.column_type() == item.types.OnlyLinks and self.is_knot(): - raise KeyError('Item not available for knots' %(KnotInfoColumns)) + raise KeyError('Item not available for knots' % (KnotInfoColumns)) if item.column_type() == item.types.OnlyKnots and not self.is_knot(): - raise KeyError('Item not available for links' %(KnotInfoColumns)) + raise KeyError('Item not available for links' % (KnotInfoColumns)) l = db.read(item) ind = db.read_row_dict()[self.name][0] @@ -400,7 +403,7 @@ def __getitem__(self, item): if item.column_type() == item.types.OnlyLinks: offset = self._offset_knots() - return l[ind-offset] + return l[ind - offset] def _offset_knots(self): r""" @@ -1620,6 +1623,161 @@ def alexander_polynomial(self, var='t', original=False, laurent_poly=False): exp = ap.exponents() return t ** ((-max(exp) - min(exp)) // 2) * ap + @cached_method + def conway_polynomial(self, var='t', original=False): + r""" + Return the Conway polynomial according to the value of column + ``conway_polynomial`` for this knot or link as an instance of + :class:`~sage.rings.polynomial.polynomial_element.Polynomial`. + + It is obtained from the Seifert matrix `V` of ``self`` by the following + formula (see the KnotInfo description web-page; to launch it see the + example below): + + .. MATH:: + + \nabla(L) = \det(t^{\frac{1}{2}} V -t^{\frac{-1}{2}} V^t) + + Here `V^t` stands for the transpose of `V`. + + + INPUT: + + - ``var`` -- (default: ``'t'``) the variable + - ``original`` -- boolean (optional, default ``False``) if set to + ``True`` the original table entry is returned as a string + + OUTPUT: + + A polynomial over the integers, more precisely an instance of + :class:`~sage.rings.polynomial.polynomial_element.Polynomial`. + If ``original`` is set to ``True`` then a string is returned. + + EXAMPLES:: + + sage: from sage.knots.knotinfo import KnotInfo + sage: K = KnotInfo.K4_1 + sage: Kc = K.conway_polynomial(); Kc + -t^2 + 1 + sage: L = KnotInfo.L5a1_0 + sage: Lc = L.conway_polynomial(); Lc + t^3 + + Comparision to Sage's results:: + + sage: Kc == K.link().conway_polynomial() + True + sage: Lc == L.link().conway_polynomial() + True + + Launch the KnotInfo description web-page:: + + sage: K.items.conway_polynomial.description_webpage() # not tested + True + """ + conway_polynomial = self[self.items.conway_polynomial] + + if original: + return conway_polynomial + + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(ZZ, var) + + if not conway_polynomial and self.crossing_number() == 0: + return R.one() + + t, = R.gens() + lc = {'z': t} + return R(eval_knotinfo(conway_polynomial, locals=lc)) + + @cached_method + def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ, original=False): + r""" + Return the Khovanov polynomial according to the value of column + ``khovanov_polynomial`` for this knot or link as an instance of + :class:`~sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair`. + + INPUT: + + - ``var1`` -- (default: ``'q'``) the first variable + - ``var2`` -- (default: ``'t'``) the second variable + - ``base_ring`` -- (default: ``ZZ``) the ring of the polynomial's + coefficients + - ``original`` -- boolean (optional, default ``False``) if set to + ``True`` the original table entry is returned as a string + + OUTPUT: + + A Laurent polynomial over the integers, more precisely an instance of + :class:`~sage.rings.polynomial.laurent_polynomial.LaurentPolynomial_mpair`. + If ``original`` is set to ``True`` then a string is returned. + + .. NOTE :: + + The Khovanov polynomial given in KnotInfo corresponds to the mirror + image of the given knot for a `list of 140 exceptions + `__. + + EXAMPLES:: + + sage: from sage.knots.knotinfo import KnotInfo + sage: K = KnotInfo.K6_3 + sage: Kk = K.khovanov_polynomial(); Kk + q^7*t^3 + q^5*t^2 + q^3*t^2 + q^3*t + q*t + 2*q + 2*q^-1 + q^-1*t^-1 + + q^-3*t^-1 + q^-3*t^-2 + q^-5*t^-2 + q^-7*t^-3 + sage: Kk2 = K.khovanov_polynomial(var1='p', base_ring=GF(2)); Kk2 + p^7*t^3 + p^5*t^3 + p^5*t^2 + p^3*t + p^-1 + p^-1*t^-1 + p^-3*t^-2 + p^-7*t^-3 + + sage: L = KnotInfo.L5a1_0 + sage: Lk = L.khovanov_polynomial(); Lk + q^4*t^2 + t + 2 + 2*q^-2 + q^-2*t^-1 + q^-4*t^-2 + q^-6*t^-2 + q^-8*t^-3 + + Comparision to Sage's results:: + + sage: Kk == K.link().khovanov_polynomial() + True + sage: Kk2 == K.link().khovanov_polynomial(var1='p', base_ring=GF(2)) + True + sage: Lk == L.link().khovanov_polynomial() + True + """ + khovanov_polynomial = self[self.items.khovanov_polynomial] + + if original: + return khovanov_polynomial + + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing + var_names = [var1, var2] + R = LaurentPolynomialRing(base_ring, var_names) + + if not khovanov_polynomial and self.crossing_number() == 0: + return R({(1, 0): 1, (-1, 0): 1}) + + ch = base_ring.characteristic() + if ch == 2: + if not self.is_knot(): + raise NotImplementedError('Khovanov polynomial available only for knots in characteristic 2') + khovanov_torsion_polynomial = self[self.items.khovanov_torsion_polynomial] + khovanov_torsion_polynomial = khovanov_torsion_polynomial.replace('Q', 'q') + khovanov_polynomial = '%s + %s' % (khovanov_polynomial, khovanov_torsion_polynomial) + + if not khovanov_polynomial: + # given just for links with less than 12 crossings + raise NotImplementedError('Khovanov polynomial not available for this link') + + from sage.repl.preparse import implicit_mul + # since implicit_mul does not know about the choice of variable names + # we have to insert * between them separately + for i in ['q', 't',')']: + for j in ['q', 't', '(']: + khovanov_polynomial = khovanov_polynomial.replace('%s%s' % (i, j), '%s*%s' % (i, j)) + khovanov_polynomial = implicit_mul(khovanov_polynomial) + gens = R.gens_dict() + lc = {} + lc['q'] = gens[var1] + lc['t'] = gens[var2] + + return R(eval_knotinfo(khovanov_polynomial, locals=lc)) @cached_method def link(self, use_item=db.columns().pd_notation, snappy=False): diff --git a/src/sage/knots/link.py b/src/sage/knots/link.py index 7eda24daa86..2bca371c6e1 100644 --- a/src/sage/knots/link.py +++ b/src/sage/knots/link.py @@ -1958,13 +1958,14 @@ def conway_polynomial(self): M = max(alex.exponents()) coeff = alex[M] alex -= coeff * binom**M - conway += coeff * t_poly**M + conway += coeff * t_poly**M return conway def khovanov_polynomial(self, var1='q', var2='t', base_ring=ZZ): r""" - Return the Khovanov polynomial of ``self``. This is the Poincaré - polynomial of the Khovanov homology. + Return the Khovanov polynomial of ``self``. + + This is the Poincaré polynomial of the Khovanov homology. INPUT: 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/linkages/__init__.py b/src/sage/libs/linkages/__init__.py new file mode 100644 index 00000000000..e69de29bb2d 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/function.pyx b/src/sage/libs/singular/function.pyx index d7255b34440..74595b7c367 100644 --- a/src/sage/libs/singular/function.pyx +++ b/src/sage/libs/singular/function.pyx @@ -1200,8 +1200,8 @@ cdef class SingularFunction(SageObject): - ``args`` -- a list of arguments - ``ring`` -- a multivariate polynomial ring - - ``interruptible`` -- if ``True`` pressing Ctrl-C during the - execution of this function will interrupt the computation + - ``interruptible`` -- if ``True`` pressing :kbd:`Ctrl` + :kbd:`C` + during the execution of this function will interrupt the computation (default: ``True``) - ``attributes`` -- a dictionary of optional Singular @@ -1332,7 +1332,7 @@ INPUT: - ``args`` -- a list of arguments - ``ring`` -- a multivariate polynomial ring -- ``interruptible`` -- if ``True`` pressing Ctrl-C during the +- ``interruptible`` -- if ``True`` pressing :kbd:`Ctrl` + :kbd:`C` during the execution of this function will interrupt the computation (default: ``True``) - ``attributes`` -- a dictionary of optional Singular attributes 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..7dcdad7b113 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -4,7 +4,7 @@ A catalog of manifolds to rapidly create various simple manifolds. The current entries to the catalog are obtained by typing -``manifolds.``, where ```` indicates pressing the tab key. +``manifolds.``, where ```` indicates pressing the :kbd:`Tab` key. They are: - :class:`~sage.manifolds.differentiable.examples.euclidean.EuclideanSpace`: Euclidean space @@ -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_misc.py b/src/sage/matrix/matrix_misc.py index e68ba3ad0bc..859620ae2f2 100644 --- a/src/sage/matrix/matrix_misc.py +++ b/src/sage/matrix/matrix_misc.py @@ -39,10 +39,10 @@ def prm_mul(p1, p2, mask_free, prec): - `p1,p2` -- polynomials as dictionaries - - `mask_free` -- an integer mask that give the list of free variables + - ``mask_free`` -- an integer mask that give the list of free variables (the `i`-th variable is free if the `i`-th bit of ``mask_free`` is `1`) - - `prec` -- if `prec` is not None, truncate the product at precision `prec` + - ``prec`` -- if ``prec`` is not ``None``, truncate the product at precision ``prec`` EXAMPLES:: 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/constructor.py b/src/sage/matroids/constructor.py index 11c1ae4bbbc..1fb2cd2b93e 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -34,9 +34,9 @@ For built-in matroids, do the following: -* Within a Sage session, type ``matroids.`` (Do not press "Enter", and do not - forget the final period ".") -* Hit "tab". +* Within a Sage session, type ``matroids.`` (Do not press :kbd:`Enter`, + and do not forget the final period ".") +* Hit :kbd:`Tab`. You will see a list of methods which will construct matroids. For example:: @@ -140,9 +140,9 @@ def Matroid(groundset=None, data=None, **kwds): There are two main entry points to Sage's matroid functionality. For built-in matroids, do the following: - * Within a Sage session, type "matroids." (Do not press "Enter", and do + * Within a Sage session, type "matroids." (Do not press :kbd:`Enter`, and do not forget the final period ".") - * Hit "tab". + * Hit :kbd:`Tab`. You will see a list of methods which will construct matroids. For example:: 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/lean_matrix.pyx b/src/sage/matroids/lean_matrix.pyx index 01aaefc2f27..6b3cf27bcf2 100644 --- a/src/sage/matroids/lean_matrix.pyx +++ b/src/sage/matroids/lean_matrix.pyx @@ -3682,4 +3682,3 @@ cdef class RationalMatrix(LeanMatrix): version = 0 data = (self.nrows(), self.ncols(), entries) return unpickle_rational_matrix, (version, data) - 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..6c43b0d896d 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 @@ -7985,8 +7985,8 @@ cdef class Matroid(SageObject): for c in LM.chains(exclude=LM.maximal_elements()): if c: # the facets of IM are already present # get the cardinality of intersection of facet with IM - r = self.rank() - len(c) - + r = self.rank() - len(c) + # get candidate independent_sets for I in self.independent_r_sets(r): if I.issubset(c[0]): @@ -8012,7 +8012,7 @@ cdef class Matroid(SageObject): OUTPUT: - An instance of + An instance of :class:`MatroidUnion `. EXAMPLES:: diff --git a/src/sage/matroids/matroids_catalog.py b/src/sage/matroids/matroids_catalog.py index 2c9e607cbbe..1fc55a58cf2 100644 --- a/src/sage/matroids/matroids_catalog.py +++ b/src/sage/matroids/matroids_catalog.py @@ -3,8 +3,8 @@ A module containing constructors for several common matroids. -A list of all matroids in this module is available via tab -completion. Let ```` indicate pressing the tab key. So begin by typing +A list of all matroids in this module is available via tab completion. +Let ```` indicate pressing the :kbd:`Tab` key. So begin by typing ``matroids.`` to see the various constructions available. Many special matroids can be accessed from the submenu ``matroids.named_matroids.``. 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/latex.py b/src/sage/misc/latex.py index 3ec3a3e9edf..04df1b0a4b3 100644 --- a/src/sage/misc/latex.py +++ b/src/sage/misc/latex.py @@ -1859,7 +1859,7 @@ def view(objects, title='Sage', debug=False, sep='', tiny=False, sage: with NamedTemporaryFile(mode="w+t", suffix=".tex") as f: # optional - latex latex_package_tkz_graph ....: _ = f.write(_latex_file_(g)) ....: f.flush() - ....: _run_latex_(file, engine="pdflatex") + ....: _run_latex_(f.name, engine="pdflatex") 'pdf' sage: view(4, margin=5, debug=True) # not tested 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/package_dir.py b/src/sage/misc/package_dir.py index 8b5474972f2..17e0ce7b72c 100644 --- a/src/sage/misc/package_dir.py +++ b/src/sage/misc/package_dir.py @@ -1,22 +1,154 @@ +# sage_setup: distribution = sagemath-environment """ Recognizing package directories """ +# **************************************************************************** +# Copyright (C) 2020-2022 Matthias Koeppe +# +# 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/ +# **************************************************************************** + import os import glob from contextlib import contextmanager -def is_package_or_sage_namespace_package_dir(path): +class SourceDistributionFilter: + r""" + A :class:`collections.abc.Container` for source files in distributions. + + INPUT: + + - ``include_distributions`` -- (default: ``None``) if not ``None``, + should be a sequence or set of strings: include files whose + ``distribution`` (from a ``# sage_setup: distribution = PACKAGE`` + directive in the source file) is an element of ``distributions``. + + - ``exclude_distributions`` -- (default: ``None``) if not ``None``, + should be a sequence or set of strings: exclude files whose + ``distribution`` (from a ``# sage_setup: distribution = PACKAGE`` + directive in the module source file) is in ``exclude_distributions``. + + EXAMPLES:: + + sage: from sage.misc.package_dir import SourceDistributionFilter + sage: F = SourceDistributionFilter() + sage: sage.misc.package_dir.__file__ in F + True + sage: F = SourceDistributionFilter(include_distributions=['sagemath-environment']) + sage: sage.misc.package_dir.__file__ in F + True + sage: F = SourceDistributionFilter(exclude_distributions=['sagemath-environment']) + sage: sage.misc.package_dir.__file__ in F + False + """ + def __init__(self, include_distributions=None, exclude_distributions=None): + r""" + TESTS: + + ``exclude_distributions=None`` is normalized to the empty tuple:: + + sage: from sage.misc.package_dir import SourceDistributionFilter + sage: F = SourceDistributionFilter() + sage: F._exclude_distributions + () + """ + self._include_distributions = include_distributions + if exclude_distributions is None: + exclude_distributions = () + self._exclude_distributions = exclude_distributions + + def __contains__(self, filename): + r""" + TESTS: + + No file access is used when neither ``include_distributions`` nor + ``exclude_distributions`` is given:: + + sage: from sage.misc.package_dir import SourceDistributionFilter + sage: F = SourceDistributionFilter() + sage: '/doesnotexist' in F + True + + ``exclude_distributions`` can also be an empty container:: + + sage: F = SourceDistributionFilter(exclude_distributions=()) + sage: '/doesnotexist' in F + True + """ + if self._include_distributions is None and not self._exclude_distributions: + return True + distribution = read_distribution(filename) + if self._include_distributions is not None: + if distribution not in self._include_distributions: + return False + return distribution not in self._exclude_distributions + + +def read_distribution(src_file): + """ + Parse ``src_file`` for a ``# sage_setup: distribution = PKG`` directive. + + INPUT: + + - ``src_file`` -- file name of a Python or Cython source file + + OUTPUT: + + - a string, the name of the distribution package (``PKG``); or the empty + string if no directive was found. + + EXAMPLES:: + + sage: from sage.env import SAGE_SRC + sage: from sage.misc.package_dir import read_distribution + sage: read_distribution(os.path.join(SAGE_SRC, 'sage', 'graphs', 'graph_decompositions', 'tdlib.pyx')) + 'sagemath-tdlib' + sage: read_distribution(os.path.join(SAGE_SRC, 'sage', 'graphs', 'graph_decompositions', 'modular_decomposition.py')) + '' + """ + from Cython.Utils import open_source_file + with open_source_file(src_file, error_handling='ignore') as fh: + for line in fh: + # Adapted from Cython's Build/Dependencies.py + line = line.lstrip() + if not line: + continue + if line[0] != '#': + break + line = line[1:].lstrip() + kind = "sage_setup:" + if line.startswith(kind): + key, _, value = [s.strip() for s in line[len(kind):].partition('=')] + if key == "distribution": + return value + return '' + + +def is_package_or_sage_namespace_package_dir(path, *, distribution_filter=None): r""" Return whether ``path`` is a directory that contains a Python package. - Ordinary Python packages are recognized by the presence of `__init__.py`. + Ordinary Python packages are recognized by the presence of ``__init__.py``. Implicit namespace packages (PEP 420) are only recognized if they follow the conventions of the Sage library, i.e., the directory contains a file ``all.py`` or a file matching the pattern ``all__*.py`` such as ``all__sagemath_categories.py``. + INPUT: + + - ``path`` -- a directory name. + + - ``distribution_filter`` -- (optional, default: ``None``) + only consider ``all*.py`` files whose distribution (from a + ``# sage_setup: distribution = PACKAGE`` directive in the source file) + is an element of ``distribution_filter``. + EXAMPLES: :mod:`sage.cpython` is an ordinary package:: @@ -49,14 +181,17 @@ def is_package_or_sage_namespace_package_dir(path): sage: is_package_or_sage_namespace_package_dir(directory) False """ - if os.path.exists(os.path.join(path, '__init__.py')): # ordinary package - return True - if os.path.exists(os.path.join(path, '__init__.pxd')): # for consistency with Cython + if os.path.exists(os.path.join(path, '__init__.py')): # ordinary package return True - if os.path.exists(os.path.join(path, 'all.py')): # complete namespace package + if os.path.exists(os.path.join(path, '__init__.pxd')): # for consistency with Cython return True - for _ in glob.iglob(os.path.join(path, 'all__*.py')): - return True # partial namespace package + fname = os.path.join(path, 'all.py') + if os.path.exists(fname): + if distribution_filter is None or fname in distribution_filter: # complete namespace package + return True + for fname in glob.iglob(os.path.join(path, 'all__*.py')): + if distribution_filter is None or fname in distribution_filter: # partial namespace package + return True return False @@ -71,7 +206,7 @@ def cython_namespace_package_support(): import Cython.Build.Cythonize import Cython.Utils orig_is_package_dir = Cython.Utils.is_package_dir - Cython.Utils.is_package_dir = Cython.Build.Cythonize.is_package_dir = Cython.Build.Dependencies.is_package_dir = is_package_or_sage_namespace_package_dir + Cython.Utils.is_package_dir = Cython.Build.Cythonize.is_package_dir = Cython.Build.Dependencies.is_package_dir = Cython.Utils.cached_function(is_package_or_sage_namespace_package_dir) try: yield finally: 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/trace.py b/src/sage/misc/trace.py index 241342a452b..2547426bc0a 100644 --- a/src/sage/misc/trace.py +++ b/src/sage/misc/trace.py @@ -28,7 +28,7 @@ def trace(code, preparse=True): sage: trace("factor(100)") # not tested - then at the (Pdb) prompt type ``s`` (or ``step``), then press return + then at the (Pdb) prompt type ``s`` (or ``step``), then press :kbd:`Return` over and over to step through every line of Python that is called in the course of the above computation. Type ``?`` at any time for help on how to use the debugger (e.g., ``l`` lists 11 lines around 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..dc6b293102f 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 @@ -110,10 +109,10 @@ def hecke_operator_on_qexp(f, n, k, eps = None, # formula v = [f[m*n] for m in range(prec)] else: - l = k-1 + l = k - 1 for m in range(prec): - am = sum([eps(d) * d**l * f[m*n//(d*d)] for \ - d in divisors(gcd(n, m)) if (m*n) % (d*d) == 0]) + am = sum([eps(d) * d**l * f[m*n//(d*d)] + for d in divisors(gcd(n, m)) if (m*n) % (d*d) == 0]) v.append(am) if _return_list: return v @@ -123,6 +122,7 @@ def hecke_operator_on_qexp(f, n, k, eps = None, R = f.parent() return R(v, prec) + def _hecke_operator_on_basis(B, V, n, k, eps): """ Does the work for hecke_operator_on_basis once the input @@ -149,8 +149,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 +232,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..a16fd85d32c 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -54,7 +54,7 @@ # # Distributed under the terms of the GNU General Public License (GPL) # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ######################################################################### from sage.arith.misc import gcd @@ -81,7 +81,8 @@ from . import defaults from . import hecke_operator_on_qexp -WARN=False +WARN = False + def is_ModularFormsSpace(x): r""" @@ -528,8 +529,8 @@ def echelon_basis(self): W = self._q_expansion_module() pr = W.degree() B = self.q_echelon_basis(pr) - E = [self(F.linear_combination_of_basis(W.coordinates(f.padded_list(pr)))) \ - for f in B] + E = [self(F.linear_combination_of_basis(W.coordinates(f.padded_list(pr)))) + for f in B] return Sequence(E, cr=True, immutable=True) @cached_method @@ -537,10 +538,10 @@ def integral_basis(self): """ Return an integral basis for this space of modular forms. - EXAMPLES: In this example the integral and echelon bases are - different. + EXAMPLES: - :: + In this example the integral and echelon bases are + different. :: sage: m = ModularForms(97,2,prec=10) sage: s = m.cuspidal_subspace() @@ -908,8 +909,8 @@ def __add__(self, right): """ from sage.modular.modform.submodule import ModularFormsSubmodule if self.ambient_module() != right.ambient_module(): - raise ArithmeticError(("Sum of %s and %s not defined because " + \ - "they do not lie in a common ambient space.")%\ + raise ArithmeticError(("Sum of %s and %s not defined because " + + "they do not lie in a common ambient space.") % (self, right)) if self.is_ambient(): return self @@ -1309,7 +1310,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): """ @@ -1381,8 +1382,9 @@ def basis(self): 1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6) ] """ - return Sequence([self.element_class(self, x) for \ - x in self.free_module().basis()], immutable=True, cr=True) + return Sequence([self.element_class(self, x) + for x in self.free_module().basis()], + immutable=True, cr=True) def gen(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/vm_basis.py b/src/sage/modular/modform/vm_basis.py index be690b7b503..21e2fcd7477 100644 --- a/src/sage/modular/modform/vm_basis.py +++ b/src/sage/modular/modform/vm_basis.py @@ -248,8 +248,8 @@ def _delta_poly(prec=10): stop = int((-1+math.sqrt(1+8*prec))/2.0) # make list of index/value pairs for the sparse poly - values = [(n*(n+1)//2, ((-2*n-1) if (n & 1) else (2*n+1))) \ - for n in range(stop+1)] + values = [(n*(n+1)//2, ((-2*n-1) if (n & 1) else (2*n+1))) + for n in range(stop + 1)] for (i1, v1) in values: for (i2, v2) in values: @@ -260,15 +260,14 @@ def _delta_poly(prec=10): f = Fmpz_poly(v) t = verbose('made series') - f = f*f + f = f * f f._unsafe_mutate_truncate(prec) t = verbose('squared (2 of 3)', t) - f = f*f + f = f * f f._unsafe_mutate_truncate(prec - 1) t = verbose('squared (3 of 3)', t) f = f.left_shift(1) t = verbose('shifted', t) - return f diff --git a/src/sage/modular/modform_hecketriangle/abstract_ring.py b/src/sage/modular/modform_hecketriangle/abstract_ring.py index 5a9b0e86258..0ff086c0a60 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_ring.py +++ b/src/sage/modular/modform_hecketriangle/abstract_ring.py @@ -222,23 +222,21 @@ def _coerce_map_from_(self, S): sage: MR4.has_coerce_map_from(MF2) True """ - from .space import FormsSpace_abstract from .functors import _common_subgroup - if ( isinstance(S, FormsRing_abstract)\ - and self._group == _common_subgroup(self._group, S._group)\ - and self._analytic_type >= S._analytic_type\ - and self.base_ring().has_coerce_map_from(S.base_ring()) ): + if (isinstance(S, FormsRing_abstract) + and self._group == _common_subgroup(self._group, S._group) + and self._analytic_type >= S._analytic_type + and self.base_ring().has_coerce_map_from(S.base_ring())): return True - elif isinstance(S, FormsRing_abstract): + if isinstance(S, FormsRing_abstract): return False - elif isinstance(S, FormsSpace_abstract): - raise RuntimeError( "This case should not occur." ) + if isinstance(S, FormsSpace_abstract): + raise RuntimeError("this case should not occur") # return self._coerce_map_from_(S.graded_ring()) - elif (self.AT("holo") <= self._analytic_type) and (self.coeff_ring().has_coerce_map_from(S)): + if (self.AT("holo") <= self._analytic_type) and (self.coeff_ring().has_coerce_map_from(S)): return True - else: - return False + return False def _an_element_(self): r""" diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index e7c59012429..90c786b1c9f 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -6,16 +6,14 @@ - Jonas Jermann (2013): initial version """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann # # 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.matrix.constructor import matrix from sage.misc.cachefunc import cached_method from sage.modules.free_module_element import is_FreeModuleElement @@ -323,19 +321,19 @@ def _coerce_map_from_(self, S): from .space import ZeroForm from .subspace import SubSpaceForms - if ( isinstance(S, ZeroForm)): + if isinstance(S, ZeroForm): return True - elif ( isinstance(S, SubSpaceForms)\ - and isinstance(self, SubSpaceForms) ): + if (isinstance(S, SubSpaceForms) + and isinstance(self, SubSpaceForms)): if (self.ambient_space().has_coerce_map_from(S.ambient_space())): S2 = S.change_ambient_space(self.ambient_space()) return self.module().has_coerce_map_from(S2.module()) else: return False - elif ( isinstance(S, FormsSpace_abstract)\ - and self.graded_ring().has_coerce_map_from(S.graded_ring())\ - and S.weight() == self._weight\ - and S.ep() == self._ep\ + elif ( isinstance(S, FormsSpace_abstract) + and self.graded_ring().has_coerce_map_from(S.graded_ring()) + and S.weight() == self._weight + and S.ep() == self._ep and not isinstance(self, SubSpaceForms)): return True else: @@ -1743,10 +1741,8 @@ def construct_form(self, laurent_series, order_1=ZZ(0), check=True, rationalize= if (len(coefficients) == 0): return self(0) - rat = sum([\ - coefficients[j] * self.F_basis_pol(exponents[j], order_1=order_1)\ - for j in range(ZZ(len(coefficients))) - ]) + rat = sum([coefficients[j] * self.F_basis_pol(exponents[j], order_1=order_1) + for j in range(ZZ(len(coefficients)))]) el = self(rat) diff --git a/src/sage/modular/modform_hecketriangle/all.py b/src/sage/modular/modform_hecketriangle/all.py index 728c7f729a9..cd236efc334 100644 --- a/src/sage/modular/modform_hecketriangle/all.py +++ b/src/sage/modular/modform_hecketriangle/all.py @@ -2,28 +2,28 @@ AUTHORS: - Jonas Jermann (2013): initial version - """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013-2014 Jonas Jermann # # 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 .hecke_triangle_groups import HeckeTriangleGroup -from .series_constructor import MFSeriesConstructor +from .series_constructor import MFSeriesConstructor -from .graded_ring import ( QuasiMeromorphicModularFormsRing, QuasiWeakModularFormsRing, QuasiModularFormsRing,\ - QuasiCuspFormsRing, MeromorphicModularFormsRing, WeakModularFormsRing,\ - ModularFormsRing, CuspFormsRing ) +from .graded_ring import (QuasiMeromorphicModularFormsRing, + QuasiWeakModularFormsRing, QuasiModularFormsRing, + QuasiCuspFormsRing, MeromorphicModularFormsRing, + WeakModularFormsRing, + ModularFormsRing, CuspFormsRing) -from .space import ( QuasiMeromorphicModularForms, QuasiWeakModularForms, QuasiModularForms, QuasiCuspForms,\ - MeromorphicModularForms, WeakModularForms, ModularForms, CuspForms,\ - ZeroForm ) +from .space import (QuasiMeromorphicModularForms, QuasiWeakModularForms, + QuasiModularForms, QuasiCuspForms, + MeromorphicModularForms, WeakModularForms, ModularForms, + CuspForms, ZeroForm) -from .subspace import ModularFormsSubSpace +from .subspace import ModularFormsSubSpace diff --git a/src/sage/modular/modform_hecketriangle/graded_ring_element.py b/src/sage/modular/modform_hecketriangle/graded_ring_element.py index 5cdf3236ebc..59161396a27 100644 --- a/src/sage/modular/modform_hecketriangle/graded_ring_element.py +++ b/src/sage/modular/modform_hecketriangle/graded_ring_element.py @@ -2169,12 +2169,10 @@ def evaluate(self, tau, prec = None, num_prec = None, check=False): pass # The general case - num_prec = max(\ - ZZ(getattr(tau,'prec',lambda: num_prec)()),\ - num_prec\ - ) + num_prec = max(ZZ(getattr(tau, 'prec', lambda: num_prec)()), num_prec) + tau = tau.n(num_prec) - (x,y,z,d) = self.parent().rat_field().gens() + (x, y, z, d) = self.parent().rat_field().gens() if (self.is_homogeneous() and self.is_modular()): q_exp = self.q_expansion_fixed_d(prec=prec, d_num_prec=num_prec) diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index aacc203cf0a..bf32cf77f65 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -837,7 +837,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..627f1c567e7 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -2651,9 +2651,9 @@ def _repr_(self): sage: M # indirect doctest Modular Symbols space of dimension 32 for Gamma_0(37) of weight 6 with sign 0 over Rational Field """ - return ("Modular Symbols space of dimension %s for Gamma_0(%s) of weight %s with sign %s " + \ - "over %s")%(self.dimension(), self.level(),self.weight(), self.sign(), - self.base_ring()) + return ("Modular Symbols space of dimension %s for Gamma_0(%s) of weight %s with sign %s " + + "over %s") % (self.dimension(), self.level(),self.weight(), self.sign(), + self.base_ring()) def _cuspidal_submodule_dimension_formula(self): r""" @@ -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) @@ -3607,10 +3607,10 @@ def _repr_(self): sage: M # indirect doctest Modular Symbols space of dimension 2 and level 5, weight 3, character [zeta4], sign 0, over Cyclotomic Field of order 4 and degree 2 """ - return ("Modular Symbols space of dimension %s and level %s, weight %s, character %s, sign %s, " + \ - "over %s")%(self.dimension(), self.level(), self.weight(), - self.character()._repr_short_(), self.sign(), self.base_ring()) - + return ("Modular Symbols space of dimension %s and level %s, weight %s, character %s, sign %s, " + + "over %s") % (self.dimension(), self.level(), self.weight(), + self.character()._repr_short_(), self.sign(), + self.base_ring()) def _cuspidal_submodule_dimension_formula(self): r""" diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index f8550d0f05f..ec41f8c36dd 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). @@ -569,7 +569,7 @@ def __call__(self, x): y = {i: xi for i, xi in enumerate(x)} return BoundarySpaceElement(self, y) - raise TypeError("Coercion of %s (of type %s) into %s not (yet) defined."%(x, type(x), self)) + raise TypeError("Coercion of %s (of type %s) into %s not (yet) defined." % (x, type(x), self)) def _repr_(self): """ @@ -580,10 +580,10 @@ def _repr_(self): sage: sage.modular.modsym.boundary.BoundarySpace(Gamma0(3), 2)._repr_() 'Space of Boundary Modular Symbols of weight 2 for Congruence Subgroup Gamma0(3) with sign 0 and character [1] over Rational Field' """ - return ("Space of Boundary Modular Symbols of weight %s for" + \ + return ("Space of Boundary Modular Symbols of weight %s for" + " %s with sign %s and character %s over %s") % ( - self.weight(), self.group(), self.sign(), - self.character()._repr_short_(), self.base_ring()) + self.weight(), self.group(), self.sign(), + self.character()._repr_short_(), self.base_ring()) def _cusp_index(self, cusp): """ @@ -806,8 +806,8 @@ def _repr_(self): sage: ModularSymbols(Gamma1(5), 3, sign=1).boundary_space()._repr_() 'Boundary Modular Symbols space for Gamma_1(5) of weight 3 over Rational Field' """ - return ("Boundary Modular Symbols space for Gamma_1(%s) of weight %s " + \ - "over %s") % (self.level(),self.weight(), self.base_ring()) + return ("Boundary Modular Symbols space for Gamma_1(%s) of weight %s " + + "over %s") % (self.level(), self.weight(), self.base_ring()) def _is_equiv(self, c1, c2): """ @@ -946,19 +946,19 @@ def _coerce_cusp(self, c): # if sign: if (c.is_infinity() and sign != (-1)**self.weight()) or \ - (c.is_zero() and sign== -1): + (c.is_zero() and sign == -1): self._zero_cusps.append(c) del self._known_gens[-1] return self(0) elif (not c.is_infinity() and not c.is_zero()): t, eps = self._is_equiv(c, -c) - if t and ((eps == 1 and sign == -1) or \ + if t and ((eps == 1 and sign == -1) or (eps == -1 and sign != (-1)**self.weight())): self._zero_cusps.append(c) del self._known_gens[-1] return self(0) - return BoundarySpaceElement(self, {(len(g)-1):1}) + return BoundarySpaceElement(self, {(len(g)-1): 1}) class BoundarySpace_wtk_gamma_h(BoundarySpace): @@ -1016,8 +1016,8 @@ def _repr_(self): sage: ModularSymbols(GammaH(7,[2]), 4).boundary_space()._repr_() 'Boundary Modular Symbols space for Congruence Subgroup Gamma_H(7) with H generated by [2] of weight 4 over Rational Field' """ - return ("Boundary Modular Symbols space for %s of weight %s " + \ - "over %s") % (self.group(),self.weight(), self.base_ring()) + return ("Boundary Modular Symbols space for %s of weight %s " + + "over %s") % (self.group(), self.weight(), self.base_ring()) def _is_equiv(self, c1, c2): """ @@ -1205,13 +1205,13 @@ def _coerce_cusp(self, c): return self(0) elif (not c.is_infinity() and not c.is_zero()): t, eps = self._is_equiv(c, -c) - if t and ((eps == 1 and sign == -1) or \ + if t and ((eps == 1 and sign == -1) or (eps == -1 and sign != (-1)**self.weight())): self._zero_cusps.append(c) del self._known_gens[-1] return self(0) - return BoundarySpaceElement(self, {(len(g)-1):1}) + return BoundarySpaceElement(self, {(len(g)-1): 1}) class BoundarySpace_wtk_eps(BoundarySpace): @@ -1263,9 +1263,11 @@ def _repr_(self): sage: ModularSymbols(DirichletGroup(6).0, 4).boundary_space()._repr_() 'Boundary Modular Symbols space of level 6, weight 4, character [-1] and dimension 0 over Rational Field' """ - return ("Boundary Modular Symbols space of level %s, weight %s, character %s " + \ + return ("Boundary Modular Symbols space of level %s, weight %s, character %s " + "and dimension %s over %s") % (self.level(), self.weight(), - self.character()._repr_short_(), self.rank(), self.base_ring()) + self.character()._repr_short_(), + self.rank(), + self.base_ring()) def _is_equiv(self, c1, c2): """ diff --git a/src/sage/modular/modsym/element.py b/src/sage/modular/modsym/element.py index 0735a58308e..cc81faad50d 100644 --- a/src/sage/modular/modsym/element.py +++ b/src/sage/modular/modsym/element.py @@ -291,8 +291,8 @@ def manin_symbol_rep(self): v = self.element() manin_symbols = A.ambient_hecke_module().manin_symbols_basis() F = formal_sum.FormalSums(A.base_ring()) - ms = F([(v[i], manin_symbols[i]) for i in \ - range(v.degree()) if v[i] != 0], check=False, reduce=False) + ms = F([(v[i], manin_symbols[i]) for i in range(v.degree()) + if v[i] != 0], check=False, reduce=False) self.__manin_symbols = ms return self.__manin_symbols diff --git a/src/sage/modular/modsym/manin_symbol_list.py b/src/sage/modular/modsym/manin_symbol_list.py index 187db53bd16..182a35ffe32 100644 --- a/src/sage/modular/modsym/manin_symbol_list.py +++ b/src/sage/modular/modsym/manin_symbol_list.py @@ -16,7 +16,7 @@ - :class:`ManinSymbolList_character` """ -#***************************************************************************** +# **************************************************************************** # Sage: Open Source Mathematical Software # # Copyright (C) 2005 William Stein @@ -30,8 +30,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sage.modular.modsym.p1list as p1list import sage.modular.modsym.g1list as g1list @@ -949,8 +949,8 @@ def __init__(self, character, weight): # The list returned from P1List is guaranteed to be sorted. # Thus each list constructed below is also sorted. This is # important since the index function assumes the list is sorted. - L = [(i, u, v) for i in range(weight-2+1) \ - for u, v in self.__P1.list()] + L = [(i, u, v) for i in range(weight - 2 + 1) + for u, v in self.__P1.list()] self.__list = L ManinSymbolList.__init__(self, weight, L) 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/modular_symbols.py b/src/sage/modular/modsym/modular_symbols.py index c832cb8be05..30a1aa2c0b8 100644 --- a/src/sage/modular/modsym/modular_symbols.py +++ b/src/sage/modular/modsym/modular_symbols.py @@ -14,8 +14,7 @@ sage: loads(dumps(s)) == s True """ - -#***************************************************************************** +# **************************************************************************** # Sage: Open Source Mathematical Software # # Copyright (C) 2005, 2009 William Stein @@ -29,8 +28,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sage.modular.cusps as cusps from sage.modular.modsym.apply import apply_to_monomial from sage.modular.modsym.manin_symbol import ManinSymbol @@ -316,11 +315,11 @@ def apply(self, g): space = self.__space i = self.__i k = space.weight() - a,b,c,d = tuple(g) - coeffs = apply_to_monomial(i, k-2, d, -b, -c, a) + a, b, c, d = tuple(g) + coeffs = apply_to_monomial(i, k - 2, d, -b, -c, a) g_alpha = self.__alpha.apply(g) g_beta = self.__beta.apply(g) - return formal_sum.FormalSum([(coeffs[j], ModularSymbol(space, j, g_alpha, g_beta)) \ + return formal_sum.FormalSum([(coeffs[j], ModularSymbol(space, j, g_alpha, g_beta)) for j in reversed(range(k-1)) if coeffs[j] != 0]) def __manin_symbol_rep(self, alpha): diff --git a/src/sage/modular/modsym/p1list_nf.py b/src/sage/modular/modsym/p1list_nf.py index 222caacca80..96f553658c1 100644 --- a/src/sage/modular/modsym/p1list_nf.py +++ b/src/sage/modular/modsym/p1list_nf.py @@ -1199,6 +1199,6 @@ def psi(N): raise ValueError("psi only defined for integral ideals") from sage.misc.misc_c import prod - return prod([(np+1)*np**(e-1) \ - for np,e in [(p.absolute_norm(),e) \ - for p,e in N.factor()]]) + return prod([(np + 1) * np**(e - 1) + for np, e in [(p.absolute_norm(), e) + for p, e in N.factor()]]) 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/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index 996e9287697..f639137bbf0 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -218,6 +218,7 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.rational_field import QQ from sage.rings.ring import CommutativeRing from sage.structure.richcmp import richcmp, richcmp_method @@ -490,7 +491,7 @@ def quaternion_order_with_given_level(A, level): level = abs(level) N = A.discriminant() N1 = gcd(level, N) - M1 = level / N1 + M1 = level // N1 O = maximal_order(A) # if N1 != 1: @@ -1034,7 +1035,7 @@ def hecke_matrix(self, n, algorithm='default', sparse=False, B=None): """ n = ZZ(n) if n <= 0: - raise IndexError("n must be positive.") + raise IndexError("n must be positive") if n not in self._hecke_matrices: if algorithm == 'default': try: @@ -1055,7 +1056,7 @@ def hecke_matrix(self, n, algorithm='default', sparse=False, B=None): elif algorithm == 'brandt': T = self._compute_hecke_matrix_brandt(n, sparse=sparse) else: - raise ValueError("unknown algorithm '%s'" % algorithm) + raise ValueError(f"unknown algorithm '{algorithm}'") T.set_immutable() self._hecke_matrices[n] = T return self._hecke_matrices[n] @@ -1517,7 +1518,7 @@ def brandt_series(self, prec, var='q'): [ 1/6 + 2*t^2 + O(t^3) 1/6 + t + O(t^3)] """ A = self._brandt_series_vectors(prec) - R = QQ[[var]] + R = PowerSeriesRing(QQ, var) n = len(A[0]) return matrix(R, n, n, [[R(x.list()[:prec], prec) for x in Y] for Y in A]) @@ -1560,7 +1561,7 @@ def eisenstein_subspace(self): V = A.kernel() return V - def is_cuspidal(self): + def is_cuspidal(self) -> bool: r""" Return whether ``self`` is cuspidal, i.e. has no Eisenstein part. @@ -1584,7 +1585,7 @@ def monodromy_weights(self): fixed choice of basis. The weight of an ideal class `[I]` is half the number of units of the right order `I`. - NOTE: The base ring must be `\QQ` or `\ZZ`. + .. NOTE:: The base ring must be `\QQ` or `\ZZ`. EXAMPLES:: @@ -1619,9 +1620,9 @@ def monodromy_weights(self): return tuple(a[1] / a[0] / 2 for a in thetas) -############################################################################# -# Benchmarking -############################################################################# +# ==================== +# Benchmarking +# ==================== def benchmark_magma(levels, silent=False): """ INPUT: diff --git a/src/sage/modules/fg_pid/fgp_element.py b/src/sage/modules/fg_pid/fgp_element.py index c2ed4590188..dadf8745f88 100644 --- a/src/sage/modules/fg_pid/fgp_element.py +++ b/src/sage/modules/fg_pid/fgp_element.py @@ -363,7 +363,7 @@ def _vector_(self, base_ring=None): - ``base_ring`` -- the desired base ring of the vector. OUTPUT: - + A vector over the base ring. EXAMPLES:: 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/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index 8710352f87a..b512db6ffbc 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -8,9 +8,9 @@ can specify and change. Create the free module of rank `n` over an arbitrary commutative ring `R` -using the command ``FreeModule(R,n)`` with a given inner_product_matrix. +using the command ``FreeModule(R,n)`` with a given ``inner_product_matrix``. -The following example illustrates the creation of both a vector spaces +The following example illustrates the creation of both a vector space and a free module over the integers and a submodule of it. Use the functions ``FreeModule``, ``span`` and member functions of free modules to create free modules. ''Do not use the ``FreeModule_xxx`` constructors @@ -56,7 +56,6 @@ - David Kohel (2008-06): First created (based on free_module.py) """ - # **************************************************************************** # Copyright (C) 2008 David Kohel # @@ -66,39 +65,38 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - import weakref import sage.matrix.matrix_space import sage.misc.latex as latex import sage.rings.ring as ring -import sage.rings.integer from sage.categories.principal_ideal_domains import PrincipalIdealDomains from . import free_module -############################################################################### +# ############################################################################# # # Constructor functions # -############################################################################### +# ############################################################################# _cache = {} -def FreeQuadraticModule( - base_ring, rank, inner_product_matrix, sparse=False, inner_product_ring=None): + +def FreeQuadraticModule(base_ring, rank, inner_product_matrix, + sparse=False, inner_product_ring=None): r""" Create the free quadratic module over the given commutative ring of the given rank. INPUT: - - base_ring -- a commutative ring + - ``base_ring`` -- a commutative ring - - rank -- a nonnegative integer + - ``rank`` -- a nonnegative integer - - inner_product_matrix -- the inner product matrix + - ``inner_product_matrix`` -- the inner product matrix - - sparse -- bool; (default False) + - ``sparse`` -- bool; (default ``False``) - - inner_product_ring -- the inner product codomain ring; (default None) + - ``inner_product_ring`` -- the inner product codomain ring; (default ``None``) OUTPUT: @@ -106,9 +104,9 @@ def FreeQuadraticModule( .. NOTE:: - In Sage it is the case that there is only one dense and one - sparse free ambient quadratic module of rank `n` over `R` and given - inner product matrix. + In Sage, it is the case that there is only one dense and one + sparse free ambient quadratic module of rank `n` over `R` and + given inner product matrix. EXAMPLES:: @@ -140,7 +138,7 @@ def FreeQuadraticModule( # In order to use coercion into the inner_product_ring we need to pass # this ring into the vector classes. if inner_product_ring is not None: - raise NotImplementedError("An inner_product_ring cannot currently be defined.") + raise NotImplementedError("an inner_product_ring cannot currently be defined") # We intentionally create a new matrix instead of using the given # inner_product_matrix. This ensures that the matrix has the correct @@ -162,11 +160,11 @@ def FreeQuadraticModule( if not base_ring.is_commutative(): raise TypeError("base_ring must be a commutative ring") - #elif not sparse and isinstance(base_ring,sage.rings.real_double.RealDoubleField_class): - # M = RealDoubleQuadraticSpace_class(rank, inner_product_matrix=inner_product_matrix, sparse=False) + # elif not sparse and isinstance(base_ring,sage.rings.real_double.RealDoubleField_class): + # M = RealDoubleQuadraticSpace_class(rank, inner_product_matrix=inner_product_matrix, sparse=False) - #elif not sparse and isinstance(base_ring,sage.rings.complex_double.ComplexDoubleField_class): - # M = ComplexDoubleQuadraticSpace_class(rank, inner_product_matrix=inner_product_matrix, sparse=False) + # elif not sparse and isinstance(base_ring,sage.rings.complex_double.ComplexDoubleField_class): + # M = ComplexDoubleQuadraticSpace_class(rank, inner_product_matrix=inner_product_matrix, sparse=False) elif base_ring.is_field(): M = FreeQuadraticModule_ambient_field( @@ -186,6 +184,7 @@ def FreeQuadraticModule( _cache[key] = weakref.ref(M) return M + def QuadraticSpace(K, dimension, inner_product_matrix, sparse=False): """ EXAMPLES: @@ -213,25 +212,27 @@ def QuadraticSpace(K, dimension, inner_product_matrix, sparse=False): sage: QuadraticSpace(ZZ,5,identity_matrix(ZZ,2)) Traceback (most recent call last): ... - TypeError: Argument K (= Integer Ring) must be a field. + TypeError: argument K (= Integer Ring) must be a field """ if not K.is_field(): - raise TypeError("Argument K (= %s) must be a field." % K) + raise TypeError(f"argument K (= {K}) must be a field") if sparse not in (True, False): raise TypeError("Argument sparse (= %s) must be a boolean." % sparse) return FreeQuadraticModule(K, rank=dimension, inner_product_matrix=inner_product_matrix, sparse=sparse) + InnerProductSpace = QuadraticSpace -############################################################################### + +# ############################################################################# # # Base class for all free modules # -############################################################################### +# ############################################################################# def is_FreeQuadraticModule(M): """ - Return True if `M` is a free quadratic module. + Return ``True`` if `M` is a free quadratic module. EXAMPLES:: @@ -248,6 +249,7 @@ def is_FreeQuadraticModule(M): """ return isinstance(M, FreeQuadraticModule_generic) + class FreeQuadraticModule_generic(free_module.FreeModule_generic): """ Base class for all free quadratic modules. @@ -302,13 +304,13 @@ class FreeQuadraticModule_generic(free_module.FreeModule_generic): """ def __init__(self, base_ring, rank, degree, inner_product_matrix, sparse=False): """ - Create the free module of given rank over the given base_ring. + Create the free module of given rank over the given ``base_ring``. INPUT: - - base_ring -- a commutative ring + - ``base_ring`` -- a commutative ring - - rank -- a non-negative integer + - ``rank`` -- a non-negative integer EXAMPLES:: @@ -326,9 +328,9 @@ def __init__(self, base_ring, rank, degree, inner_product_matrix, sparse=False): def _dense_module(self): """ - Creates a dense module with the same defining data as self. + Create a dense module with the same defining data as ``self``. - N.B. This function is for internal use only! See dense_module for use. + .. NOTE:: This function is for internal use only! See ``dense_module`` for use. EXAMPLES:: @@ -343,9 +345,9 @@ def _dense_module(self): def _sparse_module(self): """ - Creates a sparse module with the same defining data as self. + Create a sparse module with the same defining data as ``self``. - N.B. This function is for internal use only! See sparse_module for use. + .. NOTE:: This function is for internal use only! See ``sparse_module`` for use. EXAMPLES:: @@ -399,9 +401,10 @@ def determinant(self): def discriminant(self): """ - Return the discriminant of this free module, defined to be (-1)^r - of the determinant, where r = n/2 (n even) or (n-1)/2 (n odd) for - a module of rank n. + Return the discriminant of this free module. + + This is defined to be `(-1)^r` of the determinant, where `r = n/2` + (`n` even) or `(n-1)/2` (`n` odd) for a module of rank `n`. EXAMPLES:: @@ -417,23 +420,23 @@ def discriminant(self): TESTS:: - sage: M=FreeQuadraticModule(ZZ,2,matrix.identity(2)) + sage: M = FreeQuadraticModule(ZZ, 2, matrix.identity(2)) sage: M.discriminant() -1 - sage: M=FreeQuadraticModule(QQ,3,matrix.identity(3)) + sage: M = FreeQuadraticModule(QQ, 3, matrix.identity(3)) sage: M.discriminant() -1 - """ - n = self.rank() - r = n//2 - return (-1)**r*self.gram_matrix().determinant() + r = self.rank() // 2 + return (-1)**r * self.gram_matrix().determinant() def gram_matrix(self): """ - Return the gram matrix associated to this free module, defined to be - G = B*A*B.transpose(), where A is the inner product matrix (induced from - the ambient space), and B the basis matrix. + Return the Gram matrix associated to this free module. + + This is defined to be ``B*A*B.transpose()``, where ``A`` is the + inner product matrix (induced from the ambient space), and ``B`` + the basis matrix. EXAMPLES:: @@ -451,28 +454,30 @@ def gram_matrix(self): [1 1 1] [1 2 1] [1 1 2] - """ if self.is_ambient(): return self.inner_product_matrix() - else: - if self._gram_matrix is None: - A = self.inner_product_matrix() - B = self.basis_matrix() - self._gram_matrix = B*A*B.transpose() - return self._gram_matrix + if self._gram_matrix is None: + A = self.inner_product_matrix() + B = self.basis_matrix() + self._gram_matrix = B * A * B.transpose() + return self._gram_matrix def inner_product_matrix(self): """ - Return the inner product matrix associated to this module. By definition this - is the inner product matrix of the ambient space, hence may be of degree greater - than the rank of the module. + Return the inner product matrix associated to this module. + + By definition, this is the inner product matrix of the ambient + space, hence may be of degree greater than the rank of the + module. + + .. NOTE:: The inner product does not have to be symmetric (see examples). - N.B. The inner product does not have to be symmetric (see examples). + .. TODO:: - TODO: Differentiate the image ring of the inner product from the base ring of - the module and/or ambient space. E.g. On an integral module over ZZ the inner - product pairing could naturally take values in ZZ, QQ, RR, or CC. + Differentiate the image ring of the inner product from the base ring of + the module and/or ambient space. E.g. On an integral module over ZZ the inner + product pairing could naturally take values in ZZ, QQ, RR, or CC. EXAMPLES:: @@ -494,7 +499,7 @@ def inner_product_matrix(self): sage: v.inner_product(u) 2 - The inner product matrix is defined with respect to the ambient space. + The inner product matrix is defined with respect to the ambient space:: sage: V = QQ^3 sage: u = V([1/2,1,1]) @@ -509,15 +514,16 @@ def inner_product_matrix(self): sage: M.gram_matrix() [ 1/2 -3/4] [-3/4 13/4] - """ return self._inner_product_matrix def _inner_product_is_dot_product(self): """ Return whether or not the inner product on this module is induced by - the dot product on the ambient vector space. This is used internally - by the inner_product function for optimization. + the dot product on the ambient vector space. + + This is used internally by the ``inner_product`` function for + optimization. EXAMPLES:: @@ -538,12 +544,16 @@ def _inner_product_is_dot_product(self): def _inner_product_is_diagonal(self): """ Return whether or not the inner product on this module is induced by - the dot product on the ambient vector space. This is used internally - by the inner_product function for optimization. + the dot product on the ambient vector space. + + This is used internally by the ``inner_product`` function for + optimization. + + .. NOTE:: - N.B. The FreeModule classes have the identity inner product matrix, - while FreeQuadraticModules must have an inner_product_matrix, although - it can be diagonal. + The ``FreeModule`` classes have the identity inner product matrix, + while ``FreeQuadraticModules`` must have an ``inner_product_matrix``, although + it can be diagonal. EXAMPLES:: @@ -565,13 +575,12 @@ def _inner_product_is_diagonal(self): .. TODO:: Actually use the diagonal form of the inner product. """ A = self.inner_product_matrix() - D = sage.matrix.constructor.diagonal_matrix([A[i, i] - for i in range(A.nrows())]) + D = sage.matrix.constructor.diagonal_matrix(A.diagonal()) return A == D -class FreeQuadraticModule_generic_pid( - free_module.FreeModule_generic_pid, FreeQuadraticModule_generic): +class FreeQuadraticModule_generic_pid(free_module.FreeModule_generic_pid, + FreeQuadraticModule_generic): """ Class of all free modules over a PID. """ @@ -589,16 +598,17 @@ def __init__(self, base_ring, rank, degree, inner_product_matrix, sparse=False): """ free_module.FreeModule_generic_pid.__init__( self, base_ring=base_ring, rank=rank, degree=degree, sparse=sparse) - #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix self._inner_product_matrix = inner_product_matrix def span(self, gens, check=True, already_echelonized=False): """ - Return the R-span of the given list of gens, where R - is the base ring of self. Note that this span need not - be a submodule of self, nor even of the ambient space. - It must, however, be contained in the ambient vector space, i.e., - the ambient space tensored with the fraction field of R. + Return the `R`-span of the given list of gens, where `R` + is the base ring of ``self``. + + Note that this span need not be a submodule of ``self``, nor even + of the ambient space. It must, however, be contained in the + ambient vector space, i.e., the ambient space tensored with + the fraction field of `R`. EXAMPLES:: @@ -619,11 +629,13 @@ def span(self, gens, check=True, already_echelonized=False): def span_of_basis(self, basis, check=True, already_echelonized=False): r""" - Return the free R-module with the given basis, where R - is the base ring of self. Note that this R-module need not - be a submodule of self, nor even of the ambient space. It - must, however, be contained in the ambient vector space, i.e., - the ambient space tensored with the fraction field of R. + Return the free `R`-module with the given basis, where `R` + is the base ring of ``self``. + + Note that this `R`-module need not be a submodule of ``self``, nor + even of the ambient space. It must, however, be contained in + the ambient vector space, i.e., the ambient space tensored + with the fraction field of `R`. EXAMPLES:: @@ -673,14 +685,15 @@ def zero_submodule(self): return FreeQuadraticModule_submodule_pid( self.ambient_module(), [], self.inner_product_matrix(), check=False) -class FreeQuadraticModule_generic_field( - free_module.FreeModule_generic_field, FreeQuadraticModule_generic_pid): + +class FreeQuadraticModule_generic_field(free_module.FreeModule_generic_field, + FreeQuadraticModule_generic_pid): """ Base class for all free modules over fields. """ def __init__(self, base_field, dimension, degree, inner_product_matrix, sparse=False): """ - Creates a vector space over a field. + Create a vector space over a field. EXAMPLES:: @@ -701,26 +714,27 @@ def __init__(self, base_field, dimension, degree, inner_product_matrix, sparse=F [0 0 0 0 0 0 1] """ if not isinstance(base_field, ring.Field): - raise TypeError("The base_field (=%s) must be a field" % base_field) + raise TypeError("the base_field (=%s) must be a field" % base_field) free_module.FreeModule_generic_field.__init__( self, base_field=base_field, dimension=dimension, degree=degree, sparse=sparse) - #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix self._inner_product_matrix = inner_product_matrix def span(self, gens, check=True, already_echelonized=False): """ - Return the K-span of the given list of gens, where K is the - base field of self. Note that this span is a subspace of the - ambient vector space, but need not be a subspace of self. + Return the `K`-span of the given list of gens, where `K` is the + base field of ``self``. + + Note that this span is a subspace of the ambient vector space, + but need not be a subspace of ``self``. INPUT: - - gens -- list of vectors + - ``gens`` -- list of vectors - - check -- bool (default: True): whether or not to coerce + - ``check`` -- bool (default: ``True``): whether or not to coerce entries of gens into base field - - already_echelonized -- bool (default: False): set this if + - ``already_echelonized`` -- bool (default: ``False``): set this if you know the gens are already in echelon form EXAMPLES:: @@ -738,7 +752,7 @@ def span(self, gens, check=True, already_echelonized=False): if free_module.is_FreeModule(gens): gens = gens.gens() if not isinstance(gens, (list, tuple)): - raise TypeError("gens (=%s) must be a list or tuple"%gens) + raise TypeError("gens (=%s) must be a list or tuple" % gens) return FreeQuadraticModule_submodule_field( self.ambient_module(), gens, @@ -747,19 +761,20 @@ def span(self, gens, check=True, already_echelonized=False): def span_of_basis(self, basis, check=True, already_echelonized=False): r""" - Return the free K-module with the given basis, where K - is the base field of self. Note that this span is - a subspace of the ambient vector space, but need - not be a subspace of self. + Return the free `K`-module with the given basis, where `K` + is the base field of ``self``. + + Note that this span is a subspace of the ambient vector space, + but need not be a subspace of ``self``. INPUT: - - basis -- list of vectors + - ``basis`` -- list of vectors - - check -- bool (default: True): whether or not to coerce + - ``check`` -- bool (default: ``True``): whether or not to coerce entries of gens into base field - - already_echelonized -- bool (default: False): set this if + - ``already_echelonized`` -- bool (default: ``False``): set this if you know the gens are already in echelon form EXAMPLES:: @@ -788,40 +803,39 @@ def span_of_basis(self, basis, check=True, already_echelonized=False): inner_product_matrix=self.inner_product_matrix(), check=check, already_echelonized=already_echelonized) -############################################################################### + +# ############################################################################# # # Generic ambient free modules, i.e., of the form R^n for some commutative ring R. # -############################################################################### +# ############################################################################# -class FreeQuadraticModule_ambient( - free_module.FreeModule_ambient, FreeQuadraticModule_generic): +class FreeQuadraticModule_ambient(free_module.FreeModule_ambient, + FreeQuadraticModule_generic): """ Ambient free module over a commutative ring. """ def __init__(self, base_ring, rank, inner_product_matrix, sparse=False): """ - The free module of given rank over the given base_ring. + The free module of given rank over the given ``base_ring``. INPUT: - - base_ring -- a commutative ring + - ``base_ring`` -- a commutative ring - - rank -- a non-negative integer + - ``rank`` -- a non-negative integer EXAMPLES:: sage: FreeModule(ZZ, 4) Ambient free module of rank 4 over the principal ideal domain Integer Ring - """ free_module.FreeModule_ambient.__init__(self, base_ring=base_ring, rank=rank, sparse=sparse) - #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix self._inner_product_matrix = inner_product_matrix def _repr_(self): """ - The printing representation of self. + The printing representation of ``self``. EXAMPLES:: @@ -848,11 +862,10 @@ def _repr_(self): Ambient sparse free module of rank 12 over Ring of integers modulo 12 """ if self.is_sparse(): - return "Ambient sparse free quadratic module of rank %s over %s\n" % ( self.rank(), self.base_ring() ) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() - else: - return "Ambient free quadratic module of rank %s over %s\n" % ( self.rank(), self.base_ring() ) + \ + return "Ambient sparse free quadratic module of rank %s over %s\n" % (self.rank(), self.base_ring()) + \ "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient free quadratic module of rank %s over %s\n" % (self.rank(), self.base_ring()) + \ + "Inner product matrix:\n%s" % self.inner_product_matrix() def _latex_(self): r""" @@ -871,16 +884,18 @@ def _latex_(self): sage: V = QuadraticSpace(QQ,3,inner_product_matrix=[[2,1,0],[1,4,1],[0,1,8]]) sage: latex(V) - None + Traceback (most recent call last): + ... + NotImplementedError """ # How do we want to represent this object? - NotImplementedError + raise NotImplementedError def _dense_module(self): """ - Creates a dense module with the same defining data as self. + Create a dense module with the same defining data as ``self``. - N.B. This function is for internal use only! See dense_module for use. + .. NOTE:: This function is for internal use only! See dense_module for use. EXAMPLES:: @@ -890,14 +905,15 @@ def _dense_module(self): sage: M is S._dense_module() True """ - return FreeQuadraticModule(base_ring=self.base_ring(), rank = self.rank(), - inner_product_matrix = self.inner_product_matrix(), sparse=False) + return FreeQuadraticModule(base_ring=self.base_ring(), rank=self.rank(), + inner_product_matrix=self.inner_product_matrix(), + sparse=False) def _sparse_module(self): """ - Creates a sparse module with the same defining data as self. + Create a sparse module with the same defining data as ``self``. - N.B. This function is for internal use only! See sparse_module for use. + .. NOTE:: This function is for internal use only! See sparse_module for use. EXAMPLES:: @@ -907,17 +923,19 @@ def _sparse_module(self): sage: M._sparse_module() is S True """ - return FreeQuadraticModule(base_ring = self.base_ring(), rank = self.rank(), - inner_product_matrix = self.inner_product_matrix(), sparse=True) + return FreeQuadraticModule(base_ring=self.base_ring(), rank=self.rank(), + inner_product_matrix=self.inner_product_matrix(), + sparse=True) -############################################################################### + +# ############################################################################# # # Ambient free modules over an integral domain. # -############################################################################### +# ############################################################################# -class FreeQuadraticModule_ambient_domain( - free_module.FreeModule_ambient_domain, FreeQuadraticModule_ambient): +class FreeQuadraticModule_ambient_domain(free_module.FreeModule_ambient_domain, + FreeQuadraticModule_ambient): """ Ambient free quadratic module over an integral domain. """ @@ -930,12 +948,11 @@ def __init__(self, base_ring, rank, inner_product_matrix, sparse=False): Univariate Polynomial Ring in x over Finite Field of size 5 """ free_module.FreeModule_ambient.__init__(self, base_ring=base_ring, rank=rank, sparse=sparse) - #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix self._inner_product_matrix = inner_product_matrix def _repr_(self): """ - The printing representation of self. + The printing representation of ``self``. EXAMPLES:: @@ -975,17 +992,16 @@ def _repr_(self): -b^2 + 4*a*c """ if self.is_sparse(): - return "Ambient sparse free quadratic module of rank %s over the integral domain %s\n"%( - self.rank(), self.base_ring() ) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() - else: - return "Ambient free quadratic module of rank %s over the integral domain %s\n"%( - self.rank(), self.base_ring() ) + \ + return "Ambient sparse free quadratic module of rank %s over the integral domain %s\n" % ( + self.rank(), self.base_ring()) + \ "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient free quadratic module of rank %s over the integral domain %s\n" % ( + self.rank(), self.base_ring()) + \ + "Inner product matrix:\n%s" % self.inner_product_matrix() def ambient_vector_space(self): """ - Returns the ambient vector space, which is this free module tensored + Return the ambient vector space, which is this free module tensored with its fraction field. EXAMPLES:: @@ -1001,31 +1017,33 @@ def ambient_vector_space(self): inner_product_matrix=self.inner_product_matrix(), sparse=self.is_sparse()) return self.__ambient_vector_space -############################################################################### + +# ############################################################################# # # Ambient free modules over a principal ideal domain. # -############################################################################### +# ############################################################################# -class FreeQuadraticModule_ambient_pid( - free_module.FreeModule_ambient_pid, FreeQuadraticModule_generic_pid, FreeQuadraticModule_ambient_domain): +class FreeQuadraticModule_ambient_pid(free_module.FreeModule_ambient_pid, + FreeQuadraticModule_generic_pid, + FreeQuadraticModule_ambient_domain): """ Ambient free quadratic module over a principal ideal domain. """ def __init__(self, base_ring, rank, inner_product_matrix, sparse=False): """ Create the ambient free module of given rank over the given - principal ideal domain + principal ideal domain. INPUT: - - base_ring -- a principal ideal domain + - ``base_ring`` -- a principal ideal domain - - rank -- a non-negative integer + - ``rank`` -- a non-negative integer - - sparse -- bool (default: False) + - ``sparse`` -- bool (default: ``False``) - - inner_product_matrix -- bool (default: None) + - ``inner_product_matrix`` -- bool (default: ``None``) EXAMPLES:: @@ -1039,12 +1057,11 @@ def __init__(self, base_ring, rank, inner_product_matrix, sparse=False): [ 0 -1 2] """ free_module.FreeModule_ambient_pid.__init__(self, base_ring=base_ring, rank=rank, sparse=sparse) - #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix self._inner_product_matrix = inner_product_matrix def _repr_(self): """ - The printing representation of self. + The printing representation of ``self``. EXAMPLES:: @@ -1078,26 +1095,25 @@ def _repr_(self): sage: N = FreeModule(ZZ,7,sparse=True) sage: N Ambient sparse free module of rank 7 over the principal ideal domain Integer Ring - """ if self.is_sparse(): - return "Ambient sparse free quadratic module of rank %s over the principal ideal domain %s\n"%( - self.rank(), self.base_ring() ) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() - else: - return "Ambient free quadratic module of rank %s over the principal ideal domain %s\n"%( + return "Ambient sparse free quadratic module of rank %s over the principal ideal domain %s\n" % ( self.rank(), self.base_ring()) + \ "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient free quadratic module of rank %s over the principal ideal domain %s\n" % ( + self.rank(), self.base_ring()) + \ + "Inner product matrix:\n%s" % self.inner_product_matrix() + -############################################################################### +# ############################################################################# # # Ambient free modules over a field (i.e., a vector space). # -############################################################################### +# ############################################################################# -class FreeQuadraticModule_ambient_field( - free_module.FreeModule_ambient_field, - FreeQuadraticModule_generic_field, FreeQuadraticModule_ambient_pid): +class FreeQuadraticModule_ambient_field(free_module.FreeModule_ambient_field, + FreeQuadraticModule_generic_field, + FreeQuadraticModule_ambient_pid): def __init__(self, base_field, dimension, inner_product_matrix, sparse=False): """ @@ -1105,11 +1121,11 @@ def __init__(self, base_field, dimension, inner_product_matrix, sparse=False): INPUT: - - base_field -- a field + - ``base_field`` -- a field - - dimension -- a non-negative integer + - ``dimension`` -- a non-negative integer - - sparse -- bool (default: False) + - ``sparse`` -- bool (default: ``False``) EXAMPLES:: @@ -1135,12 +1151,11 @@ def __init__(self, base_field, dimension, inner_product_matrix, sparse=False): """ free_module.FreeModule_ambient_field.__init__( self, base_field=base_field, dimension=dimension, sparse=sparse) - #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix self._inner_product_matrix = inner_product_matrix def _repr_(self): """ - The printing representation of self. + The printing representation of ``self``. EXAMPLES:: @@ -1166,21 +1181,21 @@ def _repr_(self): Sparse vector space of dimension 7 over Rational Field """ if self.is_sparse(): - return "Ambient sparse free quadratic space of dimension %s over %s\n" % ( self.rank(), self.base_ring() ) + \ - "Inner product matrix:\n%s" % self.inner_product_matrix() - else: - return "Ambient quadratic space of dimension %s over %s\n" % ( self.rank(), self.base_ring() ) + \ + return "Ambient sparse free quadratic space of dimension %s over %s\n" % (self.rank(), self.base_ring()) + \ "Inner product matrix:\n%s" % self.inner_product_matrix() + return "Ambient quadratic space of dimension %s over %s\n" % (self.rank(), self.base_ring()) + \ + "Inner product matrix:\n%s" % self.inner_product_matrix() + -############################################################################### +# ############################################################################# # # R-Submodule of K^n where K is the fraction field of a principal ideal domain R. # -############################################################################### +# ############################################################################# -class FreeQuadraticModule_submodule_with_basis_pid( - free_module.FreeModule_submodule_with_basis_pid, FreeQuadraticModule_generic_pid): +class FreeQuadraticModule_submodule_with_basis_pid(free_module.FreeModule_submodule_with_basis_pid, + FreeQuadraticModule_generic_pid): r""" An `R`-submodule of `K^n` with distinguished basis, where `K` is the fraction field of a principal ideal domain `R`. @@ -1218,7 +1233,8 @@ class FreeQuadraticModule_submodule_with_basis_pid( False """ def __init__(self, ambient, basis, inner_product_matrix, - check=True, echelonize=False, echelonized_basis=None, already_echelonized=False): + check=True, echelonize=False, echelonized_basis=None, + already_echelonized=False): """ Create a free module with basis over a PID. @@ -1250,21 +1266,20 @@ def __init__(self, ambient, basis, inner_product_matrix, We test that :trac:`23703` is fixed:: - sage: A=FreeQuadraticModule(ZZ,1,matrix.identity(1)) - sage: B=A.span([[1/2]]) - sage: C=B.span([[1]]) - sage: B.intersection(C)==C.intersection(B) + sage: A = FreeQuadraticModule(ZZ, 1, matrix.identity(1)) + sage: B = A.span([[1/2]]) + sage: C = B.span([[1]]) + sage: B.intersection(C) == C.intersection(B) True """ free_module.FreeModule_submodule_with_basis_pid.__init__( self, ambient=ambient, basis=basis, check=check, echelonize=echelonize, echelonized_basis=echelonized_basis, already_echelonized=already_echelonized) - #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix self._inner_product_matrix = inner_product_matrix def _repr_(self): """ - The printing representation of self. + The printing representation of ``self``. EXAMPLES:: @@ -1295,12 +1310,12 @@ def _repr_(self): [-1 0 0 0 0 0 0 1] """ if self.is_sparse(): - s = "Sparse free quadratic module of degree %s and rank %s over %s\n"%( + s = "Sparse free quadratic module of degree %s and rank %s over %s\n" % ( self.degree(), self.rank(), self.base_ring()) + \ "Basis matrix:\n%r\n" % self.basis_matrix() + \ "Inner product matrix:\n%r" % self.inner_product_matrix() else: - s = "Free quadratic module of degree %s and rank %s over %s\n"%( + s = "Free quadratic module of degree %s and rank %s over %s\n" % ( self.degree(), self.rank(), self.base_ring()) + \ "Basis matrix:\n%r\n" % self.basis_matrix() + \ "Inner product matrix:\n%r" % self.inner_product_matrix() @@ -1317,14 +1332,16 @@ def _latex_(self): sage: M._latex_() '\\mathrm{RowSpan}_{\\Bold{Z}}\\left(\\begin{array}{rrr}\n1 & 2 & 3 \\\\\n4 & 5 & 6\n\\end{array}\\right)' """ - return "\\mathrm{RowSpan}_{%s}%s"%(latex.latex(self.base_ring()), latex.latex(self.basis_matrix())) + return "\\mathrm{RowSpan}_{%s}%s" % (latex.latex(self.base_ring()), + latex.latex(self.basis_matrix())) def change_ring(self, R): """ - Return the free module over R obtained by coercing each - element of self into a vector over the fraction field of R, - then taking the resulting R-module. Raises a TypeError - if coercion is not possible. + Return the free module over `R` obtained by coercing each + element of ``self`` into a vector over the fraction field of `R`, + then taking the resulting `R`-module. + + This raises a ``TypeError`` if coercion is not possible. INPUT: @@ -1358,15 +1375,15 @@ def change_ring(self, R): K = R.fraction_field() A = self.inner_product_matrix() V = QuadraticSpace(K, self.degree(), inner_product_matrix=A) - B = [ V(b) for b in self.basis() ] + B = [V(b) for b in self.basis()] M = FreeQuadraticModule(R, self.degree(), inner_product_matrix=A) if self.has_user_basis(): return M.span_of_basis(B) - else: - return M.span(B) + return M.span(B) -class FreeQuadraticModule_submodule_pid( - free_module.FreeModule_submodule_pid, FreeQuadraticModule_submodule_with_basis_pid): + +class FreeQuadraticModule_submodule_pid(free_module.FreeModule_submodule_pid, + FreeQuadraticModule_submodule_with_basis_pid): """ An `R`-submodule of `K^n` where `K` is the fraction field of a principal ideal domain `R`. @@ -1404,12 +1421,11 @@ def __init__(self, ambient, gens, inner_product_matrix, check=True, already_eche """ free_module.FreeModule_submodule_pid.__init__( self, ambient=ambient, gens=gens, check=check, already_echelonized=already_echelonized) - #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix self._inner_product_matrix = inner_product_matrix def _repr_(self): """ - The printing representation of self. + The printing representation of ``self``. EXAMPLES:: @@ -1427,18 +1443,19 @@ def _repr_(self): [ 0 0 0 0 0 0 1 -1] """ if self.is_sparse(): - s = "Sparse free module of degree %s and rank %s over %s\n"%( + s = "Sparse free module of degree %s and rank %s over %s\n" % ( self.degree(), self.rank(), self.base_ring()) + \ - "Echelon basis matrix:\n%s"%self.basis_matrix() + "Echelon basis matrix:\n%s" % self.basis_matrix() else: - s = "Free module of degree %s and rank %s over %s\n"%( + s = "Free module of degree %s and rank %s over %s\n" % ( self.degree(), self.rank(), self.base_ring()) + \ - "Echelon basis matrix:\n%s"%self.basis_matrix() + "Echelon basis matrix:\n%s" % self.basis_matrix() return s -class FreeQuadraticModule_submodule_with_basis_field( - free_module.FreeModule_submodule_with_basis_field, - FreeQuadraticModule_generic_field, FreeQuadraticModule_submodule_with_basis_pid): + +class FreeQuadraticModule_submodule_with_basis_field(free_module.FreeModule_submodule_with_basis_field, + FreeQuadraticModule_generic_field, + FreeQuadraticModule_submodule_with_basis_pid): """ An embedded vector subspace with a distinguished user basis. @@ -1512,12 +1529,11 @@ def __init__(self, ambient, basis, inner_product_matrix, free_module.FreeModule_submodule_with_basis_field.__init__( self, ambient=ambient, basis=basis, check=check, echelonize=echelonize, echelonized_basis=echelonized_basis, already_echelonized=already_echelonized) - #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix self._inner_product_matrix = inner_product_matrix def _repr_(self): """ - The printing representation of self. + The printing representation of ``self``. EXAMPLES:: @@ -1565,25 +1581,26 @@ def _repr_(self): [ 0 0 0 1 -1] """ if self.is_sparse(): - return "Sparse quadratic space of degree %s and dimension %s over %s\n"%( - self.degree(), self.dimension(), self.base_field()) + \ - "Basis matrix:\n%r" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() - else: - return "Quadratic space of degree %s and dimension %s over %s\n"%( - self.degree(), self.dimension(), self.base_field()) + \ - "Basis matrix:\n%r\n" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() + return "Sparse quadratic space of degree %s and dimension %s over %s\n" % ( + self.degree(), self.dimension(), self.base_field()) + \ + "Basis matrix:\n%r" % self.basis_matrix() + \ + "Inner product matrix:\n%r" % self.inner_product_matrix() + return "Quadratic space of degree %s and dimension %s over %s\n" % ( + self.degree(), self.dimension(), self.base_field()) + \ + "Basis matrix:\n%r\n" % self.basis_matrix() + \ + "Inner product matrix:\n%r" % self.inner_product_matrix() -class FreeQuadraticModule_submodule_field( - free_module.FreeModule_submodule_field, FreeQuadraticModule_submodule_with_basis_field): + +class FreeQuadraticModule_submodule_field(free_module.FreeModule_submodule_field, + FreeQuadraticModule_submodule_with_basis_field): """ An embedded vector subspace with echelonized basis. EXAMPLES: Since this is an embedded vector subspace with echelonized basis, - the echelon_coordinates() and user coordinates() agree:: + the methods :meth:`echelon_coordinates` and :meth:`coordinates` return the same + coordinates:: sage: V = QQ^3 sage: W = V.span([[1,2,3],[4,5,6]]) @@ -1621,12 +1638,11 @@ def __init__(self, ambient, gens, inner_product_matrix, check=True, already_eche """ free_module.FreeModule_submodule_field.__init__( self, ambient=ambient, gens=gens, check=check, already_echelonized=already_echelonized) - #self._FreeQuadraticModule_generic_inner_product_matrix = inner_product_matrix self._inner_product_matrix = inner_product_matrix def _repr_(self): """ - The default printing representation of self. + The default printing representation of ``self``. EXAMPLES:: @@ -1674,29 +1690,11 @@ def _repr_(self): [ 0 0 0 1 -1] """ if self.is_sparse(): - return "Sparse quadratic space of degree %s and dimension %s over %s\n"%( - self.degree(), self.dimension(), self.base_field()) + \ - "Basis matrix:\n%r\n" % self.basis_matrix() + \ - "Inner product matrix:\n%r" % self.inner_product_matrix() - else: - return "Quadratic space of degree %s and dimension %s over %s\n"%( + return "Sparse quadratic space of degree %s and dimension %s over %s\n" % ( self.degree(), self.dimension(), self.base_field()) + \ "Basis matrix:\n%r\n" % self.basis_matrix() + \ "Inner product matrix:\n%r" % self.inner_product_matrix() - -#class RealDoubleQuadraticSpace_class(free_module.RealDoubleVectorSpace_class, FreeQuadraticModule_ambient_field): -# def __init__(self, dimension, inner_product_matrix, sparse=False): -# if sparse: -# raise NotImplementedError, "Sparse matrices over RDF not implemented yet" -# free_module.RealDoubleVectorSpace_class.__init__(self, dimension=dimension, sparse=False) -# self._inner_product_matrix = inner_product_matrix - -#class ComplexDoubleQuadraticSpace_class( -# free_module.ComplexDoubleVectorSpace_class, FreeQuadraticModule_generic): #FreeQuadraticModule_ambient_field): -# def __init__(self, dimension, inner_product_matrix, sparse=False): -# if sparse: -# raise NotImplementedError, "Sparse matrices over CDF not implemented yet" -# free_module.ComplexDoubleVectorSpace_class.__init__(self, dimension=dimension, sparse=False) -# self._inner_product_matrix = inner_product_matrix - -###################################################### + return "Quadratic space of degree %s and dimension %s over %s\n" % ( + self.degree(), self.dimension(), self.base_field()) + \ + "Basis matrix:\n%r\n" % self.basis_matrix() + \ + "Inner product matrix:\n%r" % self.inner_product_matrix() diff --git a/src/sage/modules/module.pyx b/src/sage/modules/module.pyx index 3b6875ce0d1..9d76034a926 100644 --- a/src/sage/modules/module.pyx +++ b/src/sage/modules/module.pyx @@ -302,5 +302,3 @@ def is_VectorSpace(x): return is_Module(x) and x.base_ring().is_field() except AttributeError: return False - - diff --git a/src/sage/modules/module_functors.py b/src/sage/modules/module_functors.py index 5e84c79008d..c3977183c56 100644 --- a/src/sage/modules/module_functors.py +++ b/src/sage/modules/module_functors.py @@ -7,7 +7,7 @@ :class:`QuotientModuleFunctor` """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Travis Scrimshaw # # This program is free software: you can redistribute it and/or modify @@ -15,8 +15,8 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** - +# **************************************************************************** + ############################################################## # Construction functor for quotient modules ############################################################## @@ -24,6 +24,7 @@ from sage.categories.pushout import ConstructionFunctor from sage.categories.modules import Modules + class QuotientModuleFunctor(ConstructionFunctor): r""" Construct the quotient of a module by a submodule. @@ -48,9 +49,9 @@ class QuotientModuleFunctor(ConstructionFunctor): QuotientModuleFunctor sage: F(A) == Q True - + The modules are constructed from the cover not the ambient module:: - + sage: F(B.ambient_module()) == Q False @@ -75,7 +76,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 +188,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/vector_complex_double_dense.pyx b/src/sage/modules/vector_complex_double_dense.pyx index cee4f2f7970..43f3322d627 100644 --- a/src/sage/modules/vector_complex_double_dense.pyx +++ b/src/sage/modules/vector_complex_double_dense.pyx @@ -113,5 +113,3 @@ def unpickle_v1(parent, entries, degree, is_mutable=None): if is_mutable is not None: v._is_immutable = not is_mutable return v - - diff --git a/src/sage/modules/vector_integer_sparse.pyx b/src/sage/modules/vector_integer_sparse.pyx index 01c45059880..de91aab408e 100644 --- a/src/sage/modules/vector_integer_sparse.pyx +++ b/src/sage/modules/vector_integer_sparse.pyx @@ -402,4 +402,3 @@ cdef int mpz_vector_cmp(mpz_vector* v, mpz_vector* w): elif c > 0: return 1 return 0 - diff --git a/src/sage/modules/vector_mod2_dense.pyx b/src/sage/modules/vector_mod2_dense.pyx index 4798810c886..9d57897febe 100644 --- a/src/sage/modules/vector_mod2_dense.pyx +++ b/src/sage/modules/vector_mod2_dense.pyx @@ -512,4 +512,3 @@ def unpickle_v0(parent, entries, degree, is_immutable): mzd_write_bit(v._entries, 0, i, entries[i]%2) v._is_immutable = int(is_immutable) return v - diff --git a/src/sage/modules/vector_rational_sparse.pyx b/src/sage/modules/vector_rational_sparse.pyx index 78002a1a75f..14d0953b3df 100644 --- a/src/sage/modules/vector_rational_sparse.pyx +++ b/src/sage/modules/vector_rational_sparse.pyx @@ -409,4 +409,3 @@ cdef int mpq_vector_cmp(mpq_vector* v, mpq_vector* w): elif c > 0: return 1 return 0 - 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/invariant.py b/src/sage/modules/with_basis/invariant.py index 33af946e8a0..12565a411e2 100644 --- a/src/sage/modules/with_basis/invariant.py +++ b/src/sage/modules/with_basis/invariant.py @@ -22,6 +22,7 @@ from sage.sets.family import Family from sage.matrix.constructor import Matrix + class FiniteDimensionalInvariantModule(SubmoduleWithBasis): r""" The invariant submodule under a semigroup action. @@ -65,7 +66,7 @@ class FiniteDimensionalInvariantModule(SubmoduleWithBasis): sage: [I.lift(b) for b in I.basis()] [M[1] + M[2] + M[3]] - + The we could also have the action be a right-action, instead of the default left-action:: 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/arc.py b/src/sage/plot/arc.py index bb834763afc..f65973bcbd5 100644 --- a/src/sage/plot/arc.py +++ b/src/sage/plot/arc.py @@ -273,9 +273,9 @@ def _matplotlib_arc(self): p = patches.Arc((self.x, self.y), 2. * self.r1, 2. * self.r2, - fmod(self.angle, 2 * pi) * (180. / pi), - self.s1 * (180. / pi), - self.s2 * (180. / pi)) + angle=fmod(self.angle, 2 * pi) * (180. / pi), + theta1=self.s1 * (180. / pi), + theta2=self.s2 * (180. / pi)) return p def bezier_path(self): 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/ellipse.py b/src/sage/plot/ellipse.py index a77e6fe640a..c35bed574ef 100644 --- a/src/sage/plot/ellipse.py +++ b/src/sage/plot/ellipse.py @@ -192,7 +192,8 @@ def _render_on_subplot(self, subplot): options = self.options() p = patches.Ellipse( (self.x,self.y), - self.r1*2.,self.r2*2.,self.angle/pi*180.) + self.r1*2.,self.r2*2., + angle=self.angle/pi*180.) p.set_linewidth(float(options['thickness'])) p.set_fill(options['fill']) a = float(options['alpha']) diff --git a/src/sage/plot/graphics.py b/src/sage/plot/graphics.py index 0d881b235f7..18805e15c42 100644 --- a/src/sage/plot/graphics.py +++ b/src/sage/plot/graphics.py @@ -2007,7 +2007,7 @@ def show(self, **kwds): We can also do custom formatting if you need it. See above for full details:: - sage: plot(2*x+1,(x,0,5),ticks=[[0,1,e,pi,sqrt(20)],2],tick_formatter="latex") + sage: plot(2*x+1,(x,0,5),ticks=[[0,1,e,pi,sqrt(20)],2],tick_formatter="latex") # not tested (broken with matplotlib 3.6) Graphics object consisting of 1 graphics primitive This is particularly useful when setting custom ticks in multiples @@ -2341,7 +2341,7 @@ def _matplotlib_tick_formatter(self, subplot, base=(10, 10), sage: subplot = Figure().add_subplot(111) sage: p._objects[0]._render_on_subplot(subplot) sage: p._matplotlib_tick_formatter(subplot, **d) - (, + (, , , , 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..5301a05c3dc 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. @@ -1741,7 +1741,7 @@ def b(n): return lambda x: bessel_J(n, x) + 0.5*(n-1) :: - sage: plot(2*x+1,(x,0,5),ticks=[[0,1,e,pi,sqrt(20)],2],tick_formatter="latex") + sage: plot(2*x+1,(x,0,5),ticks=[[0,1,e,pi,sqrt(20)],2],tick_formatter="latex") # not tested (broken with matplotlib 3.6) Graphics object consisting of 1 graphics primitive .. PLOT:: 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 12a4a500f85..3aa99e168ee 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:: @@ -1301,7 +1301,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): sage: @interact ....: def _(which_plot=[A,B,C,D,E]): ....: show(which_plot) - Interactive function with 1 widget + ...Interactive function with 1 widget which_plot: Dropdown(description='which_plot', options=(Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object), value=Graphics3d Object) Now plot a function:: @@ -1315,7 +1315,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): sage: @interact ....: def _(which_plot=[F, G, H, I, J]): ....: show(which_plot) - Interactive function with 1 widget + ...Interactive function with 1 widget which_plot: Dropdown(description='which_plot', options=(Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object, Graphics3d Object), value=Graphics3d Object) TESTS: 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..299ea0ee25c 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 @@ -264,4 +266,3 @@ def rotate_arbitrary(v, double theta): (1 - cos_t)*z*z + cos_t ] return matrix(RDF, 3, 3, entries) - 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/quadratic_forms/genera/normal_form.py b/src/sage/quadratic_forms/genera/normal_form.py index 4744e3d079e..e9611fc5666 100644 --- a/src/sage/quadratic_forms/genera/normal_form.py +++ b/src/sage/quadratic_forms/genera/normal_form.py @@ -120,7 +120,7 @@ def collect_small_blocks(G): L = _get_small_block_indices(D)[1:] D.subdivide(L, L) blocks = [] - for i in range(len(L)+1): + for i in range(len(L) + 1): block = copy(D.subdivision(i, i)) blocks.append(block) return blocks @@ -246,11 +246,11 @@ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False): d = denom.valuation(p) r = G0.rank() if r != G0.ncols(): - U = G0.hermite_form(transformation=True)[1] + U = G0.hermite_form(transformation=True)[1] else: U = G0.parent().identity_matrix() - kernel = U[r:,:] - nondeg = U[:r,:] + kernel = U[r:, :] + nondeg = U[:r, :] # continue with the non-degenerate part G = nondeg * G * nondeg.T * p**d @@ -282,10 +282,10 @@ def p_adic_normal_form(G, p, precision=None, partial=False, debug=False): if debug: assert B.determinant().valuation() == 0 # B is invertible! if p == 2: - assert B*G*B.T == Matrix.block_diagonal(collect_small_blocks(D)) + assert B * G * B.T == Matrix.block_diagonal(collect_small_blocks(D)) else: - assert B*G*B.T == Matrix.diagonal(D.diagonal()) - return D/p**d, B + assert B * G * B.T == Matrix.diagonal(D.diagonal()) + return D / p**d, B def _find_min_p(G, cnt, lower_bound=0): @@ -338,7 +338,7 @@ def _find_min_p(G, cnt, lower_bound=0): minval = v # off diagonal for i in range(cnt, n): - for j in range(i+1, n): + for j in range(i + 1, n): v = G[i, j].valuation() if v == lower_bound: return lower_bound, i, j @@ -375,16 +375,17 @@ def _get_small_block_indices(G): L = [] n = G.ncols() i = 0 - while i < n-1: + while i < n - 1: L.append(i) - if G[i, i+1]!=0: + if G[i, i + 1] != 0: i += 2 else: i += 1 - if i == n-1: + if i == n - 1: L.append(i) return L[:] + def _get_homogeneous_block_indices(G): r""" Return the indices of the homogeneous blocks. @@ -394,7 +395,7 @@ def _get_homogeneous_block_indices(G): INPUT: - - ``G`` - a block diagonal matrix over the p-adics + - ``G`` -- a block diagonal matrix over the p-adics with blocks of size at most `2`. OUTPUT: @@ -418,26 +419,27 @@ def _get_homogeneous_block_indices(G): n = G.ncols() i = 0 val = -5 - while i < n-1: - if G[i,i+1] != 0: - m = G[i,i+1].valuation() + while i < n - 1: + if G[i, i + 1] != 0: + m = G[i, i + 1].valuation() else: - m = G[i,i].valuation() + m = G[i, i].valuation() if m > val: L.append(i) val = m vals.append(val) - if G[i, i+1] != 0: + if G[i, i + 1] != 0: i += 1 i += 1 - if i == n-1: - m = G[i,i].valuation() + if i == n - 1: + m = G[i, i].valuation() if m > val: L.append(i) val = m vals.append(val) return L, vals + def _homogeneous_normal_form(G, w): r""" Return the homogeneous normal form of the homogeneous ``G``. @@ -522,34 +524,35 @@ def _homogeneous_normal_form(G, w): D = copy(G) n = B.ncols() if w == 2: - if n>2 and D[-3,-3]!=0: + if n > 2 and D[-3, -3] != 0: v = 2 else: v = 0 - if v==2: - e1 = D[-2,-2].unit_part() - e2 = D[-1,-1].unit_part() + if v == 2: + e1 = D[-2, -2].unit_part() + e2 = D[-1, -1].unit_part() e = {e1, e2} - E = [{1,3}, {1,7}, {5,7}, {3,5}] + E = [{1, 3}, {1, 7}, {5, 7}, {3, 5}] if e not in E: - B[-4:,:] = _relations(D[-4:,-4:], 5) * B[-4:,:] + B[-4:, :] = _relations(D[-4:, -4:], 5) * B[-4:, :] D = B * G * B.T - e1 = D[-2,-2].unit_part() - e2 = D[-1,-1].unit_part() - e = {e1,e2} - E = [{3,3}, {3,5}, {5,5}, {5,7}] + e1 = D[-2, -2].unit_part() + e2 = D[-1, -1].unit_part() + e = {e1, e2} + E = [{3, 3}, {3, 5}, {5, 5}, {5, 7}] if e in E: - B[-2:,:] = _relations(D[-2:,-2:], 1) * B[-2:,:] + B[-2:, :] = _relations(D[-2:, -2:], 1) * B[-2:, :] D = B * G * B.T # assert that e1 < e2 - e1 = D[-2,-2].unit_part() - e2 = D[-1,-1].unit_part() + e1 = D[-2, -2].unit_part() + e2 = D[-1, -1].unit_part() if ZZ(e1) > ZZ(e2): - B.swap_rows(n-1, n-2) - D.swap_rows(n-1, n-2) - D.swap_columns(n-1, n-2) + B.swap_rows(n - 1, n - 2) + D.swap_rows(n - 1, n - 2) + D.swap_columns(n - 1, n - 2) return D, B + def _jordan_odd_adic(G): r""" Return the Jordan decomposition of a symmetric matrix over an odd prime. @@ -608,8 +611,8 @@ def _jordan_odd_adic(G): D.swap_columns(cnt, piv1) # we are already orthogonal to the part with i < cnt # now make the rest orthogonal too - for i in range(cnt+1,n): - if D[i, cnt]!= 0: + for i in range(cnt + 1, n): + if D[i, cnt] != 0: c = D[i, cnt] // D[cnt, cnt] B[i, :] += - c * B[cnt, :] D[i, :] += - c * D[cnt, :] @@ -680,55 +683,56 @@ def _jordan_2_adic(G): cnt = 0 minval = None while cnt < n: - pivot = _find_min_p(D, cnt) - piv1 = pivot[1] - piv2 = pivot[2] - minval = pivot[0] - # the smallest valuation is on the diagonal - if piv1 == piv2: - # move pivot to position [cnt,cnt] - if piv1 != cnt: - B.swap_rows(cnt, piv1) - D.swap_rows(cnt, piv1) - D.swap_columns(cnt, piv1) - # we are already orthogonal to the part with i < cnt - # now make the rest orthogonal too - for i in range(cnt+1, n): - if D[i, cnt] != 0: - c = D[i, cnt]//D[cnt, cnt] - B[i, :] += -c * B[cnt, :] - D[i, :] += -c * D[cnt, :] - D[:, i] += -c * D[:, cnt] - cnt = cnt + 1 - # the smallest valuation is off the diagonal - else: - # move this 2 x 2 block to the top left (starting from cnt) - if piv1 != cnt: - B.swap_rows(cnt, piv1) - D.swap_rows(cnt, piv1) - D.swap_columns(cnt, piv1) - if piv2 != cnt+1: - B.swap_rows(cnt+1, piv2) - D.swap_rows(cnt+1, piv2) - D.swap_columns(cnt+1, piv2) - # we split off a 2 x 2 block - # if it is the last 2 x 2 block, there is nothing to do. - if cnt != n-2: - content = R(2 ** minval) - eqn_mat = D[cnt:cnt+2, cnt:cnt+2].list() - eqn_mat = Matrix(R, 2, 2, [e // content for e in eqn_mat]) - # calculate the inverse without using division - inv = eqn_mat.adjugate() * eqn_mat.det().inverse_of_unit() - B1 = B[cnt:cnt+2, :] - B2 = D[cnt+2:, cnt:cnt+2] * inv - for i in range(B2.nrows()): - for j in range(B2.ncols()): - B2[i, j]=B2[i, j] // content - B[cnt+2:, :] -= B2 * B1 - D[cnt:, cnt:] = B[cnt:, :] * G * B[cnt:, :].transpose() - cnt += 2 + pivot = _find_min_p(D, cnt) + piv1 = pivot[1] + piv2 = pivot[2] + minval = pivot[0] + # the smallest valuation is on the diagonal + if piv1 == piv2: + # move pivot to position [cnt,cnt] + if piv1 != cnt: + B.swap_rows(cnt, piv1) + D.swap_rows(cnt, piv1) + D.swap_columns(cnt, piv1) + # we are already orthogonal to the part with i < cnt + # now make the rest orthogonal too + for i in range(cnt + 1, n): + if D[i, cnt] != 0: + c = D[i, cnt] // D[cnt, cnt] + B[i, :] += -c * B[cnt, :] + D[i, :] += -c * D[cnt, :] + D[:, i] += -c * D[:, cnt] + cnt = cnt + 1 + # the smallest valuation is off the diagonal + else: + # move this 2 x 2 block to the top left (starting from cnt) + if piv1 != cnt: + B.swap_rows(cnt, piv1) + D.swap_rows(cnt, piv1) + D.swap_columns(cnt, piv1) + if piv2 != cnt + 1: + B.swap_rows(cnt + 1, piv2) + D.swap_rows(cnt + 1, piv2) + D.swap_columns(cnt + 1, piv2) + # we split off a 2 x 2 block + # if it is the last 2 x 2 block, there is nothing to do. + if cnt != n - 2: + content = R(2 ** minval) + eqn_mat = D[cnt:cnt+2, cnt:cnt+2].list() + eqn_mat = Matrix(R, 2, 2, [e // content for e in eqn_mat]) + # calculate the inverse without using division + inv = eqn_mat.adjugate() * eqn_mat.det().inverse_of_unit() + B1 = B[cnt:cnt+2, :] + B2 = D[cnt+2:, cnt:cnt+2] * inv + for i in range(B2.nrows()): + for j in range(B2.ncols()): + B2[i, j] = B2[i, j] // content + B[cnt + 2:, :] -= B2 * B1 + D[cnt:, cnt:] = B[cnt:, :] * G * B[cnt:, :].transpose() + cnt += 2 return D, B + def _min_nonsquare(p): r""" Return the minimal nonsquare modulo the prime `p`. @@ -752,11 +756,11 @@ def _min_nonsquare(p): sage: _min_nonsquare(7) 3 """ - R = GF(p) - for i in R: - if not R(i).is_square(): + for i in GF(p): + if not i.is_square(): return i + def _normalize(G, normal_odd=True): r""" Return the transformation to sums of forms of types `U`, `V` and `W`. @@ -805,14 +809,14 @@ def _normalize(G, normal_odd=True): non_squares = [] val = 0 for i in range(n): - if D[i,i].valuation() > val: + if D[i, i].valuation() > val: # a new block starts - val = D[i,i].valuation() + val = D[i, i].valuation() if normal_odd and len(non_squares) != 0: # move the non-square to # the last entry of the previous block j = non_squares.pop() - B.swap_rows(j, i-1) + B.swap_rows(j, i - 1) d = D[i, i].unit_part() if d.is_square(): D[i, i] = 1 @@ -824,15 +828,15 @@ def _normalize(G, normal_odd=True): # we combine two non-squares to get # the 2 x 2 identity matrix j = non_squares.pop() - trafo = _normalize_odd_2x2(D[[i,j],[i,j]]) - B[[i,j],:] = trafo*B[[i,j],:] - D[i,i] = 1 - D[j,j] = 1 + trafo = _normalize_odd_2x2(D[[i, j], [i, j]]) + B[[i, j], :] = trafo * B[[i, j], :] + D[i, i] = 1 + D[j, j] = 1 else: non_squares.append(i) - if normal_odd and len(non_squares) != 0: - j=non_squares.pop() - B.swap_rows(j,n-1) + if normal_odd and non_squares: + j = non_squares.pop() + B.swap_rows(j, n - 1) else: # squareclasses 1,3,5,7 modulo 8 for i in range(n): @@ -841,14 +845,15 @@ def _normalize(G, normal_odd=True): v = R(mod(d, 8)) B[i, :] *= (v * d.inverse_of_unit()).sqrt() D = B * G * B.T - for i in range(n-1): - if D[i, i+1] != 0: # there is a 2 x 2 block here + for i in range(n - 1): + if D[i, i + 1] != 0: # there is a 2 x 2 block here block = D[i:i+2, i:i+2] trafo = _normalize_2x2(block) B[i:i+2, :] = trafo * B[i:i+2, :] D = B * G * B.T return D, B + def _normalize_2x2(G): r""" Normalize this indecomposable `2` by `2` block. @@ -904,9 +909,9 @@ def _normalize_2x2(G): # The input must be an even block odd1 = (G[0, 0].valuation() < G[1, 0].valuation()) odd2 = (G[1, 1].valuation() < G[1, 0].valuation()) - if odd1 or odd2: - raise ValueError("Not a valid 2 x 2 block.") - scale = 2 ** G[0,1].valuation() + if odd1 or odd2: + raise ValueError("not a valid 2 x 2 block") + scale = 2 ** G[0, 1].valuation() D = Matrix(R, 2, 2, [d // scale for d in G.list()]) # now D is of the form # [2a b ] @@ -932,7 +937,7 @@ def _normalize_2x2(G): # 1 2 # Find a point of norm 2 # solve: 2 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0] - pol = (D[1,1]*x**2 + 2*D[1,0]*x + D[0,0]-2) // 2 + pol = (D[1, 1] * x**2 + 2 * D[1, 0] * x + D[0, 0] - 2) // 2 # somehow else pari can get a hickup see trac #24065 pol = pol // pol.leading_coefficient() sol = pol.roots()[0][0] @@ -944,35 +949,35 @@ def _normalize_2x2(G): # solve: v*D*v == 2 with v = (x, -2*x+1) if D[1, 1] != 2: - v = vector([x, -2*x + 1]) - pol = (v*D*v - 2) // 2 + v = vector([x, -2 * x + 1]) + pol = (v * D * v - 2) // 2 # somehow else pari can get a hickup see trac #24065 pol = pol // pol.leading_coefficient() sol = pol.roots()[0][0] - B[1, :] = sol * B[0,:] + (-2*sol + 1)*B[1, :] + B[1, :] = sol * B[0, :] + (-2 * sol + 1) * B[1, :] D = B * G * B.transpose() # check the result - assert D == Matrix(G.parent(), 2, 2, [2, 1, 1, 2]), "D1 \n %r" %D + assert D == Matrix(G.parent(), 2, 2, [2, 1, 1, 2]), "D1 \n %r" % D elif mod(D.det(), 8) == 7: # in this case we can transform D to # 0 1 # 1 0 # Find a point representing 0 # solve: 0 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0] - pol = (D[1,1]*x**2 + 2*D[1,0]*x + D[0,0])//2 + pol = (D[1, 1] * x**2 + 2 * D[1, 0] * x + D[0, 0]) // 2 # somehow else pari can get a hickup, see trac #24065 pol = pol // pol.leading_coefficient() sol = pol.roots()[0][0] - B[0,:] += sol*B[1, :] + B[0, :] += sol * B[1, :] D = B * G * B.transpose() # make the second basis vector have 0 square as well. - B[1, :] = B[1, :] - D[1, 1]//(2*D[0, 1])*B[0,:] + B[1, :] = B[1, :] - D[1, 1] // (2 * D[0, 1]) * B[0, :] D = B * G * B.transpose() # rescale to get D[0,1] = 1 B[0, :] *= D[1, 0].inverse_of_unit() D = B * G * B.transpose() # check the result - assert D == Matrix(G.parent(), 2, 2, [0, 1, 1, 0]), "D2 \n %r" %D + assert D == Matrix(G.parent(), 2, 2, [0, 1, 1, 0]), "D2 \n %r" % D return B @@ -1000,19 +1005,20 @@ def _normalize_odd_2x2(G): [1 0] [0 1] """ - assert G[0,0]==G[1,1] - u = G[0,0] + assert G[0, 0] == G[1, 1] + u = G[0, 0] y = G.base_ring().zero() - while not (1/u-y**2).is_square(): - y = y + 1 - x = (1/u-y**2).sqrt() + while not (1 / u - y**2).is_square(): + y += 1 + x = (1 / u - y**2).sqrt() B = copy(G.parent().identity_matrix()) - B[0,0] = x - B[0,1] = y - B[1,0] = y - B[1,1] = -x + B[0, 0] = x + B[0, 1] = y + B[1, 0] = y + B[1, 1] = -x return B + def _partial_normal_form_of_block(G): r""" Return the partial normal form of the homogeneous block ``G``. @@ -1079,16 +1085,16 @@ def _partial_normal_form_of_block(G): V = [] W = [] for i in blocks: - if i+1 in blocks or i==n-1: + if i + 1 in blocks or i == n - 1: W.append(i) else: - if D[i,i] != 0: - V += [i,i+1] + if D[i, i] != 0: + V += [i, i + 1] else: - U += [i,i+1] + U += [i, i + 1] if len(W) == 3: # W W W transforms to W U or W V - B[W,:] = _relations(D[W,W],2) * B[W,:] + B[W, :] = _relations(D[W, W], 2) * B[W, :] D = B * G * B.T if mod(D[W[1:], W[1:]].det().unit_part(), 8) == 3: V += W[1:] @@ -1096,18 +1102,18 @@ def _partial_normal_form_of_block(G): U += W[1:] W = W[:1] if len(V) == 4: - B[V,:] = _relations(D[V,V],3) * B[V,:] + B[V, :] = _relations(D[V, V], 3) * B[V, :] U += V V = [] D = B * G * B.T # put everything into the right order UVW = U + V + W - B = B[UVW,:] + B = B[UVW, :] D = B * G * B.T return D, B, len(W) -def _relations(G,n): +def _relations(G, n): r""" Return relations of `2`-adic quadratic forms. @@ -1315,59 +1321,61 @@ def _relations(G,n): """ R = G.base_ring() if n == 1: - e1 = G[0,0].unit_part() - e2 = G[1,1].unit_part() - B = Matrix(R,2,[1,2,2*e2,-e1]) - if n == 2: - e1 = G[0,0].unit_part() - e2 = G[1,1].unit_part() - e3 = G[2,2].unit_part() - B = Matrix(R,3,[1,1,1,e2,-e1,0,e3,0,-e1]) - if n == 3: - B = Matrix(R,4,[1,1,1,0, 1,1,0,1, 1,0,-1,-1, 0,1,-1,-1]) - if n == 4: + e1 = G[0, 0].unit_part() + e2 = G[1, 1].unit_part() + B = Matrix(R, 2, 2, [1, 2, 2 * e2, -e1]) + elif n == 2: + e1 = G[0, 0].unit_part() + e2 = G[1, 1].unit_part() + e3 = G[2, 2].unit_part() + B = Matrix(R, 3, 3, [1, 1, 1, e2, -e1, 0, e3, 0, -e1]) + elif n == 3: + B = Matrix(R, 4, 4, + [1, 1, 1, 0, 1, 1, 0, 1, 1, 0, -1, -1, 0, 1, -1, -1]) + elif n == 4: raise NotImplementedError("relation 4 is not needed") - if n == 5: - e1 = G[2,2].unit_part() - e2 = G[3,3].unit_part() - if mod(e1,4) != mod(e2,4): + elif n == 5: + e1 = G[2, 2].unit_part() + e2 = G[3, 3].unit_part() + if mod(e1, 4) != mod(e2, 4): raise ValueError("W is of the wrong type for relation 5") - B = Matrix(R,4,[ 1, 0, 1, 1, - 0, 1, 1, 1, - -e2, -e2, 0, 3, - -e1, -e1, 2*e2 + 3, -2*e1]) - if n == 6: - if G[0,0].valuation()+1 != G[1,1].valuation(): + B = Matrix(R, 4, [1, 0, 1, 1, + 0, 1, 1, 1, + -e2, -e2, 0, 3, + -e1, -e1, 2 * e2 + 3, -2 * e1]) + elif n == 6: + if G[0, 0].valuation() + 1 != G[1, 1].valuation(): raise ValueError("wrong scales for relation 6") - e1 = G[0,0].unit_part() - e2 = G[1,1].unit_part() - B = Matrix(R,2,[1,1,-2*e2,e1]) - if n == 7: - e = G[0,0].unit_part() - B = Matrix(R,3,[-3, e**2, e**2, 2*e, 1, 0, 2*e, 0, 1]) - if n == 8: - e = G[2,2].unit_part() - if G[0,0]==0: - B = Matrix(R,3,[e, 0, -1, - 0, e, -1, - 2, 2, 1]) + e1 = G[0, 0].unit_part() + e2 = G[1, 1].unit_part() + B = Matrix(R, 2, 2, [1, 1, -2 * e2, e1]) + elif n == 7: + e = G[0, 0].unit_part() + B = Matrix(R, 3, 3, [-3, e**2, e**2, 2 * e, 1, 0, 2 * e, 0, 1]) + elif n == 8: + e = G[2, 2].unit_part() + if G[0, 0] == 0: + B = Matrix(R, 3, 3, [e, 0, -1, + 0, e, -1, + 2, 2, 1]) else: - B = Matrix(R,3,[ 1, 0, 1, - 0, 1, 1, - 2*e, 2*e, - 3]) - if n == 9: - e1 = G[0,0].unit_part() - e2 = G[1,1].unit_part() - e3 = G[2,2].unit_part() - B = Matrix(R,3,[1, 0, 1, - 2*e3, 1, - -e1, -2*e2*e3, 2*e1**2*e3 + 4*e1*e3**2, e1*e2]) - if n == 10: - e1 = G[0,0].unit_part() - e2 = G[1,1].unit_part() - B = Matrix(R,2,[1,1,-4*e2,e1]) - D, B1 = _normalize(B*G*B.T) - return B1*B + B = Matrix(R, 3, 3, [1, 0, 1, + 0, 1, 1, + 2 * e, 2 * e, - 3]) + elif n == 9: + e1 = G[0, 0].unit_part() + e2 = G[1, 1].unit_part() + e3 = G[2, 2].unit_part() + B = Matrix(R, 3, 3, [1, 0, 1, + 2 * e3, 1, -e1, + -2 * e2 * e3, 2 * e1**2 * e3 + 4 * e1 * e3**2, + e1 * e2]) + elif n == 10: + e1 = G[0, 0].unit_part() + e2 = G[1, 1].unit_part() + B = Matrix(R, 2, 2, [1, 1, -4 * e2, e1]) + D, B1 = _normalize(B * G * B.T) + return B1 * B def _two_adic_normal_forms(G, partial=False): @@ -1424,21 +1432,21 @@ def _two_adic_normal_forms(G, partial=False): # UVlist[k] is a list of indices of the block of scale p^k. # It contains the indices of the part of types U or V. # So it may be empty. - UVlist = [[],[]] # empty lists are appended to avoid special cases. + UVlist = [[], []] # empty lists are appended to avoid special cases. # same as UVlist but contains the indices of the part of type W - Wlist = [[],[]] + Wlist = [[], []] # homogeneous normal form for each part - for k in range(scales[-1] - scales[0]+1): - if k+scales[0] in scales: + for k in range(scales[-1] - scales[0] + 1): + if k + scales[0] in scales: i = scales.index(k + scales[0]) - Gk = G[h[i]:h[i+1], h[i]:h[i+1]] + Gk = G[h[i]:h[i + 1], h[i]:h[i + 1]] Dk, Bk, wk = _partial_normal_form_of_block(Gk) - B[h[i]:h[i+1],:] = Bk * B[h[i]:h[i+1], :] + B[h[i]:h[i + 1], :] = Bk * B[h[i]:h[i + 1], :] if not partial: Dk, B1k = _homogeneous_normal_form(Dk, wk) - B[h[i]:h[i+1],:] = B1k * B[h[i]:h[i+1], :] - UVlist.append(list(range(h[i], h[i+1] - wk))) - Wlist.append(list(range(h[i+1]-wk, h[i+1]))) + B[h[i]:h[i + 1], :] = B1k * B[h[i]:h[i + 1], :] + UVlist.append(list(range(h[i], h[i + 1] - wk))) + Wlist.append(list(range(h[i + 1] - wk, h[i + 1]))) else: UVlist.append([]) Wlist.append([]) @@ -1449,69 +1457,70 @@ def _two_adic_normal_forms(G, partial=False): # we never leave partial normal form # but the homogeneous normal form may be destroyed # it is restored at the end. - for k in range(len(UVlist)-1,2,-1): + for k in range(len(UVlist) - 1, 2, -1): # setup notation W = Wlist[k] - Wm = Wlist[k-1] - Wmm = Wlist[k-2] + Wm = Wlist[k - 1] + Wmm = Wlist[k - 2] UV = UVlist[k] - UVm = UVlist[k-1] + UVm = UVlist[k - 1] V = UVlist[k][-2:] - if len(V)!=0 and D[V[0], V[0]]==0: + if V and D[V[0], V[0]] == 0: V = [] # it is U not V # condition b) - if len(Wm) != 0: - if len(V)==2: + if Wm: + if len(V) == 2: R = Wm[:1] + V - B[R,:] = _relations(D[R,R],7) * B[R,:] + B[R, :] = _relations(D[R, R], 7) * B[R, :] V = [] D = B * G * B.T - E = {3,7} + E = {3, 7} for w in W: - if D[w,w].unit_part() in E: + if D[w, w].unit_part() in E: R = Wm[:1] + [w] - B[R,:] = _relations(D[R,R],6) * B[R,:] + B[R, :] = _relations(D[R, R], 6) * B[R, :] D = B * G * B.T # condition c) # We want type a or W = [] # modify D[w,w] to go from type b to type a - x = [len(V)] + [ZZ(mod(w.unit_part(),8)) for w in D[W,W].diagonal()] - if len(x)==3 and x[1]>x[2]: - x[1],x[2] = x[2], x[1] + x = [len(V)] + [ZZ(mod(w.unit_part(), 8)) for w in D[W, W].diagonal()] + if len(x) == 3 and x[1] > x[2]: + x[1], x[2] = x[2], x[1] # the first entry of x is either # 0 if there is no type V component or # 2 if there is a single type V component - # a = [[0,1], [2,3], [2,5], [0,7], [0,1,1], [2,1,3], [0,7,7], [0,1,7]] - b = [[0,5], [2,7], [2,1], [0,3], [0,1,5], [2,1,7], [0,3,7], [0,1,3]] + # a = [[0,1], [2,3], [2,5], [0,7], [0,1,1], [2,1,3], [0,7,7], [0,1,7]] + b = [[0, 5], [2, 7], [2, 1], [0, 3], + [0, 1, 5], [2, 1, 7], [0, 3, 7], [0, 1, 3]] if x in b: w = W[-1] - if x == [0,3,7]: + if x == [0, 3, 7]: # relation 10 should be applied to 3 to stay in homogeneous normal form w = W[0] - if len(UVm) > 0: + if UVm: R = UVm[-2:] + [w] - B[R,:] = _relations(D[R,R],8) * B[R,:] - elif len(Wmm) > 0: + B[R, :] = _relations(D[R, R], 8) * B[R, :] + elif Wmm: R = Wmm[:1] + [w] - B[R,:] = _relations(D[R,R],10) * B[R,:] + B[R, :] = _relations(D[R, R], 10) * B[R, :] elif len(Wm) == 2: - e0 = D[Wm,Wm][0,0].unit_part() - e1 = D[Wm,Wm][1,1].unit_part() - if mod(e1-e0,4) == 0: + e0 = D[Wm, Wm][0, 0].unit_part() + e1 = D[Wm, Wm][1, 1].unit_part() + if mod(e1 - e0, 4) == 0: R = Wm + [w] - B[R,:] = _relations(D[R,R],9) * B[R,:] + B[R, :] = _relations(D[R, R], 9) * B[R, :] D = B * G * B.T # condition a) - stay in homogeneous normal form R = UV + W - Dk = D[R,R] + Dk = D[R, R] Bk = _homogeneous_normal_form(Dk, len(W))[1] - B[R,:] = Bk * B[R,:] + B[R, :] = Bk * B[R, :] D = B * G * B.T # we need to restore the homogeneous normal form of k-1 - if len(Wm)>0: + if Wm: R = UVm + Wm - Dkm = D[R,R] + Dkm = D[R, R] Bkm = _homogeneous_normal_form(Dkm, len(Wm))[1] - B[R,:] = Bkm * B[R,:] + B[R, :] = Bkm * B[R, :] D = B * G * B.T return D, B 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/morphism.py b/src/sage/quivers/morphism.py index 04c45658d13..b8bb25657eb 100644 --- a/src/sage/quivers/morphism.py +++ b/src/sage/quivers/morphism.py @@ -562,7 +562,7 @@ def __ne__(self, other): # If all that holds just check the vectors return self._vector != other._vector - def __bool__(self): + def __bool__(self) -> bool: """ Return whether ``self`` is the zero morphism. @@ -586,8 +586,6 @@ def __bool__(self): """ return any(self._vector) - - def __mul__(self, other): """ This function overrides the ``*`` operator 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/repl/display/formatter.py b/src/sage/repl/display/formatter.py index 2910fb8ee19..488f0bf2791 100644 --- a/src/sage/repl/display/formatter.py +++ b/src/sage/repl/display/formatter.py @@ -169,8 +169,7 @@ def format(self, obj, include=None, exclude=None): sage: shell.run_cell('import ipywidgets') sage: shell.run_cell('slider = ipywidgets.IntSlider()') sage: shell.run_cell('get_ipython().display_formatter.format(slider)') - IntSlider(value=0) - ({}, {}) + ...IntSlider(value=0)..., {}) sage: shell.run_cell('%display default') sage: shell.quit() diff --git a/src/sage/repl/ipython_kernel/interact.py b/src/sage/repl/ipython_kernel/interact.py index 4a6960ece3a..4f96a212ab7 100644 --- a/src/sage/repl/ipython_kernel/interact.py +++ b/src/sage/repl/ipython_kernel/interact.py @@ -18,7 +18,7 @@ sage: @interact ....: def f(x=(0, 10)): ....: pass - Interactive function with 1 widget + ...Interactive function with 1 widget x: IntSlider(value=5, description='x', max=10) sage: f.widget.children (IntSlider(value=5, description='x', max=10), Output()) @@ -69,7 +69,7 @@ class sage_interactive(interactive): sage: from sage.repl.ipython_kernel.interact import sage_interactive sage: def myfunc(x=10, y="hello", z=None): pass sage: sage_interactive(myfunc, x=(0,100), z=["one", "two", "three"]) - Interactive function with 3 widgets + ...Interactive function with 3 widgets x: IntSlider(value=10, description='x') y: Text(value='hello', description='y') z: Dropdown(description='z', options=('one', 'two', 'three'), value=None) @@ -99,10 +99,10 @@ def __init__(self, *args, **kwds): sage: def myfunc(auto_update=False): pass sage: sage_interactive(myfunc) - Manual interactive function with 0 widgets + ...Manual interactive function with 0 widgets sage: def myfunc(auto_update=None): pass sage: sage_interactive(myfunc) - Interactive function with 0 widgets + ...Interactive function with 0 widgets """ # Use *args to avoid name clash with keyword arguments if len(args) < 2: @@ -126,7 +126,7 @@ def __init__(self, *args, **kwds): super().__init__(f, options, **kwds) if self.manual: # In Sage, manual interacts are always run once - self.on_displayed(self.update) + self.on_widget_constructed(self.update) else: # In automatic mode, clicking on a ToggleButtons button # should also run the interact @@ -143,7 +143,7 @@ def __repr__(self): sage: from sage.repl.ipython_kernel.interact import sage_interactive sage: def myfunc(): pass sage: sage_interactive(myfunc) - Interactive function with 0 widgets + ...Interactive function with 0 widgets """ s = "Manual interactive" if self.manual else "Interactive" widgets = [w for w in self.children if isinstance(w, ValueWidget)] @@ -164,7 +164,7 @@ def signature(self): sage: from sage.repl.ipython_kernel.interact import sage_interactive sage: def myfunc(x=[1,2,3], auto_update=False): pass sage: sage_interactive(myfunc).signature().parameters - mappingproxy({'x': }) + ...mappingproxy({'x': }) """ return self.__signature @@ -181,14 +181,14 @@ def widget_from_single_value(cls, abbrev, *args, **kwds): sage: from sage.repl.ipython_kernel.interact import sage_interactive sage: sage_interactive.widget_from_single_value("sin(x)") - Text(value='sin(x)') + ...Text(value='sin(x)') sage: sage_interactive.widget_from_single_value(sin(x)) - EvalText(value='sin(x)') + ...EvalText(value='sin(x)') sage: from sage.plot.colors import Color sage: sage_interactive.widget_from_single_value(matrix([[1, 2], [3, 4]])) - Grid(value=[[1, 2], [3, 4]], children=(Label(value=''), VBox(children=(EvalText(value='1', layout=Layout(max_width='5em')), EvalText(value='3', layout=Layout(max_width='5em')))), VBox(children=(EvalText(value='2', layout=Layout(max_width='5em')), EvalText(value='4', layout=Layout(max_width='5em')))))) + ...Grid(value=[[1, 2], [3, 4]], children=(Label(value=''), VBox(children=(EvalText(value='1', layout=Layout(max_width='5em')), EvalText(value='3', layout=Layout(max_width='5em')))), VBox(children=(EvalText(value='2', layout=Layout(max_width='5em')), EvalText(value='4', layout=Layout(max_width='5em')))))) sage: sage_interactive.widget_from_single_value(Color('cornflowerblue')) - SageColorPicker(value='#6495ed') + ...SageColorPicker(value='#6495ed') """ # Support Sage matrices and colors if isinstance(abbrev, Matrix): @@ -219,15 +219,15 @@ def widget_from_tuple(cls, abbrev, *args, **kwds): sage: from sage.repl.ipython_kernel.interact import sage_interactive sage: sage_interactive.widget_from_tuple( (0, 10) ) - IntSlider(value=5, max=10) + ...IntSlider(value=5, max=10) sage: sage_interactive.widget_from_tuple( ("number", (0, 10)) ) - IntSlider(value=5, description='number', max=10) + ...IntSlider(value=5, description='number', max=10) sage: sage_interactive.widget_from_tuple( (3, (0, 10)) ) - IntSlider(value=3, max=10) - sage: sage_interactive.widget_from_tuple((2, dict(one=1, two=2, three=3))) - Dropdown(index=1, options={'one': 1, 'two': 2, 'three': 3}, value=2) + ...IntSlider(value=3, max=10) + sage: sage_interactive.widget_from_tuple((2, [('one', 1), ('two', 2), ('three', 3)])) + ...Dropdown(index=1, options=(('one', 1), ('two', 2), ('three', 3)), value=2) sage: sage_interactive.widget_from_tuple( (sqrt(2), pi) ) - FloatSlider(value=2.277903107981444, max=3.141592653589793, min=1.4142135623730951) + ...FloatSlider(value=2.277903107981444, max=3.141592653589793, min=1.4142135623730951) TESTS: @@ -235,7 +235,7 @@ def widget_from_tuple(cls, abbrev, *args, **kwds): sage: SCR = SR.subring(no_variables=True) sage: sage_interactive.widget_from_tuple( (SCR(sqrt(2)), SCR(pi)) ) - FloatSlider(value=2.277903107981444, max=3.141592653589793, min=1.4142135623730951) + ...FloatSlider(value=2.277903107981444, max=3.141592653589793, min=1.4142135623730951) """ # Support (description, abbrev) if len(abbrev) == 2 and isinstance(abbrev[0], str): @@ -269,17 +269,17 @@ def widget_from_iterable(cls, abbrev, *args, **kwds): sage: from sage.repl.ipython_kernel.interact import sage_interactive sage: sage_interactive.widget_from_iterable([1..5]) - Dropdown(options=(1, 2, 3, 4, 5), value=1) + ...Dropdown(options=(1, 2, 3, 4, 5), value=1) sage: sage_interactive.widget_from_iterable(iter([1..5])) - SelectionSlider(options=(1, 2, 3, 4, 5), value=1) + ...SelectionSlider(options=(1, 2, 3, 4, 5), value=1) sage: sage_interactive.widget_from_iterable((1..5)) - SelectionSlider(options=(1, 2, 3, 4, 5), value=1) + ...SelectionSlider(options=(1, 2, 3, 4, 5), value=1) sage: sage_interactive.widget_from_iterable(x for x in [1..5]) - SelectionSlider(options=(1, 2, 3, 4, 5), value=1) + ...SelectionSlider(options=(1, 2, 3, 4, 5), value=1) sage: def gen(): ....: yield 1; yield 2; yield 3; yield 4; yield 5 sage: sage_interactive.widget_from_iterable(gen()) - SelectionSlider(options=(1, 2, 3, 4, 5), value=1) + ...SelectionSlider(options=(1, 2, 3, 4, 5), value=1) """ if isinstance(abbrev, Iterator): return SelectionSlider(options=list(abbrev)) diff --git a/src/sage/repl/ipython_kernel/widgets_sagenb.py b/src/sage/repl/ipython_kernel/widgets_sagenb.py index 2ce59d79a3b..76f4f52ac4a 100644 --- a/src/sage/repl/ipython_kernel/widgets_sagenb.py +++ b/src/sage/repl/ipython_kernel/widgets_sagenb.py @@ -470,15 +470,6 @@ def selector(values, label=None, default=None, nrows=None, ncols=None, width=Non sage: selector([(1,"one"), (2,"two"), (3,"three")], buttons=True) ToggleButtons(options=(('one', 1), ('two', 2), ('three', 3)), value=1) - A dict of ``label:value`` pairs is also allowed. Since a ``dict`` - is not ordered, it is better to use an :class:`OrderedDict`:: - - sage: from collections import OrderedDict - sage: selector(OrderedDict(one=1, two=2, three=3)) - Dropdown(options=OrderedDict([('one', 1), ('two', 2), ('three', 3)]), value=1) - sage: selector(OrderedDict(one=1, two=2, three=3), buttons=True) - ToggleButtons(options=OrderedDict([('one', 1), ('two', 2), ('three', 3)]), value=1) - The values can be any kind of object: sage: selector([sin(x^2), GF(29), EllipticCurve('37a1')]) diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index 500ab0b615a..a6090039db2 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -146,7 +146,7 @@ lazy_import('sage.rings.laurent_series_ring_element', 'LaurentSeries', deprecation=33602) # Lazy Laurent series ring -lazy_import('sage.rings.lazy_series_ring', ['LazyLaurentSeriesRing', 'LazyTaylorSeriesRing', +lazy_import('sage.rings.lazy_series_ring', ['LazyLaurentSeriesRing', 'LazyPowerSeriesRing', 'LazySymmetricFunctions', 'LazyDirichletSeriesRing']) # Tate algebras diff --git a/src/sage/rings/complex_arb.pyx b/src/sage/rings/complex_arb.pyx index 62841a9f8d6..797f5122d40 100644 --- a/src/sage/rings/complex_arb.pyx +++ b/src/sage/rings/complex_arb.pyx @@ -2984,7 +2984,7 @@ cdef class ComplexBall(RingElement): return res def rising_factorial(self, n): - """ + r""" Return the ``n``-th rising factorial of this ball. The `n`-th rising factorial of `x` is equal to `x (x+1) \cdots (x+n-1)`. @@ -3704,7 +3704,7 @@ cdef class ComplexBall(RingElement): return res def polylog(self, s): - """ + r""" Return the polylogarithm `\operatorname{Li}_s(\mathrm{self})`. EXAMPLES:: diff --git a/src/sage/rings/complex_double.pyx b/src/sage/rings/complex_double.pyx index 5cd5cb1910f..f0c70c67f82 100644 --- a/src/sage/rings/complex_double.pyx +++ b/src/sage/rings/complex_double.pyx @@ -1637,7 +1637,7 @@ cdef class ComplexDoubleElement(FieldElement): return self.real().is_NaN() or self.imag().is_NaN() cpdef _pow_(self, other): - """ + r""" The complex number ``self`` raised to the power ``other``. This is computed using complex logarithms and exponentials diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index 49109af92c6..2a5e3048fbc 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -137,15 +137,15 @@ cdef inline mpfr_rnd_t rnd_im(mpc_rnd_t rnd): sign = '[+-]' digit_ten = '[0123456789]' exponent_ten = '[e@]' + sign + '?[0123456789]+' -number_ten = 'inf(?:inity)?|@inf@|nan(?:\([0-9A-Z_]*\))?|@nan@(?:\([0-9A-Z_]*\))?'\ - '|(?:' + digit_ten + '*\.' + digit_ten + '+|' + digit_ten + '+\.?)(?:' + exponent_ten + ')?' -imaginary_ten = 'i(?:\s*\*\s*(?:' + number_ten + '))?|(?:' + number_ten + ')\s*\*\s*i' -complex_ten = '(?P(?P' + sign + ')?\s*(?P' + imaginary_ten + ')' \ - '(\s*(?P' + sign + ')\s*(?P' + number_ten + '))?)' \ +number_ten = r'inf(?:inity)?|@inf@|nan(?:\([0-9A-Z_]*\))?|@nan@(?:\([0-9A-Z_]*\))?'\ + '|(?:' + digit_ten + r'*\.' + digit_ten + '+|' + digit_ten + r'+\.?)(?:' + exponent_ten + ')?' +imaginary_ten = r'i(?:\s*\*\s*(?:' + number_ten + '))?|(?:' + number_ten + r')\s*\*\s*i' +complex_ten = '(?P(?P' + sign + r')?\s*(?P' + imaginary_ten + r')' \ + r'(\s*(?P' + sign + r')\s*(?P' + number_ten + '))?)' \ '|' \ - '(?P(?P' + sign + ')?\s*(?P' + number_ten + ')' \ - '(\s*(?P' + sign + ')\s*(?P' + imaginary_ten + '))?)' -re_complex_ten = re.compile('^\s*(?:' + complex_ten + ')\s*$', re.I) + '(?P(?P' + sign + r')?\s*(?P' + number_ten + r')' \ + r'(\s*(?P' + sign + r')\s*(?P' + imaginary_ten + '))?)' +re_complex_ten = re.compile(r'^\s*(?:' + complex_ten + r')\s*$', re.I) cpdef inline split_complex_string(string, int base=10): """ @@ -185,17 +185,17 @@ cpdef inline split_complex_string(string, int base=10): # Warning: number, imaginary, and complex should be enclosed in parentheses # when used as regexp because of alternatives '|' - number = '@nan@(?:\([0-9A-Z_]*\))?|@inf@|(?:' + digit + '*\.' + digit + '+|' + digit + '+\.?)(?:' + exponent + ')?' + number = r'@nan@(?:\([0-9A-Z_]*\))?|@inf@|(?:' + digit + r'*\.' + digit + '+|' + digit + r'+\.?)(?:' + exponent + ')?' if base <= 10: - number = 'nan(?:\([0-9A-Z_]*\))?|inf(?:inity)?|' + number - imaginary = 'i(?:\s*\*\s*(?:' + number + '))?|(?:' + number + ')\s*\*\s*i' - complex = '(?P(?P' + sign + ')?\s*(?P' + imaginary + ')' \ - '(\s*(?P' + sign + ')\s*(?P' + number + '))?)' \ + number = r'nan(?:\([0-9A-Z_]*\))?|inf(?:inity)?|' + number + imaginary = r'i(?:\s*\*\s*(?:' + number + '))?|(?:' + number + r')\s*\*\s*i' + complex = '(?P(?P' + sign + r')?\s*(?P' + imaginary + r')' \ + r'(\s*(?P' + sign + r')\s*(?P' + number + '))?)' \ '|' \ - '(?P(?P' + sign + ')?\s*(?P' + number + ')' \ - '(\s*(?P' + sign + ')\s*(?P' + imaginary + '))?)' + '(?P(?P' + sign + r')?\s*(?P' + number + r')' \ + r'(\s*(?P' + sign + r')\s*(?P' + imaginary + '))?)' - z = re.match('^\s*(?:' + complex + ')\s*$', string, re.I) + z = re.match(r'^\s*(?:' + complex + r')\s*$', string, re.I) x, y = None, None if z is not None: @@ -207,18 +207,18 @@ cpdef inline split_complex_string(string, int base=10): return None if z.group(prefix + '_re_abs') is not None: - x = z.expand('\g<' + prefix + '_re_abs>') + x = z.expand(r'\g<' + prefix + '_re_abs>') if z.group(prefix + '_re_sign') is not None: - x = z.expand('\g<' + prefix + '_re_sign>') + x + x = z.expand(r'\g<' + prefix + '_re_sign>') + x if z.group(prefix + '_im_abs') is not None: - y = re.search('(?P' + number + ')', z.expand('\g<' + prefix + '_im_abs>'), re.I) + y = re.search('(?P' + number + ')', z.expand(r'\g<' + prefix + '_im_abs>'), re.I) if y is None: y = '1' else: - y = y.expand('\g') + y = y.expand(r'\g') if z.group(prefix + '_im_sign') is not None: - y = z.expand('\g<' + prefix + '_im_sign>') + y + y = z.expand(r'\g<' + prefix + '_im_sign>') + y return x, y @@ -1701,7 +1701,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): return z def cosh(self): - """ + r""" Return the hyperbolic cosine of this complex number: .. MATH:: @@ -1721,7 +1721,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): return z def sinh(self): - """ + r""" Return the hyperbolic sine of this complex number: .. MATH:: @@ -2063,7 +2063,7 @@ cdef class MPComplexNumber(sage.structure.element.FieldElement): return z def exp(self): - """ + r""" Return the exponential of this complex number: .. MATH:: diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index 21b32326aa3..5083f66a89d 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -2549,7 +2549,7 @@ cdef class ComplexNumber(sage.structure.element.FieldElement): # Other special functions def agm(self, right, algorithm="optimal"): - """ + r""" Return the Arithmetic-Geometric Mean (AGM) of ``self`` and ``right``. INPUT: diff --git a/src/sage/rings/continued_fraction.py b/src/sage/rings/continued_fraction.py index f4c10b009ad..a16137ff609 100644 --- a/src/sage/rings/continued_fraction.py +++ b/src/sage/rings/continued_fraction.py @@ -1018,7 +1018,7 @@ def __bool__(self): """ return bool(self.quotient(0)) or self.quotient(1) is not Infinity - + def is_zero(self): r""" diff --git a/src/sage/rings/finite_rings/element_base.pyx b/src/sage/rings/finite_rings/element_base.pyx index d4dd6b22ee4..ec8d50d4f07 100755 --- a/src/sage/rings/finite_rings/element_base.pyx +++ b/src/sage/rings/finite_rings/element_base.pyx @@ -983,9 +983,10 @@ cdef class FinitePolyExtElement(FiniteRingElement): return self.pth_power(k=k) + cdef class Cache_base(SageObject): cpdef FinitePolyExtElement fetch_int(self, number): - """ + r""" Given an integer less than `p^n` with base `2` representation `a_0 + a_1 \cdot 2 + \cdots + a_k 2^k`, this returns `a_0 + a_1 x + \cdots + a_k x^k`, where `x` is the @@ -998,4 +999,3 @@ cdef class Cache_base(SageObject): a^33 + a + 1 """ raise NotImplementedError("this must be implemented by subclasses") - 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..96e4e3df8d9 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``. @@ -401,7 +401,7 @@ cdef class Cache_ntl_gf2e(Cache_base): raise ValueError("Cannot coerce element %s to this field." % e) cpdef FiniteField_ntl_gf2eElement fetch_int(self, number): - """ + r""" Given an integer less than `p^n` with base `2` representation `a_0 + a_1 \cdot 2 + \cdots + a_k 2^k`, this returns `a_0 + a_1 x + \cdots + a_k x^k`, where `x` is the diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index ffad0442389..c91126649f1 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:: @@ -1021,7 +1021,7 @@ cdef class FiniteField(Field): return self._modulus def polynomial(self, name=None): - """ + r""" Return the minimal polynomial of the generator of ``self`` over the prime finite field. 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/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index 400bf154522..58218d9a193 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -116,8 +116,9 @@ from sage.groups.generic import discrete_log cdef Integer one_Z = Integer(1) + def Mod(n, m, parent=None): - """ + r""" Return the equivalence class of `n` modulo `m` as an element of `\ZZ/m\ZZ`. @@ -1598,7 +1599,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): return [a for a in self.parent() if a**n == self] def _balanced_abs(self): - """ + r""" This function returns `x` or `-x`, whichever has a positive representative in `-n/2 < x \leq n/2`. @@ -1608,8 +1609,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): """ if self.lift() > self.__modulus.sageInteger >> 1: return -self - else: - return self + return self def rational_reconstruction(self): """ @@ -1947,7 +1947,7 @@ cdef class IntegerMod_abstract(FiniteRingElement): cdef class IntegerMod_gmp(IntegerMod_abstract): - """ + r""" Elements of `\ZZ/n\ZZ` for n not small enough to be operated on in word size. @@ -2354,7 +2354,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): @coerce_binop def gcd(self, IntegerMod_gmp other): - """ + r""" Greatest common divisor Returns the "smallest" generator in `\ZZ / N\ZZ` of the ideal @@ -2387,7 +2387,7 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): cdef class IntegerMod_int(IntegerMod_abstract): - """ + r""" Elements of `\ZZ/n\ZZ` for n small enough to be operated on in 32 bits @@ -3022,20 +3022,18 @@ cdef class IntegerMod_int(IntegerMod_abstract): # Either it failed but extend was True, or the generic algorithm is better return IntegerMod_abstract.sqrt(self, extend=extend, all=all) - def _balanced_abs(self): - """ + r""" This function returns `x` or `-x`, whichever has a positive representative in `-n/2 < x \leq n/2`. """ if self.ivalue > self.__modulus.int32 / 2: return -self - else: - return self + return self @coerce_binop def gcd(self, IntegerMod_int other): - """ + r""" Greatest common divisor Returns the "smallest" generator in `\ZZ / N\ZZ` of the ideal @@ -3213,7 +3211,7 @@ cdef int jacobi_int(int_fast32_t a, int_fast32_t m) except -2: ###################################################################### cdef class IntegerMod_int64(IntegerMod_abstract): - """ + r""" Elements of `\ZZ/n\ZZ` for n small enough to be operated on in 64 bits @@ -3688,22 +3686,20 @@ cdef class IntegerMod_int64(IntegerMod_abstract): sage: hash(a) 8943 """ - return hash(self.ivalue) def _balanced_abs(self): - """ + r""" This function returns `x` or `-x`, whichever has a positive representative in `-n/2 < x \leq n/2`. """ if self.ivalue > self.__modulus.int64 / 2: return -self - else: - return self + return self @coerce_binop def gcd(self, IntegerMod_int64 other): - """ + r""" Greatest common divisor Returns the "smallest" generator in `\ZZ / N\ZZ` of the ideal diff --git a/src/sage/rings/finite_rings/residue_field.pyx b/src/sage/rings/finite_rings/residue_field.pyx index 7596f2a3028..dbef75e9fe6 100644 --- a/src/sage/rings/finite_rings/residue_field.pyx +++ b/src/sage/rings/finite_rings/residue_field.pyx @@ -1,4 +1,4 @@ -""" +r""" Finite residue fields We can take the residue field of maximal ideals in the ring of integers @@ -1846,7 +1846,7 @@ class ResidueFiniteField_ntl_gf2e(ResidueField_generic, FiniteField_ntl_gf2e): """ # we change the order for consistency with FiniteField_ntl_gf2e's __cinit__ def __init__(self, q, name, modulus, repr, p, to_vs, to_order, PB): - """ + r""" INPUT: - ``p`` -- the prime ideal defining this residue field diff --git a/src/sage/rings/function_field/ideal.py b/src/sage/rings/function_field/ideal.py index 75e6a826cd2..1ce0b885f56 100644 --- a/src/sage/rings/function_field/ideal.py +++ b/src/sage/rings/function_field/ideal.py @@ -1266,7 +1266,7 @@ def __bool__(self): """ return self._hnf.nrows() != 0 - + def __hash__(self): """ diff --git a/src/sage/rings/homset.py b/src/sage/rings/homset.py index c0db5c9210b..6f7a2d4b415 100644 --- a/src/sage/rings/homset.py +++ b/src/sage/rings/homset.py @@ -49,7 +49,9 @@ def RingHomset(R, S, category = None): """ if quotient_ring.is_QuotientRing(R): - return RingHomset_quo_ring(R, S, category = category) + from .polynomial.polynomial_quotient_ring import is_PolynomialQuotientRing + if not is_PolynomialQuotientRing(R): # backwards compatibility + return RingHomset_quo_ring(R, S, category = category) return RingHomset_generic(R, S, category = category) 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/integer.pyx b/src/sage/rings/integer.pyx index 00b490ecb00..0312f3f99fb 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -1257,7 +1257,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return self.str(2) def bits(self): - """ + r""" Return the bits in self as a list, least significant first. The result satisfies the identity @@ -2434,7 +2434,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): integer_ring.ZZ(n).ordinal_str())) cpdef size_t _exact_log_log2_iter(self,Integer m): - """ + r""" This is only for internal use only. You should expect it to crash and burn for negative or other malformed input. In particular, if the base `2 \leq m < 4` the log2 approximation of m is 1 and certain @@ -3463,7 +3463,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): return q, r def powermod(self, exp, mod): - """ + r""" Compute self\*\*exp modulo mod. EXAMPLES:: @@ -6714,8 +6714,9 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): raise ArithmeticError("inverse does not exist") def inverse_mod(self, n): - """ - Returns the inverse of self modulo `n`, if this inverse exists. + r""" + Return the inverse of self modulo `n`, if this inverse exists. + Otherwise, raises a ``ZeroDivisionError`` exception. INPUT: diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index 9e9b655da9f..837df2ebf8d 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -68,7 +68,7 @@ series are much faster. Moreover, these are the series where equality can be decided. For example:: - sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L. = LazyPowerSeriesRing(ZZ) sage: f = 1 + 2*z^2 / (1 - z) sage: f - 2 / (1 - z) + 1 + 2*z 0 @@ -77,7 +77,7 @@ streams of multivariate polynomials. Therefore, the only exact series in this case are polynomials:: - sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L. = LazyPowerSeriesRing(ZZ) sage: 1 / (1-x) 1 + x + x^2 + x^3 + x^4 + x^5 + x^6 + O(x,y)^7 @@ -100,6 +100,101 @@ sage: hinv.valuation() -1 +TESTS: + +We check that -- at least for some simple cases -- division, +composition and reversion do not raise exceptions for univariate lazy +Laurent series, lazy power series and lazy symmetric functions:: + + sage: def check(L, z, verbose=False): + ....: # division + ....: lf = [0, L(0), 1, L(1), z, 1 + z, 2 + z + z^2] + ....: lg = [3, L(3), 1 + z, 2 + z + z^2] + ....: for f in lf: + ....: for g in lg: + ....: try: + ....: h = f / g + ....: if verbose: print("(%s) / (%s) = %s" % (f, g, h)) + ....: except Exception as e: + ....: print("%s in (%s) / (%s)" % (e, f, g)) + ....: # composition + ....: f = L(0) + ....: l = [(f, 0), (f, L(0)), (f, 2), (f, L(2)), (f, 2 + z + z^2), (f, 3/(1 - 2*z))] + ....: f = L(1) + ....: l.extend([(f, 0), (f, L(0)), (f, 2), (f, L(2)), (f, 2 + z + z^2), (f, 3/(1 - 2*z))]) + ....: f = 2 + z + z^2 + ....: l.extend([(f, 0), (f, L(0)), (f, 2), (f, L(2)), (f, 2 + z + z^2), (f, 3/(1 - 2*z))]) + ....: f = 3/(2 - 3*z) + ....: l.extend([(f, 0), (f, L(0)), (f, 3*z/(1 - 2*z))]) + ....: for f, g in l: + ....: try: + ....: h = f(g) + ....: if verbose: print("(%s)(%s) = %s" % (f, g, h)) + ....: except Exception as e: + ....: print("%s in (%s)(%s)" % (e, f, g)) + ....: # reversion + ....: l = [2 + 3*z, 3*z + 2*z^2, 3*z/(1 - 2*z - 3*z^2)] + ....: for f in l: + ....: try: + ....: h = f.revert() + ....: if verbose: print("(%s)^{(-1)} = %s" % (f, h)) + ....: except Exception as e: + ....: print("%s in (%s).revert()" % (e, f)) + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: check(L, z) + sage: L. = LazyPowerSeriesRing(QQ) + sage: check(L, z) + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(p) + sage: check(L, L(p[1])) + +We check that the elements in the cache of the stream of homogeneous +components are in the correct ring:: + + sage: def check(L, x, valuation, verbose=False): + ....: f = L(x, valuation=valuation) + ....: _ = f[2], f[5] + ....: if callable(x): + ....: assert len(f._coeff_stream._cache) == 2, "the cache is %s" % f._coeff_stream._cache + ....: else: + ....: m = 6 if valuation is None else 5 - valuation + 1 + ....: assert len(f._coeff_stream._cache) == m, "the cache is %s" % f._coeff_stream._cache + ....: P = f._coeff_stream._cache[2].parent() + ....: assert P is L._internal_poly_ring.base_ring(), "the cache is in %s" % P + ....: if verbose: + ....: print(P) + + sage: def gen(): + ....: n = 0 + ....: while True: + ....: yield n + ....: n += 1 + + sage: L. = LazyLaurentSeriesRing(GF(2)) + sage: check(L, lambda n: n, valuation=-5) + sage: check(L, gen(), valuation=-5) + + sage: L = LazyDirichletSeriesRing(QQbar, "s") + sage: check(L, lambda n: n, valuation=2) + sage: check(L, gen(), valuation=2) + + sage: L. = LazyPowerSeriesRing(GF(2)) + sage: check(L, lambda n: n, valuation=0) + sage: check(L, gen(), valuation=0) + + sage: L. = LazyPowerSeriesRing(GF(2)) + sage: check(L, lambda n: (x + y)^n, valuation=None) + sage: def gen(): + ....: n = 0 + ....: while True: + ....: yield (x+y)^n + ....: n += 1 + sage: check(L, gen(), valuation=None) + + sage: s = SymmetricFunctions(GF(2)).s() + sage: L = LazySymmetricFunctions(s) + sage: check(L, lambda n: sum(k*s(la) for k, la in enumerate(Partitions(n))), valuation=0) """ # **************************************************************************** @@ -120,11 +215,17 @@ lazy_import("sage.functions.other", "factorial") from sage.misc.misc_c import prod from sage.arith.power import generic_power +from sage.arith.functions import lcm +from sage.arith.misc import divisors, moebius +from sage.combinat.partition import Partition, Partitions +from sage.misc.derivative import derivative_parse +from sage.categories.integral_domains import IntegralDomains from sage.rings.infinity import infinity from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.categories.tensor import tensor from sage.data_structures.stream import ( Stream_add, Stream_cauchy_mul, @@ -140,11 +241,13 @@ Stream_uninitialized, Stream_shift, Stream_function, + Stream_derivative, Stream_dirichlet_convolve, Stream_dirichlet_invert, Stream_plethysm ) + class LazyModuleElement(Element): r""" A lazy sequence with a module structure given by term-wise @@ -155,9 +258,9 @@ class LazyModuleElement(Element): sage: L. = LazyLaurentSeriesRing(ZZ) sage: M = L(lambda n: n, valuation=0) sage: N = L(lambda n: 1, valuation=0) - sage: M[:10] + sage: M[0:10] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - sage: N[:10] + sage: N[0:10] [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] Two sequences can be added:: @@ -169,19 +272,19 @@ class LazyModuleElement(Element): Two sequences can be subtracted:: sage: P = M - N - sage: P[:10] + sage: P[0:10] [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8] A sequence can be multiplied by a scalar:: sage: Q = 2 * M - sage: Q[:10] + sage: Q[0:10] [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] The negation of a sequence can also be found:: sage: R = -M - sage: R[:10] + sage: R[0:10] [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] """ def __init__(self, parent, coeff_stream): @@ -196,27 +299,41 @@ def __init__(self, parent, coeff_stream): sage: L = LazyDirichletSeriesRing(QQbar, 'z') sage: g = L(constant=1) sage: TestSuite(g).run() - """ Element.__init__(self, parent) self._coeff_stream = coeff_stream def __getitem__(self, n): - """ - Return the coefficient of the term with exponent ``n`` of the series. + r""" + Return the homogeneous degree ``n`` part of the series. INPUT: - - ``n`` -- integer; the exponent + - ``n`` -- integer; the degree + + For a series ``f``, the slice ``f[start:stop]`` produces the following: + + - if ``start`` and ``stop`` are integers, return the list of + terms with given degrees + + - if ``start`` is ``None``, return the list of terms + beginning with the valuation + + - if ``stop`` is ``None``, return a + :class:`~sage.misc.lazy_list.lazy_list_generic` instead. EXAMPLES:: - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: L. = LazyLaurentSeriesRing(ZZ) sage: f = z / (1 - 2*z^3) sage: [f[n] for n in range(20)] [0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64] sage: f[0:20] [0, 1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64] + sage: f[:20] + [1, 0, 0, 2, 0, 0, 4, 0, 0, 8, 0, 0, 16, 0, 0, 32, 0, 0, 64] + sage: f[::3] + lazy list [1, 2, 4, ...] sage: M = L(lambda n: n, valuation=0) sage: [M[n] for n in range(20)] @@ -227,75 +344,154 @@ def __getitem__(self, n): sage: [M[n] for n in range(20)] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + Similarly for multivariate series:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: sin(x*y)[:11] + [x*y, 0, 0, 0, -1/6*x^3*y^3, 0, 0, 0, 1/120*x^5*y^5] + sage: sin(x*y)[2::4] + lazy list [x*y, -1/6*x^3*y^3, 1/120*x^5*y^5, ...] + Similarly for Dirichlet series:: sage: L = LazyDirichletSeriesRing(ZZ, "z") - sage: f = L(lambda n: n) - sage: [f[n] for n in range(1, 11)] - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - sage: f[1:11] + sage: L(lambda n: n)[1:11] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - sage: M = L(lambda n: n) - sage: [M[n] for n in range(1, 11)] - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - sage: L = LazyDirichletSeriesRing(ZZ, "z", sparse=True) - sage: M = L(lambda n: n) - sage: [M[n] for n in range(1, 11)] - [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + TESTS: + + Check that no more elements than necessary are computed:: + sage: L = LazyDirichletSeriesRing(ZZ, "z") + sage: f = L(lambda n: 0 if n < 5 else n) + sage: f[:3] + [] + sage: f._coeff_stream._cache + {1: 0, 2: 0} """ R = self.parent()._internal_poly_ring.base_ring() + coeff_stream = self._coeff_stream if isinstance(n, slice): - if n.stop is None: - raise NotImplementedError("cannot list an infinite set") - start = n.start if n.start is not None else self._coeff_stream._approximate_order + if n.start is None: + # WARNING: for Dirichlet series, 'degree' and + # valuation are different + if n.stop is None: + start = coeff_stream.order() + else: + start = coeff_stream._approximate_order + while start < n.stop and not coeff_stream[start]: + start += 1 + coeff_stream._approximate_order = start + else: + start = n.start step = n.step if n.step is not None else 1 + if n.stop is None: + from sage.misc.lazy_list import lazy_list + return lazy_list(lambda k: R(self._coeff_stream[start + k * step])) + return [R(self._coeff_stream[k]) for k in range(start, n.stop, step)] + return R(self._coeff_stream[n]) coefficient = __getitem__ - def map_coefficients(self, func, ring=None): + def coefficients(self, n=None): r""" - Return the series with ``func`` applied to each nonzero - coefficient of ``self``. + Return the first `n` non-zero coefficients of ``self``. INPUT: - - ``func`` -- function that takes in a coefficient and returns - a new coefficient + - ``n`` -- (optional) the number of non-zero coefficients to return - EXAMPLES: + If the series has fewer than `n` non-zero coefficients, only + these are returned. - Dense Implementation:: + If ``n`` is ``None``, a + :class:`~sage.misc.lazy_list.lazy_list_generic` with all + non-zero coefficients is returned instead. - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) - sage: s = z/(1 - 2*z^2) - sage: t = s.map_coefficients(lambda c: c + 1) - sage: s - z + 2*z^3 + 4*z^5 + 8*z^7 + O(z^8) - sage: t - 2*z + 3*z^3 + 5*z^5 + 9*z^7 + O(z^8) - sage: m = L(lambda n: n, valuation=0); m - z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) - sage: m.map_coefficients(lambda c: c + 1) - 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + .. WARNING:: - Sparse Implementation:: + If there are fewer than `n` non-zero coefficients, but + this cannot be detected, this method will not return. - sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) + EXAMPLES:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: f = L([1,2,3]) + sage: f.coefficients(5) + doctest:...: DeprecationWarning: the method coefficients now only returns the non-zero coefficients. Use __getitem__ instead. + See https://trac.sagemath.org/32367 for details. + [1, 2, 3] + + sage: f = sin(x) + sage: f.coefficients(5) + [1, -1/6, 1/120, -1/5040, 1/362880] + + sage: L. = LazyPowerSeriesRing(QQ) + sage: f = sin(x^2+y^2) + sage: f.coefficients(5) + [1, 1, -1/6, -1/2, -1/2] + + sage: f.coefficients() + lazy list [1, 1, -1/6, ...] + + sage: L. = LazyPowerSeriesRing(GF(2)) + sage: f = L(lambda n: n) + sage: f.coefficients(5) + [1, 1, 1, 1, 1] + """ + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_zero): + return [] + from itertools import repeat, chain, islice + from sage.misc.lazy_list import lazy_list + # prepare a generator of the non-zero coefficients + P = self.parent() + if isinstance(coeff_stream, Stream_exact): + if coeff_stream._constant: + coeffs = chain((c for c in coeff_stream._initial_coefficients if c), + repeat(coeff_stream._constant)) + else: + coeffs = (c for c in coeff_stream._initial_coefficients if c) + else: + coeffs = filter(bool, coeff_stream.iterate_coefficients()) + + if n is None: + if P._internal_poly_ring.base_ring() is not P._laurent_poly_ring: + return lazy_list(coeffs) + + # flatten out the generator in the multivariate case + return lazy_list(chain.from_iterable(map(lambda coeff: coeff.coefficients(), coeffs))) + + if isinstance(self, LazyPowerSeries) and self.parent()._arity == 1: + from sage.misc.superseded import deprecation + deprecation(32367, 'the method coefficients now only returns the non-zero coefficients. Use __getitem__ instead.') + + if P._internal_poly_ring.base_ring() is not P._laurent_poly_ring: + return list(islice(coeffs, n)) + + # flatten out the generator in the multivariate case + return list(islice(chain.from_iterable(map(lambda coeff: coeff.coefficients(), coeffs)), n)) + + def map_coefficients(self, f): + r""" + Return the series with ``f`` applied to each nonzero + coefficient of ``self``. + + INPUT: + + - ``func`` -- function that takes in a coefficient and returns + a new coefficient + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) sage: m = L(lambda n: n, valuation=0); m z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) sage: m.map_coefficients(lambda c: c + 1) 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) - An example where the series is known to be exact:: - - sage: f = z + z^2 + z^3 - sage: f.map_coefficients(lambda c: c + 1) - 2*z + 2*z^2 + 2*z^3 - Similarly for Dirichlet series:: sage: L = LazyDirichletSeriesRing(ZZ, "z") @@ -304,7 +500,50 @@ def map_coefficients(self, func, ring=None): sage: s.map_coefficients(lambda c: c + 1) 2/2^z + 3/3^z + 4/4^z + 5/5^z + 6/6^z + 7/7^z + O(1/(8^z)) - TESTS:: + Similarly for multivariate power series:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: f = 1/(1-(x+y)); f + 1 + (x+y) + (x^2+2*x*y+y^2) + (x^3+3*x^2*y+3*x*y^2+y^3) + + (x^4+4*x^3*y+6*x^2*y^2+4*x*y^3+y^4) + + (x^5+5*x^4*y+10*x^3*y^2+10*x^2*y^3+5*x*y^4+y^5) + + (x^6+6*x^5*y+15*x^4*y^2+20*x^3*y^3+15*x^2*y^4+6*x*y^5+y^6) + + O(x,y)^7 + sage: f.map_coefficients(lambda c: c^2) + 1 + (x+y) + (x^2+4*x*y+y^2) + (x^3+9*x^2*y+9*x*y^2+y^3) + + (x^4+16*x^3*y+36*x^2*y^2+16*x*y^3+y^4) + + (x^5+25*x^4*y+100*x^3*y^2+100*x^2*y^3+25*x*y^4+y^5) + + (x^6+36*x^5*y+225*x^4*y^2+400*x^3*y^3+225*x^2*y^4+36*x*y^5+y^6) + + O(x,y)^7 + + Similarly for lazy symmetric functions:: + + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(p) + sage: f = 1/(1-2*L(p[1])); f + p[] + 2*p[1] + (4*p[1,1]) + (8*p[1,1,1]) + (16*p[1,1,1,1]) + + (32*p[1,1,1,1,1]) + (64*p[1,1,1,1,1,1]) + O^7 + sage: f.map_coefficients(lambda c: log(c, 2)) + p[1] + (2*p[1,1]) + (3*p[1,1,1]) + (4*p[1,1,1,1]) + + (5*p[1,1,1,1,1]) + (6*p[1,1,1,1,1,1]) + O^7 + + TESTS: + + Dense implementation:: + + sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) + sage: s = z/(1 - 2*z^2) + sage: t = s.map_coefficients(lambda c: c + 1) + sage: s + z + 2*z^3 + 4*z^5 + 8*z^7 + O(z^8) + sage: t + 2*z + 3*z^3 + 5*z^5 + 9*z^7 + O(z^8) + sage: m = L(lambda n: n, valuation=0); m + z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + O(z^7) + sage: m.map_coefficients(lambda c: c + 1) + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + + Test the zero series:: sage: from sage.data_structures.stream import Stream_zero sage: L. = LazyLaurentSeriesRing(ZZ) @@ -313,12 +552,22 @@ def map_coefficients(self, func, ring=None): sage: isinstance(s._coeff_stream, Stream_zero) True + An example where the series is known to be exact:: + + sage: f = z + z^2 + z^3 + sage: f.map_coefficients(lambda c: c + 1) + 2*z + 2*z^2 + 2*z^3 + """ P = self.parent() coeff_stream = self._coeff_stream if isinstance(coeff_stream, Stream_zero): return self - BR = P.base_ring() + R = P._internal_poly_ring.base_ring() + if R is P._laurent_poly_ring: + func = lambda c: R(c).map_coefficients(f) + else: + func = f if isinstance(coeff_stream, Stream_exact): initial_coefficients = [func(i) if i else 0 for i in coeff_stream._initial_coefficients] @@ -326,13 +575,12 @@ def map_coefficients(self, func, ring=None): if not any(initial_coefficients) and not c: return P.zero() coeff_stream = Stream_exact(initial_coefficients, - self._coeff_stream._is_sparse, - order=coeff_stream._approximate_order, - degree=coeff_stream._degree, - constant=BR(c)) + self._coeff_stream._is_sparse, + order=coeff_stream._approximate_order, + degree=coeff_stream._degree, + constant=P.base_ring()(c)) return P.element_class(P, coeff_stream) - R = P._internal_poly_ring.base_ring() - coeff_stream = Stream_map_coefficients(self._coeff_stream, func, R) + coeff_stream = Stream_map_coefficients(self._coeff_stream, func) return P.element_class(P, coeff_stream) def truncate(self, d): @@ -345,7 +593,7 @@ def truncate(self, d): EXAMPLES: - Dense Implementation:: + Dense implementation:: sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: alpha = 1/(1-z) @@ -422,6 +670,11 @@ def shift(self, n): sage: f.shift(5).shift(-5) - f 0 + sage: L. = LazyPowerSeriesRing(QQ) + sage: f = x.shift(-3); f + x^-2 + sage: f.parent() + Lazy Laurent Series Ring in x over Rational Field """ if isinstance(self._coeff_stream, Stream_zero): return self @@ -441,6 +694,12 @@ def shift(self, n): else: coeff_stream = Stream_shift(self._coeff_stream, n) P = self.parent() + # If we shift it too much, then it needs to go into the fraction field + # FIXME? This is different than the polynomial rings, which truncates the terms + if (coeff_stream._true_order + and P._minimal_valuation is not None + and coeff_stream._approximate_order < P._minimal_valuation): + P = P.fraction_field() return P.element_class(P, coeff_stream) __lshift__ = shift @@ -477,6 +736,35 @@ def prec(self): """ return infinity + def lift_to_precision(self, absprec=None): + """ + Return another element of the same parent with absolute + precision at least ``absprec``, congruent to this element + modulo the precision of this element. + + Since the precision of a lazy series is infinity, this method + returns the series itself, and the argument is ignored. + + EXAMPLES:: + + sage: P. = PowerSeriesRing(QQ, default_prec=2) + sage: R. = LazyPowerSeriesRing(P) + sage: f = R(lambda n: 1/(1-t)^n) + sage: f + 1 + ((1+t+O(t^2))*z) + ((1+2*t+O(t^2))*z^2) + + ((1+3*t+O(t^2))*z^3) + + ((1+4*t+O(t^2))*z^4) + + ((1+5*t+O(t^2))*z^5) + + ((1+6*t+O(t^2))*z^6) + O(z^7) + sage: f.lift_to_precision() + 1 + ((1+t+O(t^2))*z) + ((1+2*t+O(t^2))*z^2) + + ((1+3*t+O(t^2))*z^3) + + ((1+4*t+O(t^2))*z^4) + + ((1+5*t+O(t^2))*z^5) + + ((1+6*t+O(t^2))*z^6) + O(z^7) + """ + return self + def _richcmp_(self, other, op): r""" Compare ``self`` with ``other`` with respect to the comparison @@ -515,35 +803,50 @@ def _richcmp_(self, other, op): Traceback (most recent call last): ... ValueError: undecidable + + TESTS:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: f = L([0,0,1,0,1,0,0,1], constant=1) + sage: g = L([0,0,1,0,1,0,0], degree=7, constant=1) + sage: f == g + True + """ if op is op_EQ: - if isinstance(self._coeff_stream, Stream_zero): # self == 0 + if isinstance(self._coeff_stream, Stream_zero): if isinstance(other._coeff_stream, Stream_zero): return True if other._coeff_stream.is_nonzero(): return False - # other == 0 but self likely != 0 - elif (isinstance(other._coeff_stream, Stream_zero) - and self._coeff_stream.is_nonzero()): - return False - - if (not isinstance(self._coeff_stream, Stream_exact) - or not isinstance(other._coeff_stream, Stream_exact)): - # One of the lazy laurent series is not known to eventually be constant - # Implement the checking of the caches here. - n = min(self._coeff_stream._approximate_order, other._coeff_stream._approximate_order) - m = max(self._coeff_stream._approximate_order, other._coeff_stream._approximate_order) - for i in range(n, m): - if self[i] != other[i]: - return False + elif isinstance(other._coeff_stream, Stream_zero): + if self._coeff_stream.is_nonzero(): + return False + elif isinstance(self._coeff_stream, Stream_exact): + if isinstance(other._coeff_stream, Stream_exact): + return self._coeff_stream == other._coeff_stream + if self._coeff_stream != other._coeff_stream: + return False + elif isinstance(other._coeff_stream, Stream_exact): + if other._coeff_stream != self._coeff_stream: + return False + else: + # both streams are inexact, perhaps they are equal by + # construction if self._coeff_stream == other._coeff_stream: return True + # perhaps their caches are different if self._coeff_stream != other._coeff_stream: return False - raise ValueError("undecidable") - # Both are Stream_exact, which implements a full check - return self._coeff_stream == other._coeff_stream + # undecidable otherwise + prec = self.parent().options['halting_precision'] + if prec is None: + raise ValueError("undecidable") + # at least one of the approximate orders is not infinity + m = min(self._coeff_stream._approximate_order, + other._coeff_stream._approximate_order) + return all(self[i] == other[i] for i in range(m, m + prec)) if op is op_NE: return not (self == other) @@ -570,6 +873,10 @@ def __bool__(self): """ Test whether ``self`` is not zero. + An uninitialized series returns ``True`` as it is considered + as a formal variable, such as a generator of a polynomial + ring. + TESTS:: sage: L. = LazyLaurentSeriesRing(GF(2)) @@ -604,11 +911,41 @@ def __bool__(self): 1 sage: bool(M) True + + Uninitialized series:: + + sage: g = L.undefined(valuation=0) + sage: bool(g) + True + sage: g.define(0) + sage: bool(g) + False + + sage: g = L.undefined(valuation=0) + sage: bool(g) + True + sage: g.define(1 + z) + sage: bool(g) + True + + sage: g = L.undefined(valuation=0) + sage: bool(g) + True + sage: g.define(1 + z*g) + sage: bool(g) + True """ if isinstance(self._coeff_stream, Stream_zero): return False if isinstance(self._coeff_stream, Stream_exact): return True + if isinstance(self._coeff_stream, Stream_uninitialized): + if self._coeff_stream._target is None: + return True + if isinstance(self._coeff_stream._target, Stream_zero): + return False + if isinstance(self._coeff_stream._target, Stream_exact): + return True if self.parent()._sparse: cache = self._coeff_stream._cache if any(cache[a] for a in cache): @@ -616,9 +953,15 @@ def __bool__(self): else: if any(a for a in self._coeff_stream._cache): return True - if self[self._coeff_stream._approximate_order]: + + v = self._coeff_stream._approximate_order + if self[v]: return True - raise ValueError("undecidable as lazy Laurent series") + + prec = self.parent().options['halting_precision'] + if prec is None: + raise ValueError("undecidable as lazy Laurent series") + return any(self[i] for i in range(v, v + prec)) def define(self, s): r""" @@ -626,42 +969,42 @@ def define(self, s): INPUT: - - ``s`` -- a Laurent polynomial + - ``s`` -- a lazy series EXAMPLES: We begin by constructing the Catalan numbers:: - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: C = L(None, valuation=0) + sage: L. = LazyPowerSeriesRing(ZZ) + sage: C = L.undefined() sage: C.define(1 + z*C^2) sage: C 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + O(z^7) The Catalan numbers but with a valuation 1:: - sage: B = L(None, valuation=1) + sage: B = L.undefined(valuation=1) sage: B.define(z + B^2) sage: B z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) We can define multiple series that are linked:: - sage: s = L(None, valuation=0) - sage: t = L(None, valuation=0) + sage: s = L.undefined() + sage: t = L.undefined() sage: s.define(1 + z*t^3) sage: t.define(1 + z*s^2) - sage: s[:9] + sage: s[0:9] [1, 1, 3, 9, 34, 132, 546, 2327, 10191] - sage: t[:9] + sage: t[0:9] [1, 1, 2, 7, 24, 95, 386, 1641, 7150] A bigger example:: - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: A = L(None, valuation=5) - sage: B = L(None, valuation=0) - sage: C = L(None, valuation=2) + sage: L. = LazyPowerSeriesRing(ZZ) + sage: A = L.undefined(valuation=5) + sage: B = L.undefined() + sage: C = L.undefined(valuation=2) sage: A.define(z^5 + B^2) sage: B.define(z^5 + C^2) sage: C.define(z^2 + C^2 + A^2) @@ -674,17 +1017,17 @@ def define(self, s): Counting binary trees:: - sage: L. = LazyLaurentSeriesRing(QQ) - sage: s = L(None, valuation=1) + sage: L. = LazyPowerSeriesRing(QQ) + sage: s = L.undefined(valuation=1) sage: s.define(z + (s^2+s(z^2))/2) - sage: [s[i] for i in range(9)] + sage: s[0:9] [0, 1, 1, 1, 2, 3, 6, 11, 23] The `q`-Catalan numbers:: sage: R. = ZZ[] sage: L. = LazyLaurentSeriesRing(R) - sage: s = L(None, valuation=0) + sage: s = L.undefined(valuation=0) sage: s.define(1+z*s*s(q*z)) sage: s 1 + z + (q + 1)*z^2 + (q^3 + q^2 + 2*q + 1)*z^3 @@ -697,29 +1040,31 @@ def define(self, s): and number of internal nodes:: sage: R. = QQ[] - sage: Q. = LazyLaurentSeriesRing(R) + sage: Q. = LazyPowerSeriesRing(R) sage: leaf = z sage: internal_node = q * z sage: L = Q(constant=1, degree=1) - sage: T = Q(None, valuation=1) + sage: T = Q.undefined(valuation=1) sage: T.define(leaf + internal_node * L(T)) - sage: [T[i] for i in range(6)] + sage: T[0:6] [0, 1, q, q^2 + q, q^3 + 3*q^2 + q, q^4 + 6*q^3 + 6*q^2 + q] Similarly for Dirichlet series:: sage: L = LazyDirichletSeriesRing(ZZ, "z") sage: g = L(constant=1, valuation=2) - sage: F = L(None); F.define(1 + g*F) - sage: [F[i] for i in range(1, 16)] + sage: F = L.undefined() + sage: F.define(1 + g*F) + sage: F[:16] [1, 1, 1, 2, 1, 3, 1, 4, 2, 3, 1, 8, 1, 3, 3] sage: oeis(_) # optional, internet 0: A002033: Number of perfect partitions of n. 1: A074206: Kalmár's [Kalmar's] problem: number of ordered factorizations of n. ... - sage: F = L(None); F.define(1 + g*F*F) - sage: [F[i] for i in range(1, 16)] + sage: F = L.undefined() + sage: F.define(1 + g*F*F) + sage: F[:16] [1, 1, 1, 3, 1, 5, 1, 10, 3, 5, 1, 24, 1, 5, 5] We can compute the Frobenius character of unlabeled trees:: @@ -729,10 +1074,10 @@ def define(self, s): sage: L = LazySymmetricFunctions(m) sage: E = L(lambda n: s[n], valuation=0) sage: X = L(s[1]) - sage: A = L(None); A.define(X*E(A, check=False)) + sage: A = L.undefined() + sage: A.define(X*E(A, check=False)) sage: A[:6] - [0, - m[1], + [m[1], 2*m[1, 1] + m[2], 9*m[1, 1, 1] + 5*m[2, 1] + 2*m[3], 64*m[1, 1, 1, 1] + 34*m[2, 1, 1] + 18*m[2, 2] + 13*m[3, 1] + 4*m[4], @@ -741,12 +1086,12 @@ def define(self, s): TESTS:: sage: L. = LazyLaurentSeriesRing(ZZ, sparse=True) - sage: s = L(None, valuation=0) - sage: s.define(1 + z*s^3) - sage: s[:10] + sage: s = L.undefined(valuation=-1) + sage: s.define(z^-1 + z^3*s^3) + sage: s[-1:9] [1, 1, 3, 12, 55, 273, 1428, 7752, 43263, 246675] - sage: e = L(None, valuation=0) + sage: e = L.undefined(valuation=0) sage: e.define(1 + z*e) sage: e.define(1 + z*e) Traceback (most recent call last): @@ -757,17 +1102,122 @@ def define(self, s): ... ValueError: series already defined + sage: e = L.undefined(valuation=0) + sage: e.define(1) + sage: e + 1 + + sage: e = L.undefined(valuation=0) + sage: e.define((1 + z).polynomial()) + sage: e + 1 + z + sage: D = LazyDirichletSeriesRing(QQ, "s") sage: L. = LazyLaurentSeriesRing(QQ) sage: e = L(lambda n: 1/factorial(n), 0) - sage: g = D(None, valuation=2) + sage: g = D.undefined(valuation=2) sage: o = D(constant=1, valuation=2) sage: g.define(o * e(g)) sage: g 1/(2^s) + 1/(3^s) + 2/4^s + 1/(5^s) + 3/6^s + 1/(7^s) + 9/2/8^s + O(1/(9^s)) + + For Laurent series there is no minimal valuation, so it has + to be specified:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: L.undefined() + Traceback (most recent call last): + ... + ValueError: the valuation must be specified for undefined series + + For power series and Dirichlet series there is a minimal + valuation, which is why the following work:: + + sage: P. = LazyPowerSeriesRing(QQ) + sage: f = P.undefined() + sage: f.define(1 - ~f*x) + sage: f + 1 - x - x^2 - 2*x^3 - 5*x^4 - 14*x^5 - 42*x^6 + O(x^7) + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: g = D([0, 1]) + sage: f = D.undefined() + sage: f.define(1 + ~f*g) + sage: f + 1 + 1/(2^s) - 1/(4^s) + O(1/(8^s)) + + sage: oeis(f[:30]) # optional, internet + 0: A122698: a(1)=a(2)=1 then a(n) = Sum_{d|n, 1 = LazyPowerSeriesRing(QQ) + sage: f = L.undefined() + sage: f.define(1+(t*f).revert()) + sage: f + 1 + t - t^2 + 3*t^3 - 13*t^4 + 69*t^5 - 419*t^6 + O(t^7) + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: f = L.undefined(valuation=0) + sage: f.define(1+(t*f).revert()) + sage: f + 1 + t - t^2 + 3*t^3 - 13*t^4 + 69*t^5 - 419*t^6 + O(t^7) + + sage: f = L.undefined(valuation=0) + sage: f.define(1+(t*~f).revert()) + sage: f + 1 + t + t^2 + 2*t^3 + 6*t^4 + 23*t^5 + 104*t^6 + O(t^7) + sage: oeis(f[1:20]) # optional, internet + 0: A030266: Shifts left under COMPOSE transform with itself. + 1: A110447: Permutations containing 3241 patterns only as part of 35241 patterns. + + The following can only work for power series, where we have a + minimal valuation of `0`:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: f = L.undefined(valuation=0) + sage: f.define(1 - t*~(-f) - (-t*f).revert()) + sage: f + 1 + 2*t + 12*t^3 + 32*t^4 + 368*t^5 + 2192*t^6 + O(t^7) + + sage: s = SymmetricFunctions(QQ).s() + sage: L = LazySymmetricFunctions(s) + sage: f = L.undefined() + sage: f.define(1+(s[1]*f).revert()) + sage: f + s[] + s[1] + (-s[1,1]-s[2]) + + (3*s[1,1,1]+6*s[2,1]+3*s[3]) + + (-13*s[1,1,1,1]-39*s[2,1,1]-26*s[2,2]-39*s[3,1]-13*s[4]) + + (69*s[1,1,1,1,1]+276*s[2,1,1,1]+345*s[2,2,1]+414*s[3,1,1]+345*s[3,2]+276*s[4,1]+69*s[5]) + + (-419*s[1,1,1,1,1,1]-2095*s[2,1,1,1,1]-3771*s[2,2,1,1]-2095*s[2,2,2]-4190*s[3,1,1,1]-6704*s[3,2,1]-2095*s[3,3]-4190*s[4,1,1]-3771*s[4,2]-2095*s[5,1]-419*s[6]) + + O^7 + + sage: (f*s[1]).revert() + 1 - f + O^7 + """ if not isinstance(self._coeff_stream, Stream_uninitialized) or self._coeff_stream._target is not None: raise ValueError("series already defined") + + if not isinstance(s, LazyModuleElement): + s = self.parent()(s) + + # Special case when it has a trivial definition + if isinstance(s._coeff_stream, (Stream_zero, Stream_exact)): + self._coeff_stream = s._coeff_stream + return + self._coeff_stream._target = s._coeff_stream # an alias for compatibility with padics @@ -801,7 +1251,7 @@ def _repr_(self): sage: L(lambda x: x if x > 0 else 0, valuation=-10) O(z^-3) - sage: L(None, valuation=0) + sage: L.undefined(valuation=0) Uninitialized Lazy Laurent Series sage: L(0) 0 @@ -848,7 +1298,7 @@ def _latex_(self): sage: latex(L(lambda x: x if x > 0 else 0, valuation=-10)) O(\frac{1}{z^{3}}) - sage: latex(L(None, valuation=0)) + sage: latex(L.undefined(valuation=0)) \text{\texttt{Undef}} sage: latex(L(0)) 0 @@ -959,7 +1409,7 @@ def change_ring(self, ring): A Taylor series example:: - sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L. = LazyPowerSeriesRing(ZZ) sage: s = 2 + z sage: t = s.change_ring(QQ) sage: t^-1 @@ -968,7 +1418,10 @@ def change_ring(self, ring): Lazy Taylor Series Ring in z over Rational Field """ P = self.parent() - Q = type(P)(ring, names=P.variable_names(), sparse=P._sparse) + if P._names is None: + Q = type(P)(ring, sparse=P._sparse) + else: + Q = type(P)(ring, names=P.variable_names(), sparse=P._sparse) return Q.element_class(Q, self._coeff_stream) # === module structure === @@ -1369,7 +1822,7 @@ def exp(self): ... ValueError: can only compose with a positive valuation series - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: exp(x+y)[4].factor() (1/24) * (x + y)^4 sage: exp(x/(1-y)).polynomial(3) @@ -1380,10 +1833,17 @@ def exp(self): sage: L. = LazyLaurentSeriesRing(QQ); x = var("x") sage: exp(z)[0:6] == exp(x).series(x, 6).coefficients(sparse=False) True + + Check the exponential when the base ring is a lazy ring:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: M. = LazyPowerSeriesRing(L) + sage: exp(x) + 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + 1/720*x^6 + O(x^7) """ from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(lambda n: 1/factorial(ZZ(n)), valuation=0) + f = P(coefficients=lambda n: 1/factorial(ZZ(n)), valuation=0) return f(self) def log(self): @@ -1396,7 +1856,7 @@ def log(self): sage: log(1/(1-z)) z + 1/2*z^2 + 1/3*z^3 + 1/4*z^4 + 1/5*z^5 + 1/6*z^6 + 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: log((1 + x/(1-y))).polynomial(3) 1/3*x^3 - x^2*y + x*y^2 - 1/2*x^2 + x*y + x @@ -1413,7 +1873,7 @@ def log(self): """ from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(lambda n: ((-1) ** (n + 1))/ZZ(n), valuation=1) + f = P(coefficients=lambda n: ((-1) ** (n + 1))/ZZ(n), valuation=1) return f(self-1) # trigonometric functions @@ -1433,7 +1893,7 @@ def sin(self): ... ValueError: can only compose with a positive valuation series - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: sin(x/(1-y)).polynomial(3) -1/6*x^3 + x*y^2 + x*y + x @@ -1445,8 +1905,8 @@ def sin(self): """ from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(lambda n: (n % 2)/factorial(ZZ(n)) if n % 4 == 1 else -(n % 2)/factorial(ZZ(n)), - valuation=1) + c = lambda n: (n % 2)/factorial(ZZ(n)) if n % 4 == 1 else -(n % 2)/factorial(ZZ(n)) + f = P(coefficients=c, valuation=1) return f(self) def cos(self): @@ -1459,7 +1919,7 @@ def cos(self): sage: cos(z) 1 - 1/2*z^2 + 1/24*z^4 - 1/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: cos(x/(1-y)).polynomial(4) 1/24*x^4 - 3/2*x^2*y^2 - x^2*y - 1/2*x^2 + 1 @@ -1471,8 +1931,8 @@ def cos(self): """ from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(lambda n: 1/factorial(ZZ(n)) if n % 4 == 0 else (n % 2 - 1)/factorial(ZZ(n)), - valuation=0) + c = lambda n: 1/factorial(ZZ(n)) if n % 4 == 0 else (n % 2 - 1)/factorial(ZZ(n)) + f = P(coefficients=c, valuation=0) return f(self) def tan(self): @@ -1485,7 +1945,7 @@ def tan(self): sage: tan(z) z + 1/3*z^3 + 2/15*z^5 + 17/315*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: tan(x/(1-y)).polynomial(5) 2/15*x^5 + 2*x^3*y^2 + x*y^4 + x^3*y + x*y^3 + 1/3*x^3 + x*y^2 + x*y + x @@ -1551,7 +2011,7 @@ def sec(self): sage: sec(z) 1 + 1/2*z^2 + 5/24*z^4 + 61/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: sec(x/(1-y)).polynomial(4) 5/24*x^4 + 3/2*x^2*y^2 + x^2*y + 1/2*x^2 + 1 @@ -1575,7 +2035,7 @@ def arcsin(self): sage: arcsin(z) z + 1/6*z^3 + 3/40*z^5 + 5/112*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: asin(x/(1-y)) x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + (3/40*x^5+x^3*y^2+x*y^4) + (3/8*x^5*y+5/3*x^3*y^3+x*y^5) @@ -1613,7 +2073,7 @@ def arccos(self): sage: arccos(z/(1-z)) 1/2*pi - z - z^2 - 7/6*z^3 - 3/2*z^4 - 83/40*z^5 - 73/24*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) + sage: L. = LazyPowerSeriesRing(SR) sage: arccos(x/(1-y)) 1/2*pi + (-x) + (-x*y) + ((-1/6)*x^3-x*y^2) + ((-1/2)*x^3*y-x*y^3) + ((-3/40)*x^5-x^3*y^2-x*y^4) + ((-3/8)*x^5*y+(-5/3)*x^3*y^3-x*y^5) + O(x,y)^7 @@ -1637,7 +2097,7 @@ def arctan(self): sage: arctan(z) z - 1/3*z^3 + 1/5*z^5 - 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: atan(x/(1-y)) x + x*y + (-1/3*x^3+x*y^2) + (-x^3*y+x*y^3) + (1/5*x^5-2*x^3*y^2+x*y^4) + (x^5*y-10/3*x^3*y^3+x*y^5) + (-1/7*x^7+3*x^5*y^2-5*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1676,7 +2136,7 @@ def arccot(self): sage: arccot(z/(1-z)) 1/2*pi - z - z^2 - 2/3*z^3 + 4/5*z^5 + 4/3*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(SR) + sage: L. = LazyPowerSeriesRing(SR) sage: acot(x/(1-y)) 1/2*pi + (-x) + (-x*y) + (1/3*x^3-x*y^2) + (x^3*y-x*y^3) + ((-1/5)*x^5+2*x^3*y^2-x*y^4) + (-x^5*y+10/3*x^3*y^3-x*y^5) + O(x,y)^7 @@ -1702,7 +2162,7 @@ def sinh(self): sage: sinh(z) z + 1/6*z^3 + 1/120*z^5 + 1/5040*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: sinh(x/(1-y)) x + x*y + (1/6*x^3+x*y^2) + (1/2*x^3*y+x*y^3) + (1/120*x^5+x^3*y^2+x*y^4) + (1/24*x^5*y+5/3*x^3*y^3+x*y^5) @@ -1716,7 +2176,7 @@ def sinh(self): """ from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(lambda n: 1/factorial(ZZ(n)) if n % 2 else ZZ.zero(), + f = P(coefficients=lambda n: 1/factorial(ZZ(n)) if n % 2 else ZZ.zero(), valuation=1) return f(self) @@ -1730,7 +2190,7 @@ def cosh(self): sage: cosh(z) 1 + 1/2*z^2 + 1/24*z^4 + 1/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: cosh(x/(1-y)) 1 + 1/2*x^2 + x^2*y + (1/24*x^4+3/2*x^2*y^2) + (1/6*x^4*y+2*x^2*y^3) + (1/720*x^6+5/12*x^4*y^2+5/2*x^2*y^4) + O(x,y)^7 @@ -1743,7 +2203,7 @@ def cosh(self): """ from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(lambda n: ZZ.zero() if n % 2 else 1/factorial(ZZ(n)), + f = P(coefficients=lambda n: ZZ.zero() if n % 2 else 1/factorial(ZZ(n)), valuation=0) return f(self) @@ -1757,7 +2217,7 @@ def tanh(self): sage: tanh(z) z - 1/3*z^3 + 2/15*z^5 - 17/315*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: tanh(x/(1-y)) x + x*y + (-1/3*x^3+x*y^2) + (-x^3*y+x*y^3) + (2/15*x^5-2*x^3*y^2+x*y^4) + (2/3*x^5*y-10/3*x^3*y^3+x*y^5) + (-17/315*x^7+2*x^5*y^2-5*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1776,7 +2236,7 @@ def f(n): n = ZZ(n) if n % 2: h = 4 ** ((n + 1) // 2) - return bernoulli(n + 1) * h * (h -1) / factorial(n + 1) + return bernoulli(n + 1) * h * (h - 1) / factorial(n + 1) return ZZ.zero() return P(f, valuation=1)(self) @@ -1820,7 +2280,7 @@ def sech(self): sage: sech(z) 1 - 1/2*z^2 + 5/24*z^4 - 61/720*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: sech(x/(1-y)) 1 + (-1/2*x^2) + (-x^2*y) + (5/24*x^4-3/2*x^2*y^2) + (5/6*x^4*y-2*x^2*y^3) + (-61/720*x^6+25/12*x^4*y^2-5/2*x^2*y^4) + O(x,y)^7 @@ -1890,7 +2350,7 @@ def arcsinh(self): sage: arcsinh(z) z - 1/6*z^3 + 3/40*z^5 - 5/112*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: asinh(x/(1-y)) x + x*y + (-1/6*x^3+x*y^2) + (-1/2*x^3*y+x*y^3) + (3/40*x^5-x^3*y^2+x*y^4) + (3/8*x^5*y-5/3*x^3*y^3+x*y^5) + (-5/112*x^7+9/8*x^5*y^2-5/2*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1928,7 +2388,7 @@ def arctanh(self): sage: arctanh(z) z + 1/3*z^3 + 1/5*z^5 + 1/7*z^7 + O(z^8) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: atanh(x/(1-y)) x + x*y + (1/3*x^3+x*y^2) + (x^3*y+x*y^3) + (1/5*x^5+2*x^3*y^2+x*y^4) + (x^5*y+10/3*x^3*y^3+x*y^5) + (1/7*x^7+3*x^5*y^2+5*x^3*y^4+x*y^6) + O(x,y)^8 @@ -1942,7 +2402,7 @@ def arctanh(self): """ from .lazy_series_ring import LazyLaurentSeriesRing P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) - f = P(lambda n: 1/ZZ(n) if n % 2 else ZZ.zero(), valuation=1) + f = P(coefficients=lambda n: 1/ZZ(n) if n % 2 else ZZ.zero(), valuation=1) return f(self) def hypergeometric(self, a, b): @@ -1963,7 +2423,7 @@ def hypergeometric(self, a, b): sage: z.hypergeometric([], []) - exp(z) O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: (x+y).hypergeometric([1, 1], [1]).polynomial(4) x^4 + 4*x^3*y + 6*x^2*y^2 + 4*x*y^3 + y^4 + x^3 + 3*x^2*y + 3*x*y^2 + y^3 + x^2 + 2*x*y + y^2 + x + y + 1 @@ -1984,7 +2444,7 @@ def coeff(n, c): for term in range(len(c)): num *= rising_factorial(c[term], n) return num - f = P(lambda n: coeff(n, a) / (coeff(n, b) * factorial(ZZ(n))), + f = P(coefficients=lambda n: coeff(n, a) / (coeff(n, b) * factorial(ZZ(n))), valuation=0) return f(self) @@ -2038,10 +2498,10 @@ def __pow__(self, n): P = LazyLaurentSeriesRing(self.base_ring(), "z", sparse=self.parent()._sparse) if n in QQ or n in self.base_ring(): - f = P(lambda k: prod(n - i for i in range(k)) / ZZ(k).factorial(), valuation=0) + f = P(coefficients=lambda k: prod(n - i for i in range(k)) / ZZ(k).factorial(), valuation=0) return f(self - 1) - exp = P(lambda k: 1 / ZZ(k).factorial(), valuation=0) + exp = P(coefficients=lambda k: 1 / ZZ(k).factorial(), valuation=0) return exp(self.log() * n) def sqrt(self): @@ -2054,7 +2514,7 @@ def sqrt(self): sage: sqrt(1+z) 1 + 1/2*z - 1/8*z^2 + 1/16*z^3 - 5/128*z^4 + 7/256*z^5 - 21/1024*z^6 + O(z^7) - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: sqrt(1+x/(1-y)) 1 + 1/2*x + (-1/8*x^2+1/2*x*y) + (1/16*x^3-1/4*x^2*y+1/2*x*y^2) + (-5/128*x^4+3/16*x^3*y-3/8*x^2*y^2+1/2*x*y^3) @@ -2187,6 +2647,14 @@ def _mul_(self, other): sage: t1 = t.approximate_series(44) sage: s1 * t1 - (s * t).approximate_series(42) O(z^42) + + Check products with exact series:: + + sage: L([1], constant=3)^2 + 1 + 6*z + 15*z^2 + 24*z^3 + 33*z^4 + 42*z^5 + 51*z^6 + O(z^7) + + sage: (1+z) * L([1,0,1], constant=1) + 1 + z + z^2 + 2*z^3 + 2*z^4 + 2*z^5 + O(z^6) """ P = self.parent() left = self._coeff_stream @@ -2195,15 +2663,21 @@ def _mul_(self, other): # Check some trivial products if isinstance(left, Stream_zero) or isinstance(right, Stream_zero): return P.zero() - if isinstance(left, Stream_exact) and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and left.order() == 0: + if (isinstance(left, Stream_exact) + and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) + and left.order() == 0 + and not left._constant): return other # self == 1 - if isinstance(right, Stream_exact) and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and right.order() == 0: + if (isinstance(right, Stream_exact) + and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) + and right.order() == 0 + and not right._constant): return self # right == 1 - # The product is exact if and only if both factors are exact # and one of the factors has eventually 0 coefficients: # (p + a x^d/(1-x))(q + b x^e/(1-x)) # = p q + (a x^d q + b x^e p)/(1-x) + a b x^(d+e)/(1-x)^2 + # TODO: this is not true in characteristic 2 if (isinstance(left, Stream_exact) and isinstance(right, Stream_exact) and not (left._constant and right._constant)): @@ -2221,7 +2695,8 @@ def _mul_(self, other): # coefficients of q. if right._constant: d = right._degree - c = left._constant # this is zero + c = left._constant # this is zero + initial_coefficients.extend([c]*(d - rv - len(ir))) # left._constant must be 0 and thus len(il) >= 1 for k in range(len(il)-1): c += il[k] * right._constant @@ -2229,14 +2704,15 @@ def _mul_(self, other): c += il[-1] * right._constant elif left._constant: d = left._degree - c = right._constant # this is zero + c = right._constant # this is zero + initial_coefficients.extend([c]*(d - lv - len(il))) # left._constant must be 0 and thus len(il) >= 1 for k in range(len(ir)-1): c += left._constant * ir[k] initial_coefficients[d - lv + k] += c c += left._constant * ir[-1] else: - c = left._constant # this is zero + c = left._constant # this is zero coeff_stream = Stream_exact(initial_coefficients, P._sparse, order=lv + rv, @@ -2358,17 +2834,38 @@ def __invert__(self): sage: ~z z^-1 + We can also compute the multiplicative inverse of a symmetric + function:: + + sage: h = SymmetricFunctions(QQ).h() + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(p) + sage: E = L(lambda n: h[n]) + sage: (~E)[:4] + [p[], -p[1], 1/2*p[1, 1] - 1/2*p[2], -1/6*p[1, 1, 1] + 1/2*p[2, 1] - 1/3*p[3]] + + sage: (E * ~E)[:6] + [p[], 0, 0, 0, 0, 0] + TESTS:: sage: L. = LazyLaurentSeriesRing(QQ) sage: g = L([2], valuation=-1, constant=1); g 2*x^-1 + 1 + x + x^2 + O(x^3) - sage: g*g^-1 + sage: g * g^-1 1 + O(x^7) + sage: L. = LazyPowerSeriesRing(QQ) + sage: ~(x + x^2) + Traceback (most recent call last): + ... + ZeroDivisionError: cannot divide by a series of positive valuation """ P = self.parent() coeff_stream = self._coeff_stream + if P._minimal_valuation is not None and coeff_stream._approximate_order > 0: + raise ZeroDivisionError("cannot divide by a series of positive valuation") + # the inverse is exact if and only if coeff_stream corresponds to one of # cx^d/(1-x) ... (c, ...) # cx^d ... (c, 0, ...) @@ -2395,7 +2892,7 @@ def __invert__(self): return P.element_class(P, coeff_stream) if (len(initial_coefficients) == 2 and not (initial_coefficients[0] + initial_coefficients[1]) - and not coeff_stream._constant): + and not coeff_stream._constant): v = -coeff_stream.order() c = ~initial_coefficients[0] coeff_stream = Stream_exact((), @@ -2407,7 +2904,10 @@ def __invert__(self): # (f^-1)^-1 = f if isinstance(coeff_stream, Stream_cauchy_invert): return P.element_class(P, coeff_stream._series) - return P.element_class(P, Stream_cauchy_invert(coeff_stream)) + + coeff_stream_inverse = Stream_cauchy_invert(coeff_stream, + approximate_order=P._minimal_valuation) + return P.element_class(P, coeff_stream_inverse) def _div_(self, other): r""" @@ -2466,22 +2966,70 @@ def _div_(self, other): Examples for multivariate Taylor series:: - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: 1 / (1 - y) 1 + y + y^2 + y^3 + y^4 + y^5 + y^6 + O(x,y)^7 sage: (x + y) / (1 - y) (x+y) + (x*y+y^2) + (x*y^2+y^3) + (x*y^3+y^4) + (x*y^4+y^5) + (x*y^5+y^6) + (x*y^6+y^7) + O(x,y)^8 + TESTS:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: t / L(1) + t + + sage: t^3 * (1+2*t+3*t^2+4*t^3) / (t-t^2) + t^2 + 3*t^3 + 6*t^4 + 10*t^5 + 10*t^6 + 10*t^7 + O(t^8) + + sage: t^3 * ((1+2*t+3*t^2+4*t^3) / (t-t^2)) + t^2 + 3*t^3 + 6*t^4 + 10*t^5 + 10*t^6 + 10*t^7 + O(t^8) + + sage: L(lambda n: n) / (t + t^2) + 1 + t + 2*t^2 + 2*t^3 + 3*t^4 + 3*t^5 + O(t^6) + + Check that division by one does nothing, and division by + itself gives one:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: S = LazySymmetricFunctions(s) + sage: f = S(lambda n: s(Partitions(n).random_element())) + sage: f / S.one() is f + True + + sage: f / f + s[] + """ if isinstance(other._coeff_stream, Stream_zero): raise ZeroDivisionError("cannot divide by 0") P = self.parent() left = self._coeff_stream + # self == 0 if isinstance(left, Stream_zero): return P.zero() right = other._coeff_stream + + # right == 1 + if (isinstance(right, Stream_exact) + and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) + and right.order() == 0 + and not right._constant): + return self + + # self is right + if left is right: + return P.one() + + if (P._minimal_valuation is not None + and left._true_order + and left._approximate_order < right._approximate_order): + F = P.fraction_field() + num = F.element_class(F, left) + den = F.element_class(F, right) + return num / den + R = P._internal_poly_ring if (isinstance(left, Stream_exact) and isinstance(right, Stream_exact) @@ -2502,9 +3050,11 @@ def _div_(self, other): den = den // g exponents = den.exponents() if len(exponents) == 1: + # dividing by z^k d = den[exponents[0]] - initial_coefficients = [c / d for c in num] - order = num.valuation() - den.valuation() + v = num.valuation() + initial_coefficients = [num[i] / d for i in range(v, num.degree() + 1)] + order = v - den.valuation() return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, order=order, @@ -2513,6 +3063,7 @@ def _div_(self, other): if (len(exponents) == 2 and exponents[0] + 1 == exponents[1] and den[exponents[0]] == -den[exponents[1]]): + # dividing by z^k (1-z) quo, rem = num.quo_rem(den) # rem is a unit, i.e., in the Laurent case c*z^v v_rem = rem.exponents()[0] @@ -2529,7 +3080,8 @@ def _div_(self, other): order = quo.valuation() else: order = 0 - return P.element_class(P, Stream_exact(list(quo), + initial_coefficients = [quo[i] for i in range(order, quo.degree() + 1)] + return P.element_class(P, Stream_exact(initial_coefficients, P._sparse, order=order, degree=v, @@ -2540,8 +3092,43 @@ def _div_(self, other): degree=v, constant=constant)) - return P.element_class(P, Stream_cauchy_mul(left, Stream_cauchy_invert(right))) + # we cannot pass the approximate order here, even when + # P._minimal_valuation is zero, because we allow division by + # series of positive valuation + right_inverse = Stream_cauchy_invert(right) + return P.element_class(P, Stream_cauchy_mul(left, right_inverse)) + + + def _floordiv_(self, other): + r""" + Return ``self`` floor divided by ``other``. + + INPUT: + + - ``other`` -- nonzero series + + EXAMPLES:: + sage: L. = LazyLaurentSeriesRing(QQ) + sage: g = (x + 2*x^2) / (1 - x - x^2) + sage: x // g + 1 - 3*x + 5*x^2 - 10*x^3 + 20*x^4 - 40*x^5 + 80*x^6 + O(x^7) + sage: 1 // g + x^-1 - 3 + 5*x - 10*x^2 + 20*x^3 - 40*x^4 + 80*x^5 + O(x^6) + sage: x^-3 // g + x^-4 - 3*x^-3 + 5*x^-2 - 10*x^-1 + 20 - 40*x + 80*x^2 + O(x^3) + sage: f = (x + x^2) / (1 - x) + sage: f // g + 1 - x + x^2 - 4*x^3 + 6*x^4 - 14*x^5 + 26*x^6 + O(x^7) + sage: g // f + 1 + x + 3*x^3 + x^4 + 6*x^5 + 5*x^6 + O(x^7) + """ + if isinstance(other._coeff_stream, Stream_zero): + raise ZeroDivisionError("cannot divide by 0") + P = self.parent() + if P not in IntegralDomains(): + raise TypeError("must be an integral domain") + return P(self / other) class LazyLaurentSeries(LazyCauchyProductSeries): r""" @@ -2614,12 +3201,63 @@ class LazyLaurentSeries(LazyCauchyProductSeries): sage: f = 1 / (1 - z - z^2) sage: TestSuite(f).run() """ + def is_unit(self): + """ + Return whether this element is a unit in the ring. - def __call__(self, g, *, check=True): - r""" - Return the composition of ``self`` with ``g``. + EXAMPLES:: - Given two Laurent Series `f` and `g` over the same base ring, the + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: (2*z).is_unit() + False + + sage: (1 + 2*z).is_unit() + True + + sage: (1 + 2*z^-1).is_unit() + False + + sage: (z^3 + 4 - z^-2).is_unit() + True + """ + if self.is_zero(): # now 0 != 1 + return False + a = self[self.valuation()] + return a.is_unit() + + def _im_gens_(self, codomain, im_gens, base_map=None): + """ + Return the image of ``self`` under the map that sends the + generators of the parent of ``self`` to the elements of the + tuple ``im_gens``. + + EXAMPLES:: + + sage: Z. = ZZ[] + sage: K. = NumberField(x^2 + 1) + sage: R. = LazyLaurentSeriesRing(K) + sage: f = R(lambda n: i^n, valuation=-2) + sage: f + -t^-2 - i*t^-1 + 1 + i*t - t^2 - i*t^3 + t^4 + O(t^5) + sage: f._im_gens_(R, [t + t^2]) + -t^-2 + (-i + 2)*t^-1 + (i - 2) + 4*t + (2*i - 6)*t^2 + + (-2*i + 4)*t^3 + (-2*i - 7)*t^4 + O(t^5) + + sage: cc = K.hom([-i]) + sage: f._im_gens_(R, [t + t^2], base_map=cc) + -t^-2 + (i + 2)*t^-1 + (-i - 2) + 4*t + (-2*i - 6)*t^2 + + (2*i + 4)*t^3 + (2*i - 7)*t^4 + O(t^5) + """ + if base_map is None: + return codomain(self(im_gens[0])) + + return codomain(self.map_coefficients(base_map)(im_gens[0])) + + def __call__(self, g, *, check=True): + r""" + Return the composition of ``self`` with ``g``. + + Given two Laurent series `f` and `g` over the same base ring, the composition `(f \circ g)(z) = f(g(z))` is defined if and only if: - `g = 0` and `val(f) >= 0`, @@ -2820,7 +3458,7 @@ def __call__(self, g, *, check=True): ZeroDivisionError: the valuation of the series must be nonnegative `g \neq 0` and `val(g) \leq 0` and `f` has infinitely many - non-zero coefficients`:: + non-zero coefficients:: sage: g = z^-1 + z^-2 sage: g.valuation() <= 0 @@ -2889,8 +3527,17 @@ def __call__(self, g, *, check=True): 3 sage: parent(three) Univariate Polynomial Ring in x over Rational Field + + Consistency check when `g` is an uninitialized series between a + polynomial `f` as both a polynomial and a lazy series:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: f = 1 + z + sage: g = L.undefined(valuation=0) + sage: f(g) == f.polynomial()(g) + True """ - # f = self and compute f(g) + # Find a good parent for the result from sage.structure.element import get_coercion_model cm = get_coercion_model() P = cm.common_parent(self.base_ring(), parent(g)) @@ -3001,8 +3648,9 @@ def __call__(self, g, *, check=True): def coefficient(n): return sum(self[i] * (g**i)[n] for i in range(n+1)) + R = P._internal_poly_ring.base_ring() - coeff_stream = Stream_function(coefficient, R, P._sparse, 1) + coeff_stream = Stream_function(coefficient, P._sparse, 1) return P.element_class(P, coeff_stream) coeff_stream = Stream_cauchy_compose(self._coeff_stream, g._coeff_stream) @@ -3014,45 +3662,71 @@ def revert(self): r""" Return the compositional inverse of ``self``. - Given a Laurent Series `f`. the compositional inverse is a - Laurent Series `g` over the same base ring, such that + Given a Laurent series `f`, the compositional inverse is a + Laurent series `g` over the same base ring, such that `(f \circ g)(z) = f(g(z)) = z`. The compositional inverse exists if and only if: - `val(f) = 1`, or - - `f = a + b z` with `a b \neq 0`, or + - `f = a + b z` with `a, b \neq 0`, or - `f = a/z` with `a \neq 0` EXAMPLES:: - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: z.revert() - z + O(z^8) - sage: (1/z).revert() - z^-1 + sage: L. = LazyLaurentSeriesRing(QQ) + sage: (2*z).revert() + 1/2*z + sage: (2/z).revert() + 2*z^-1 sage: (z-z^2).revert() z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) + sage: s = L(degree=1, constant=-1) + sage: s.revert() + -z - z^2 - z^3 + O(z^4) + + sage: s = L(degree=1, constant=1) + sage: s.revert() + z - z^2 + z^3 - z^4 + z^5 - z^6 + z^7 + O(z^8) + TESTS:: sage: L. = LazyLaurentSeriesRing(QQ) - sage: s = L(lambda n: 1 if n == 1 else 0, valuation=1); s - z + O(z^8) + sage: s = L(lambda n: 2 if n == 1 else 0, valuation=1); s + 2*z + O(z^8) sage: s.revert() - z + O(z^8) + 1/2*z + O(z^8) sage: (2+3*z).revert() -2/3 + 1/3*z sage: s = L(lambda n: 2 if n == 0 else 3 if n == 1 else 0, valuation=0); s 2 + 3*z + O(z^7) + sage: f = s.revert() + sage: f[1] + Traceback (most recent call last): + ... + ValueError: inverse does not exist + + sage: s = L(lambda n: 1, valuation=-2); s + z^-2 + z^-1 + 1 + z + z^2 + z^3 + z^4 + O(z^5) + sage: f = s.revert() + sage: f[1] + Traceback (most recent call last): + ... + ValueError: inverse does not exist + + sage: R. = QQ[] + sage: L. = LazyLaurentSeriesRing(R.fraction_field()) + sage: s = L([q], valuation=0, constant=t); s + q + t*z + t*z^2 + t*z^3 + O(z^4) sage: s.revert() Traceback (most recent call last): ... - ValueError: cannot determine whether the compositional inverse exists + ValueError: compositional inverse does not exist We look at some cases where the compositional inverse does not exist: @@ -3067,7 +3741,7 @@ def revert(self): ... ValueError: compositional inverse does not exist - `val(f) ! = 1` and `f(0) * f(1) = 0`:: + `val(f) != 1` and `f(0) * f(1) = 0`:: sage: (z^2).revert() Traceback (most recent call last): @@ -3078,30 +3752,175 @@ def revert(self): Traceback (most recent call last): ... ValueError: compositional inverse does not exist + + Reversion of exact series:: + + sage: f = L([2], valuation=-1, constant=2) + sage: f.revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + sage: f = L([1, 2], valuation=0, constant=1) + sage: f.revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + sage: f = L([-1, -1], valuation=1, constant=-1) + sage: f.revert() + -z - z^2 - z^3 + O(z^4) + + sage: f = L([-1, 0, -1], valuation=1, constant=-1) + sage: f.revert() + (1/(-1))*z + z^3 - z^4 - 2*z^5 + 6*z^6 + z^7 + O(z^8) + + sage: f = L([-1], valuation=1, degree=3, constant=-1) + sage: f.revert() + (1/(-1))*z + z^3 - z^4 - 2*z^5 + 6*z^6 + z^7 + O(z^8) """ P = self.parent() - if self.valuation() == 1: - z = P.gen() - g = P(None, valuation=1) - g.define(z/((self/z)(g))) - return g - if self.valuation() not in [-1, 0]: - raise ValueError("compositional inverse does not exist") coeff_stream = self._coeff_stream - if isinstance(coeff_stream, Stream_exact): - if (coeff_stream.order() == 0 - and coeff_stream._degree == 2): - a = coeff_stream[0] - b = coeff_stream[1] - coeff_stream = Stream_exact((-a/b, 1/b), - coeff_stream._is_sparse, - order=0) - return P.element_class(P, coeff_stream) - if (coeff_stream.order() == -1 - and coeff_stream._degree == 0): - return self + if isinstance(coeff_stream, Stream_zero): raise ValueError("compositional inverse does not exist") - raise ValueError("cannot determine whether the compositional inverse exists") + if isinstance(coeff_stream, Stream_exact): + if coeff_stream._constant: + if coeff_stream.order() == 1: + R = P.base_ring() + # we cannot assume that the last initial coefficient + # and the constant differ, see stream.Stream_exact + if (coeff_stream._degree == 1 + len(coeff_stream._initial_coefficients) + and coeff_stream._constant == -R.one() + and all(c == -R.one() for c in coeff_stream._initial_coefficients)): + # self = -z/(1-z); self.revert() = -z/(1-z) + return self + else: + raise ValueError("compositional inverse does not exist") + else: + if (coeff_stream.order() == -1 + and coeff_stream._degree == 0): + # self = a/z; self.revert() = a/z + return self + + if (coeff_stream.order() >= 0 + and coeff_stream._degree == 2): + # self = a + b*z; self.revert() = -a/b + 1/b * z + a = coeff_stream[0] + b = coeff_stream[1] + coeff_stream = Stream_exact((-a/b, 1/b), + coeff_stream._is_sparse, + order=0) + return P.element_class(P, coeff_stream) + + if coeff_stream.order() != 1: + raise ValueError("compositional inverse does not exist") + + g = P.undefined(valuation=1) + # the following is mathematically equivalent to + # z / ((self / z)(g)) + # but more efficient and more lazy + g.define((~self.shift(-1)(g)).shift(1)) + return g + + compositional_inverse = revert + + def derivative(self, *args): + """ + Return the derivative of the Laurent series. + + Multiple variables and iteration counts may be supplied; see + the documentation of + :func:`sage.calculus.functional.derivative` function for + details. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: z.derivative() + 1 + sage: (1+z+z^2).derivative(3) + 0 + sage: (1/z).derivative() + -z^-2 + sage: (1/(1-z)).derivative(z) + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + + TESTS: + + Check the derivative of the logarithm: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: -log(1-z).derivative() + 1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + O(z^7) + + Check that differentiation of 'exact' series with nonzero + constant works:: + + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: f = L([1,2], valuation=-2, constant=1) + sage: f + z^-2 + 2*z^-1 + 1 + z + z^2 + O(z^3) + sage: f.derivative() + -2*z^-3 - 2*z^-2 + 1 + 2*z + 3*z^2 + 4*z^3 + O(z^4) + + Check that differentiation with respect to a variable other + than the series variable works:: + + sage: R. = QQ[] + sage: L. = LazyLaurentSeriesRing(R) + sage: (z*q).derivative() + q + + sage: (z*q).derivative(q) + z + + sage: (z*q).derivative(q, z) + 1 + + sage: f = 1/(1-q*z+z^2) + sage: f + 1 + q*z + (q^2 - 1)*z^2 + (q^3 - 2*q)*z^3 + (q^4 - 3*q^2 + 1)*z^4 + (q^5 - 4*q^3 + 3*q)*z^5 + (q^6 - 5*q^4 + 6*q^2 - 1)*z^6 + O(z^7) + sage: f.derivative(q)[3] + 3*q^2 - 2 + + """ + P = self.parent() + R = P._laurent_poly_ring + v = R.gen() + order = 0 + vars = [] + for x in derivative_parse(args): + if x is None or x == v: + order += 1 + else: + vars.append(x) + + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_zero): + return self + if (isinstance(coeff_stream, Stream_exact) + and not coeff_stream._constant): + if coeff_stream._approximate_order >= 0 and coeff_stream._degree <= order: + return P.zero() + if vars: + coeffs = [prod(i-k for k in range(order)) * c.derivative(vars) + for i, c in enumerate(coeff_stream._initial_coefficients, + coeff_stream._approximate_order)] + else: + coeffs = [prod(i-k for k in range(order)) * c + for i, c in enumerate(coeff_stream._initial_coefficients, + coeff_stream._approximate_order)] + coeff_stream = Stream_exact(coeffs, + self._coeff_stream._is_sparse, + order=coeff_stream._approximate_order - order, + constant=coeff_stream._constant) + return P.element_class(P, coeff_stream) + + coeff_stream = Stream_derivative(self._coeff_stream, order) + if vars: + coeff_stream = Stream_map_coefficients(coeff_stream, + lambda c: c.derivative(vars)) + return P.element_class(P, coeff_stream) def approximate_series(self, prec, name=None): r""" @@ -3164,10 +3983,10 @@ def polynomial(self, degree=None, name=None): A Laurent polynomial if the valuation of the series is negative or a polynomial otherwise. - If ``degree`` is not ``None``, the terms of the series of degree - greater than ``degree`` are truncated first. If ``degree`` is ``None`` - and the series is not a polynomial or a Laurent polynomial, a - ``ValueError`` is raised. + If ``degree`` is not ``None``, the terms of the series of + degree greater than ``degree`` are first truncated. If + ``degree`` is ``None`` and the series is not a polynomial or + a Laurent polynomial, a ``ValueError`` is raised. EXAMPLES:: @@ -3208,6 +4027,7 @@ def polynomial(self, degree=None, name=None): sage: L.zero().polynomial() 0 + """ S = self.parent() @@ -3273,13 +4093,13 @@ def _format_series(self, formatter, format_strings=False): return strformat("O({})".format(formatter(z**m))) return formatter(poly) + strformat(" + O({})".format(formatter(z**m))) -class LazyTaylorSeries(LazyCauchyProductSeries): +class LazyPowerSeries(LazyCauchyProductSeries): r""" A Taylor series where the coefficients are computed lazily. EXAMPLES:: - sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L. = LazyPowerSeriesRing(ZZ) sage: f = 1 / (1 - x^2 + y^3); f 1 + x^2 + (-y^3) + x^4 + (-2*x^2*y^3) + (x^6+y^6) + O(x,y)^7 sage: P. = PowerSeriesRing(ZZ, default_prec=101) @@ -3294,6 +4114,96 @@ class LazyTaylorSeries(LazyCauchyProductSeries): sage: g == f True """ + def is_unit(self): + """ + Return whether this element is a unit in the ring. + + EXAMPLES:: + + sage: L. = LazyPowerSeriesRing(ZZ) + sage: (2*z).is_unit() + False + + sage: (1 + 2*z).is_unit() + True + + sage: (3 + 2*z).is_unit() + False + + sage: L. = LazyPowerSeriesRing(ZZ) + sage: (-1 + 2*x + 3*x*y).is_unit() + True + """ + if self.is_zero(): # now 0 != 1 + return False + return self[0].is_unit() + + def exponential(self): + r""" + Return the exponential series of ``self``. + + This method is deprecated, use :meth:`exp` instead. + + TESTS:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: lazy_exp = x.exponential(); lazy_exp + doctest:...: DeprecationWarning: the method exponential is deprecated. Use exp instead. + See https://trac.sagemath.org/32367 for details. + 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + 1/720*x^6 + O(x^7) + """ + from sage.misc.superseded import deprecation + deprecation(32367, 'the method exponential is deprecated. Use exp instead.') + return self.exp() + + def compute_coefficients(self, i): + r""" + Computes all the coefficients of self up to i. + + This method is deprecated, it has no effect anymore. + + TESTS:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: a = L([1,2,3], constant=3) + sage: a.compute_coefficients(5) + doctest:...: DeprecationWarning: the method compute_coefficients obsolete and has no effect. + See https://trac.sagemath.org/32367 for details. + sage: a + 1 + 2*z + 3*z^2 + 3*z^3 + 3*z^4 + O(z^5) + """ + from sage.misc.superseded import deprecation + deprecation(32367, "the method compute_coefficients obsolete and has no effect.") + return + + def _im_gens_(self, codomain, im_gens, base_map=None): + """ + Return the image of ``self`` under the map that sends the + generators of the parent of ``self`` to the elements of the + tuple ``im_gens``. + + EXAMPLES:: + + sage: Z. = QQ[] + sage: R. = LazyPowerSeriesRing(Z) + sage: f = 1/(1-q-t) + sage: f + 1 + (q+t) + (q^2+2*q*t+t^2) + (q^3+3*q^2*t+3*q*t^2+t^3) + (q^4+4*q^3*t+6*q^2*t^2+4*q*t^3+t^4) + (q^5+5*q^4*t+10*q^3*t^2+10*q^2*t^3+5*q*t^4+t^5) + (q^6+6*q^5*t+15*q^4*t^2+20*q^3*t^3+15*q^2*t^4+6*q*t^5+t^6) + O(q,t)^7 + sage: S. = LazyPowerSeriesRing(Z) + sage: f._im_gens_(S, [s, x*s]) + 1 + ((x+1)*s) + ((x^2+2*x+1)*s^2) + ((x^3+3*x^2+3*x+1)*s^3) + ((x^4+4*x^3+6*x^2+4*x+1)*s^4) + ((x^5+5*x^4+10*x^3+10*x^2+5*x+1)*s^5) + ((x^6+6*x^5+15*x^4+20*x^3+15*x^2+6*x+1)*s^6) + O(s^7) + + sage: cc = Z.hom([-x]) + sage: f = 1/(1+x*q-t) + sage: f._im_gens_(S, [s, x*s], base_map=cc) + 1 + 2*x*s + 4*x^2*s^2 + 8*x^3*s^3 + 16*x^4*s^4 + 32*x^5*s^5 + 64*x^6*s^6 + O(s^7) + + """ + if base_map is None: + return codomain(self(*im_gens)) + + return codomain(self.map_coefficients(base_map)(*im_gens)) + def __call__(self, *g, check=True): r""" Return the composition of ``self`` with ``g``. @@ -3301,12 +4211,21 @@ def __call__(self, *g, check=True): The arity of ``self`` must be equal to the number of arguments provided. - Given two Taylor Series `f` and `g` over the same base ring, the - composition `(f \circ g)(z) = f(g(z))` is defined if and only if: + Given a Taylor series `f` of arity `n` and a tuple of Taylor + series `g = (g_1,\dots, g_n)` over the same base ring, the + composition `f \circ g` is defined if and only if for each + `1\leq k\leq n`: - - `g = 0` and `val(f) >= 0`, - - `g` is non-zero and `f` has only finitely many non-zero coefficients, - - `g` is non-zero and `val(g) > 0`. + - `g_i` is zero, or + - setting all variables except the `i`th in `f` to zero + yields a polynomial, or + - `val(g_i) > 0`. + + If `f` is a univariate 'exact' series, we can check whether + `f` is a actually a polynomial. However, if `f` is a + multivariate series, we have no way to test whether setting + all but one variable of `f` to zero yields a polynomial, + except if `f` itself is 'exact' and therefore a polynomial. INPUT: @@ -3314,8 +4233,8 @@ def __call__(self, *g, check=True): EXAMPLES:: - sage: L. = LazyTaylorSeriesRing(QQ) - sage: M. = LazyTaylorSeriesRing(ZZ) + sage: L. = LazyPowerSeriesRing(QQ) + sage: M. = LazyPowerSeriesRing(ZZ) sage: g1 = 1 / (1 - x) sage: g2 = x + y^2 sage: p = a^2 + b + 1 @@ -3325,7 +4244,7 @@ def __call__(self, *g, check=True): The number of mappings from a set with `m` elements to a set with `n` elements:: - sage: M. = LazyTaylorSeriesRing(QQ) + sage: M. = LazyPowerSeriesRing(QQ) sage: Ea = M(lambda n: 1/factorial(n)) sage: Ex = L(lambda n: 1/factorial(n)*x^n) sage: Ea(Ex*y)[5] @@ -3369,7 +4288,7 @@ def __call__(self, *g, check=True): of `f` and the parent of `g` or extended to the corresponding lazy series:: - sage: T. = LazyTaylorSeriesRing(QQ) + sage: T. = LazyPowerSeriesRing(QQ) sage: R. = ZZ[] sage: S. = R[] sage: L. = LaurentPolynomialRing(ZZ) @@ -3398,7 +4317,7 @@ def __call__(self, *g, check=True): TESTS:: - sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L. = LazyPowerSeriesRing(ZZ) sage: f = 1 / (1 - x - y) sage: f(f) Traceback (most recent call last): @@ -3418,8 +4337,50 @@ def __call__(self, *g, check=True): ... TypeError: no common canonical parent for objects with parents: ... + Consistency check when `g` is an uninitialized series between a + polynomial `f` as both a polynomial and a lazy series:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: f = 1 - z + sage: g = L.undefined(valuation=1) + sage: f(g) == f.polynomial()(g) + True + + sage: g = L.undefined(valuation=1) + sage: g.define(z / (1 - g)) + sage: g + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) + sage: gp = L.undefined(valuation=1) + sage: gp.define(z / f(gp)) + sage: gp + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) + + Check that composing the zero series with anything yields zero:: + + sage: T. = LazyPowerSeriesRing(QQ) + sage: M. = LazyPowerSeriesRing(QQ) + sage: T(0)(1/(1-a), a+b) + 0 + + Check that composing `f` with zero series yields the constant term of `f`:: + + sage: T(3/(1-x-2*y))(0, 0) + 3 + + Check that we can compose a polynomial with anything:: + + sage: T(1-x-2*y + x*y^2)(1, 3) + 3 + + sage: T(1-x-2*y + x*y^2)(1 + a, 3) + 3 + 8*a + + sage: T(1-x-2*y + x*y^2)(1/(1-a), 3) + 3 + 8*a + 8*a^2 + 8*a^3 + 8*a^4 + 8*a^5 + 8*a^6 + O(a,b)^7 + """ - if len(g) != len(self.parent().variable_names()): + fP = parent(self) + if len(g) != fP._arity: raise ValueError("arity of must be equal to the number of arguments provided") # Find a good parent for the result @@ -3427,8 +4388,20 @@ def __call__(self, *g, check=True): cm = get_coercion_model() P = cm.common_parent(self.base_ring(), *[parent(h) for h in g]) - # f has finite length - if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: + # f = 0 + if isinstance(self._coeff_stream, Stream_zero): + return P.zero() + + # g = (0, ..., 0) + if all((not isinstance(h, LazyModuleElement) and not h) + or (isinstance(h, LazyModuleElement) + and isinstance(h._coeff_stream, Stream_zero)) + for h in g): + return P(self[0]) + + # f has finite length and f != 0 + if (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): # constant polynomial poly = self.polynomial() if poly.is_constant(): @@ -3443,18 +4416,17 @@ def __call__(self, *g, check=True): from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing_univariate from sage.rings.lazy_series_ring import LazySeriesRing if not isinstance(P, LazySeriesRing): - fP = parent(self) if fP._laurent_poly_ring.has_coerce_map_from(P): S = fP._laurent_poly_ring P = fP if isinstance(P, (PolynomialRing_general, MPolynomialRing_base)): - from sage.rings.lazy_series_ring import LazyTaylorSeriesRing + from sage.rings.lazy_series_ring import LazyPowerSeriesRing S = P try: sparse = S.is_sparse() except AttributeError: sparse = fP.is_sparse() - P = LazyTaylorSeriesRing(S.base_ring(), S.variable_names(), sparse) + P = LazyPowerSeriesRing(S.base_ring(), S.variable_names(), sparse) elif isinstance(P, LaurentPolynomialRing_univariate): from sage.rings.lazy_series_ring import LazyLaurentSeriesRing S = P @@ -3479,8 +4451,7 @@ def __call__(self, *g, check=True): raise ValueError("can only compose with a positive valuation series") h._coeff_stream._approximate_order = 2 - - # We now ahave that every element of g has a _coeff_stream + # We now have that every element of g has a _coeff_stream sorder = self._coeff_stream._approximate_order if len(g) == 1: g0 = g[0] @@ -3488,7 +4459,8 @@ def __call__(self, *g, check=True): # we assume that the valuation of self[i](g) is at least i def coefficient(n): return sum(self[i] * (g0**i)[n] for i in range(n+1)) - coeff_stream = Stream_function(coefficient, R, P._sparse, 1) + + coeff_stream = Stream_function(coefficient, P._sparse, 1) return P.element_class(P, coeff_stream) coeff_stream = Stream_cauchy_compose(self._coeff_stream, g0._coeff_stream) @@ -3499,340 +4471,1419 @@ def coefficient(n): def coefficient(n): r = R.zero() - for i in range(n//gv+1): + for i in range(n // gv + 1): # Make sure the element returned from the composition is in P r += P(self[i](g))[n] return r - coeff_stream = Stream_function(coefficient, R, P._sparse, sorder * gv) + coeff_stream = Stream_function(coefficient, P._sparse, sorder * gv) return P.element_class(P, coeff_stream) compose = __call__ - def _format_series(self, formatter, format_strings=False): - """ - Return nonzero ``self`` formatted by ``formatter``. + def revert(self): + r""" + Return the compositional inverse of ``self``. - TESTS:: + Given a Taylor series `f`, the compositional inverse is a + Laurent series `g` over the same base ring, such that + `(f \circ g)(z) = f(g(z)) = z`. - sage: L. = LazyTaylorSeriesRing(QQ) - sage: f = 1 / (2 - x^2 + y) - sage: f._format_series(repr) - '1/2 + (-1/4*y) + (1/4*x^2+1/8*y^2) + (-1/4*x^2*y-1/16*y^3) + (1/8*x^4+3/16*x^2*y^2+1/32*y^4) + (-3/16*x^4*y-1/8*x^2*y^3-1/64*y^5) + (1/16*x^6+3/16*x^4*y^2+5/64*x^2*y^4+1/128*y^6) + O(x,y)^7' + The compositional inverse exists if and only if: - sage: f = (2 - x^2 + y) - sage: f._format_series(repr) - '2 + y + (-x^2)' - """ - P = self.parent() - cs = self._coeff_stream - v = cs._approximate_order - if isinstance(cs, Stream_exact): - if not cs._constant: - m = cs._degree - else: - m = cs._degree + P.options.constant_length - else: - m = v + P.options.display_length + - `val(f) = 1`, or - atomic_repr = P._internal_poly_ring.base_ring()._repr_option('element_is_atomic') - mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] - if not isinstance(cs, Stream_exact) or cs._constant: - if P._internal_poly_ring.base_ring() is P.base_ring(): - bigO = ["O(%s)" % P._monomial(1, m)] - else: - bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] - else: - bigO = [] + - `f = a + b z` with `a, b \neq 0` - from sage.misc.latex import latex - from sage.typeset.unicode_art import unicode_art - from sage.typeset.ascii_art import ascii_art - from sage.misc.repr import repr_lincomb - from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis - from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis - if formatter == repr: - poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) - elif formatter == latex: - poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) - elif formatter == ascii_art: - if atomic_repr: - poly = ascii_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = ascii_art(m) - h = a.height() - return ascii_art(ascii_left_parenthesis.character_art(h), - a, ascii_right_parenthesis.character_art(h)) - poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - elif formatter == unicode_art: - if atomic_repr: - poly = unicode_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = unicode_art(m) - h = a.height() - return unicode_art(unicode_left_parenthesis.character_art(h), - a, unicode_right_parenthesis.character_art(h)) - poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + EXAMPLES:: - return poly + sage: L. = LazyPowerSeriesRing(QQ) + sage: (2*z).revert() + 1/2*z + sage: (z-z^2).revert() + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) - def polynomial(self, degree=None, names=None): - r""" - Return ``self`` as a polynomial if ``self`` is actually so. + sage: s = L(degree=1, constant=-1) + sage: s.revert() + -z - z^2 - z^3 + O(z^4) - INPUT: + sage: s = L(degree=1, constant=1) + sage: s.revert() + z - z^2 + z^3 - z^4 + z^5 - z^6 + z^7 + O(z^8) - - ``degree`` -- ``None`` or an integer + TESTS:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: s = L(lambda n: 2 if n == 1 else 0, valuation=1); s + 2*z + O(z^8) + sage: s.revert() + 1/2*z + O(z^8) + + sage: (2+3*z).revert() + -2/3 + 1/3*z + + sage: s = L(lambda n: 2 if n == 0 else 3 if n == 1 else 0, valuation=0); s + 2 + 3*z + O(z^7) + sage: s.revert() + Traceback (most recent call last): + ... + ValueError: cannot determine whether the compositional inverse exists + + sage: R. = QQ[] + sage: L. = LazyPowerSeriesRing(R.fraction_field()) + sage: s = L([q], valuation=0, constant=t); s + q + t*z + t*z^2 + t*z^3 + O(z^4) + sage: s.revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + We look at some cases where the compositional inverse does not exist: + + `f = 0`:: + + sage: L(0).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + sage: (z - z).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + `val(f) != 1` and `f(0) * f(1) = 0`:: + + sage: (z^2).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + sage: L(1).revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + Reversion of exact series:: + + sage: f = L([1, 2], valuation=0, constant=1) + sage: f.revert() + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + sage: f = L([-1, -1], valuation=1, constant=-1) + sage: f.revert() + (-z) + (-z^2) + (-z^3) + O(z^4) + + sage: f = L([-1, 0, -1], valuation=1, constant=-1) + sage: f.revert() + (-z) + z^3 + (-z^4) + (-2*z^5) + 6*z^6 + z^7 + O(z^8) + + sage: f = L([-1], valuation=1, degree=3, constant=-1) + sage: f.revert() + (-z) + z^3 + (-z^4) + (-2*z^5) + 6*z^6 + z^7 + O(z^8) + """ + P = self.parent() + if P._arity != 1: + raise ValueError("arity must be equal to 1") + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_zero): + raise ValueError("compositional inverse does not exist") + if isinstance(coeff_stream, Stream_exact): + if coeff_stream._constant: + if coeff_stream.order() == 1: + R = P.base_ring() + # we cannot assume that the last initial coefficient + # and the constant differ, see stream.Stream_exact + if (coeff_stream._degree == 1 + len(coeff_stream._initial_coefficients) + and coeff_stream._constant == -R.one() + and all(c == -R.one() for c in coeff_stream._initial_coefficients)): + # self = -z/(1-z); self.revert() = -z/(1-z) + return self + else: + raise ValueError("compositional inverse does not exist") + else: + if coeff_stream._degree == 2: + # self = a + b*z; self.revert() = -a/b + 1/b * z + a = coeff_stream[0] + b = coeff_stream[1] + coeff_stream = Stream_exact((-a/b, 1/b), + coeff_stream._is_sparse, + order=0) + return P.element_class(P, coeff_stream) + + if coeff_stream.order() != 1: + raise ValueError("compositional inverse does not exist") + + # TODO: coefficients should not be checked here, it prevents + # us from using self.define in some cases! + if coeff_stream[0]: + raise ValueError("cannot determine whether the compositional inverse exists") + + g = P.undefined(valuation=1) + # the following is mathematically equivalent to + # z / ((self / z)(g)) + # but more efficient and more lazy + g.define((~self.shift(-1)(g)).shift(1)) + return g + + compositional_inverse = revert + + def derivative(self, *args): + """ + Return the derivative of the Taylor series. + + Multiple variables and iteration counts may be supplied; see + the documentation of + :func:`sage.calculus.functional.derivative` function for + details. + + EXAMPLES:: + + sage: T. = LazyPowerSeriesRing(ZZ) + sage: z.derivative() + 1 + sage: (1+z+z^2).derivative(3) + 0 + sage: (1/(1-z)).derivative() + 1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7) + + sage: R. = QQ[] + sage: L. = LazyPowerSeriesRing(R) + sage: f = 1/(1-q*x+y); f + 1 + (q*x-y) + (q^2*x^2+(-2*q)*x*y+y^2) + + (q^3*x^3+(-3*q^2)*x^2*y+3*q*x*y^2-y^3) + + (q^4*x^4+(-4*q^3)*x^3*y+6*q^2*x^2*y^2+(-4*q)*x*y^3+y^4) + + (q^5*x^5+(-5*q^4)*x^4*y+10*q^3*x^3*y^2+(-10*q^2)*x^2*y^3+5*q*x*y^4-y^5) + + (q^6*x^6+(-6*q^5)*x^5*y+15*q^4*x^4*y^2+(-20*q^3)*x^3*y^3+15*q^2*x^2*y^4+(-6*q)*x*y^5+y^6) + + O(x,y)^7 + sage: f.derivative(q) + x + (2*q*x^2+(-2)*x*y) + (3*q^2*x^3+(-6*q)*x^2*y+3*x*y^2) + + (4*q^3*x^4+(-12*q^2)*x^3*y+12*q*x^2*y^2+(-4)*x*y^3) + + (5*q^4*x^5+(-20*q^3)*x^4*y+30*q^2*x^3*y^2+(-20*q)*x^2*y^3+5*x*y^4) + + (6*q^5*x^6+(-30*q^4)*x^5*y+60*q^3*x^4*y^2+(-60*q^2)*x^3*y^3+30*q*x^2*y^4+(-6)*x*y^5) + + O(x,y)^7 + + """ + P = self.parent() + R = P._laurent_poly_ring + V = R.gens() + order = 0 + vars = [] + gen_vars = [] + for x in derivative_parse(args): + if x is None: + order += 1 + elif x in V: + gen_vars.append(x) + else: + vars.append(x) + + if P._arity > 1 and order: + raise ValueError("for multivariate series you have to specify the variable with respect to which the derivative should be taken") + else: + order += len(gen_vars) + + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_zero): + return self + + if P._arity > 1: + v = gen_vars + vars + d = -len(gen_vars) + coeff_stream = Stream_map_coefficients(coeff_stream, + lambda c: R(c).derivative(v)) + coeff_stream = Stream_shift(coeff_stream, d) + return P.element_class(P, coeff_stream) + + if (isinstance(coeff_stream, Stream_exact) + and not coeff_stream._constant): + if coeff_stream._degree <= order: + return P.zero() + if vars: + coeffs = [prod(i-k for k in range(order)) * c.derivative(vars) + for i, c in enumerate(coeff_stream._initial_coefficients, + coeff_stream._approximate_order)] + else: + coeffs = [prod(i-k for k in range(order)) * c + for i, c in enumerate(coeff_stream._initial_coefficients, + coeff_stream._approximate_order)] + coeff_stream = Stream_exact(coeffs, + self._coeff_stream._is_sparse, + order=coeff_stream._approximate_order - order, + constant=coeff_stream._constant) + return P.element_class(P, coeff_stream) + + coeff_stream = Stream_derivative(self._coeff_stream, order) + if vars: + coeff_stream = Stream_map_coefficients(coeff_stream, + lambda c: c.derivative(vars)) + return P.element_class(P, coeff_stream) + + def _format_series(self, formatter, format_strings=False): + """ + Return nonzero ``self`` formatted by ``formatter``. + + TESTS:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: f = 1 / (2 - x^2 + y) + sage: f._format_series(repr) + '1/2 + (-1/4*y) + (1/4*x^2+1/8*y^2) + (-1/4*x^2*y-1/16*y^3) + + (1/8*x^4+3/16*x^2*y^2+1/32*y^4) + (-3/16*x^4*y-1/8*x^2*y^3-1/64*y^5) + + (1/16*x^6+3/16*x^4*y^2+5/64*x^2*y^4+1/128*y^6) + O(x,y)^7' + + sage: f = (2 - x^2 + y) + sage: f._format_series(repr) + '2 + y + (-x^2)' + """ + P = self.parent() + cs = self._coeff_stream + v = cs._approximate_order + if isinstance(cs, Stream_exact): + if not cs._constant: + m = cs._degree + else: + m = cs._degree + P.options.constant_length + else: + m = v + P.options.display_length + + atomic_repr = P._internal_poly_ring.base_ring()._repr_option('element_is_atomic') + mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] + if not isinstance(cs, Stream_exact) or cs._constant: + if P._internal_poly_ring.base_ring() is P.base_ring(): + bigO = ["O(%s)" % P._monomial(1, m)] + else: + bigO = ["O(%s)^%s" % (', '.join(str(g) for g in P._names), m)] + else: + bigO = [] + + from sage.misc.latex import latex + from sage.typeset.unicode_art import unicode_art + from sage.typeset.ascii_art import ascii_art + from sage.misc.repr import repr_lincomb + from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis + from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis + if formatter == repr: + poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) + elif formatter == latex: + poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) + elif formatter == ascii_art: + if atomic_repr: + poly = ascii_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = ascii_art(m) + h = a.height() + return ascii_art(ascii_left_parenthesis.character_art(h), + a, ascii_right_parenthesis.character_art(h)) + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + elif formatter == unicode_art: + if atomic_repr: + poly = unicode_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = unicode_art(m) + h = a.height() + return unicode_art(unicode_left_parenthesis.character_art(h), + a, unicode_right_parenthesis.character_art(h)) + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + + return poly + + def polynomial(self, degree=None, names=None): + r""" + Return ``self`` as a polynomial if ``self`` is actually so. + + INPUT: + + - ``degree`` -- ``None`` or an integer - ``names`` -- names of the variables; if it is ``None``, the name of the variables of the series is used - OUTPUT: + OUTPUT: + + If ``degree`` is not ``None``, the terms of the series of + degree greater than ``degree`` are first truncated. If + ``degree`` is ``None`` and the series is not a polynomial + polynomial, a ``ValueError`` is raised. + + EXAMPLES:: + + sage: L. = LazyPowerSeriesRing(ZZ) + sage: f = x^2 + y*x - x + 2; f + 2 + (-x) + (x^2+x*y) + sage: f.polynomial() + x^2 + x*y - x + 2 + + TESTS:: + + sage: g = 1 / (1 + x + y + x*y) + sage: g3 = g.truncate(4); g3 + 1 + (-x-y) + (x^2+x*y+y^2) + (-x^3-x^2*y-x*y^2-y^3) + sage: g.polynomial() + Traceback (most recent call last): + ... + ValueError: not a polynomial + sage: g3.polynomial() + -x^3 - x^2*y - x*y^2 - y^3 + x^2 + x*y + y^2 - x - y + 1 + sage: L.zero().polynomial() + 0 + sage: g3.polynomial() == g.polynomial(3) + True + sage: g3.polynomial(0) + 1 + + sage: L. = LazyPowerSeriesRing(ZZ) + sage: f = z-z^2 + sage: f.polynomial() + -z^2 + z + """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + S = self.parent() + if names is None: + names = S.variable_names() + R = PolynomialRing(S.base_ring(), names=names) + if isinstance(self._coeff_stream, Stream_zero): + return R.zero() + + if degree is None: + if (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): + m = self._coeff_stream._degree + else: + raise ValueError("not a polynomial") + else: + m = degree + 1 + + if S._arity == 1: + return R(self[0:m]) + return R.sum(self[0:m]) + + def _floordiv_(self, other): + r""" + Return ``self`` floor divided by ``other``. + + INPUT: + + - ``other`` -- nonzero series + + EXAMPLES:: + + sage: L. = LazyPowerSeriesRing(ZZ) + sage: g = x^2 + y*x + sage: x // g + 0 + sage: g = (x^2 + y*x) / (1 - x + x*y) + sage: x // g + 0 + sage: f = (x + y) / (1 - x - y + x*y) + sage: f // g + 0 + + sage: L. = LazyPowerSeriesRing(QQ) + sage: g = (x + 2*x^2) / (1 - x - x^2) + sage: 3 // g + 0 + sage: x // g + 1 - 3*x + 5*x^2 - 10*x^3 + 20*x^4 - 40*x^5 + 80*x^6 + O(x^7) + sage: x^2 // g + x - 3*x^2 + 5*x^3 - 10*x^4 + 20*x^5 - 40*x^6 + 80*x^7 + O(x^8) + sage: f = (x + x^2) / (1 - x) + sage: f // g + 1 - x + x^2 - 4*x^3 + 6*x^4 - 14*x^5 + 26*x^6 + O(x^7) + """ + if isinstance(other._coeff_stream, Stream_zero): + raise ZeroDivisionError("cannot divide by 0") + P = self.parent() + if P not in IntegralDomains(): + raise TypeError("must be an integral domain") + left = self._coeff_stream + right_order = other._coeff_stream._approximate_order + if left._approximate_order < right_order: + if left._true_order: + return P.zero() + while left._approximate_order < right_order: + # TODO: Implement a bound on computing the order of a Stream + if left[left._approximate_order]: + left._true_order = True + return P.zero() + left._approximate_order += 1 + return super()._floordiv_(other) + +class LazyPowerSeries_gcd_mixin: + """ + A lazy power series that also implements the GCD algorithm. + """ + def gcd(self, other): + r""" + Return the greatest common divisor of ``self`` and ``other``. + + EXAMPLES:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: a = 16*x^5 / (1 - 5*x) + sage: b = (22*x^2 + x^8) / (1 - 4*x^2) + sage: a.gcd(b) + x^2 + """ + P = self.parent() + if P._arity != 1: + raise NotImplementedError("only implemented for arity one") + if not self or not other: + return P.zero() + sv = self.valuation() + ov = other.valuation() + val = min(sv, ov) + assert val is not infinity + # This assumes the base ring is a field + return P.gen(0) ** val + + def xgcd(self, f): + r""" + Return the extended gcd of ``self`` and ``f``. + + OUTPUT: + + A triple ``(g, s, t)`` such that ``g`` is the gcd of ``self`` + and ``f``, and ``s`` and ``t`` are cofactors satisfying the + Bezout identity + + .. MATH:: + + g = s \cdot \mathrm{self} + t \cdot f. + + EXAMPLES:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: a = 16*x^5 / (1 - 2*x) + sage: b = (22*x^3 + x^8) / (1 - 3*x^2) + sage: g, s, t = a.xgcd(b) + sage: g + x^3 + sage: s + 1/22 - 41/242*x^2 - 8/121*x^3 + 120/1331*x^4 + 1205/5324*x^5 + 316/14641*x^6 + O(x^7) + sage: t + 1/22 - 41/242*x^2 - 8/121*x^3 + 120/1331*x^4 + 1205/5324*x^5 + 316/14641*x^6 + O(x^7) + + sage: LazyPowerSeriesRing.options.halting_precision(20) # verify up to degree 20 + + sage: g == s * a + t * b + True + + sage: a = 16*x^5 / (1 - 2*x) + sage: b = (-16*x^5 + x^8) / (1 - 3*x^2) + sage: g, s, t = a.xgcd(b) + sage: g + x^5 + sage: s + 1/16 - 1/16*x - 3/16*x^2 + 1/8*x^3 - 17/256*x^4 + 9/128*x^5 + 1/128*x^6 + O(x^7) + sage: t + 1/16*x - 1/16*x^2 - 3/16*x^3 + 1/8*x^4 - 17/256*x^5 + 9/128*x^6 + 1/128*x^7 + O(x^8) + sage: g == s * a + t * b + True + + sage: L. = LazyPowerSeriesRing(GF(2)) + sage: a = L(lambda n: n % 2, valuation=3); a + x^3 + x^5 + x^7 + x^9 + O(x^10) + sage: b = L(lambda n: binomial(n,2) % 2, valuation=3); b + x^3 + x^6 + x^7 + O(x^10) + sage: g, s, t = a.xgcd(b) + sage: g + x^3 + sage: s + 1 + x + x^3 + x^4 + x^5 + O(x^7) + sage: t + x + x^2 + x^4 + x^5 + x^6 + O(x^8) + sage: g == s * a + t * b + True + + sage: LazyPowerSeriesRing.options._reset() # reset the options + """ + P = self.parent() + if P._arity != 1: + raise NotImplementedError("only implemented for arity one") + # one of the elements is zero + if not self: + return (P.zero(), P.zero(), P.one()) + if not f: + return (P.zero(), P.one(), P.zero()) + # get the valuations + sv = self.valuation() + fv = f.valuation() + val = min(sv, fv) + assert val is not infinity + # This assumes the base ring is a field + x = P.gen(0) + unit = (self + f).shift(-val) + if not unit[0]: + # this only happens if they have the same valuation + # we multiply f by the generator to avoid any cancellations + unit = (self + f.shift(1)).shift(-val) + unit = ~unit + return (x**val, + unit, + unit * x) + unit = ~unit + return (x**val, unit, unit) + +class LazyCompletionGradedAlgebraElement(LazyCauchyProductSeries): + """ + An element of a completion of a graded algebra that is computed lazily. + """ + def _format_series(self, formatter, format_strings=False): + r""" + Return nonzero ``self`` formatted by ``formatter``. + + TESTS:: + + sage: h = SymmetricFunctions(ZZ).h() + sage: e = SymmetricFunctions(ZZ).e() + sage: L = LazySymmetricFunctions(tensor([h, e])) + sage: f = L(lambda n: sum(tensor([h[k], e[n-k]]) for k in range(n+1))) + sage: f._format_series(repr) + '(h[]#e[]) + + (h[]#e[1]+h[1]#e[]) + + (h[]#e[2]+h[1]#e[1]+h[2]#e[]) + + (h[]#e[3]+h[1]#e[2]+h[2]#e[1]+h[3]#e[]) + + (h[]#e[4]+h[1]#e[3]+h[2]#e[2]+h[3]#e[1]+h[4]#e[]) + + (h[]#e[5]+h[1]#e[4]+h[2]#e[3]+h[3]#e[2]+h[4]#e[1]+h[5]#e[]) + + (h[]#e[6]+h[1]#e[5]+h[2]#e[4]+h[3]#e[3]+h[4]#e[2]+h[5]#e[1]+h[6]#e[]) + + O^7' + """ + P = self.parent() + cs = self._coeff_stream + v = cs._approximate_order + if isinstance(cs, Stream_exact): + if not cs._constant: + m = cs._degree + else: + m = cs._degree + P.options.constant_length + else: + m = v + P.options.display_length + + atomic_repr = P._internal_poly_ring.base_ring()._repr_option('element_is_atomic') + mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] + if not isinstance(cs, Stream_exact) or cs._constant: + if P._internal_poly_ring.base_ring() is P.base_ring(): + bigO = ["O(%s)" % P._monomial(1, m)] + else: + bigO = ["O^%s" % m] + else: + bigO = [] + + from sage.misc.latex import latex + from sage.typeset.unicode_art import unicode_art + from sage.typeset.ascii_art import ascii_art + from sage.misc.repr import repr_lincomb + from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis + from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis + if formatter == repr: + poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) + elif formatter == latex: + poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) + elif formatter == ascii_art: + if atomic_repr: + poly = ascii_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = ascii_art(m) + h = a.height() + return ascii_art(ascii_left_parenthesis.character_art(h), + a, ascii_right_parenthesis.character_art(h)) + poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + elif formatter == unicode_art: + if atomic_repr: + poly = unicode_art(*(mons + bigO), sep = " + ") + else: + def parenthesize(m): + a = unicode_art(m) + h = a.height() + return unicode_art(unicode_left_parenthesis.character_art(h), + a, unicode_right_parenthesis.character_art(h)) + poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + + return poly + + +class LazySymmetricFunction(LazyCompletionGradedAlgebraElement): + r""" + A symmetric function where each degree is computed lazily. + + EXAMPLES:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: L = LazySymmetricFunctions(s) + """ + def is_unit(self): + """ + Return whether this element is a unit in the ring. + + EXAMPLES:: + + sage: m = SymmetricFunctions(ZZ).m() + sage: L = LazySymmetricFunctions(m) + + sage: L(2*m[1]).is_unit() + False + + sage: L(-1 + 2*m[1]).is_unit() + True + + sage: L(2 + m[1]).is_unit() + False + + sage: m = SymmetricFunctions(QQ).m() + sage: L = LazySymmetricFunctions(m) + + sage: L(2 + 3*m[1]).is_unit() + True + """ + if self.is_zero(): # now 0 != 1 + return False + return self[0].is_unit() + + def __call__(self, *args, check=True): + r""" + Return the composition of ``self`` with ``g``. + + The arity of ``self`` must be equal to the number of + arguments provided. + + Given a lazy symmetric function `f` of arity `n` and a tuple + of lazy symmetric functions `g = (g_1,\dots, g_n)` over the + same base ring, the composition (or plethysm) `(f \circ g)` + is defined if and only if for each `1\leq k\leq n`: + + - `g_i = 0`, or + - setting all alphabets except the `i`th in `f` to zero + yields a symmetric function with only finitely many + non-zero coefficients, or + - `val(g) > 0`. + + If `f` is a univariate 'exact' lazy symmetric function, we + can check whether `f` has only finitely many non-zero + coefficients. However, if `f` has larger arity, we have no + way to test whether setting all but one alphabets of `f` to + zero yields a polynomial, except if `f` itself is 'exact' and + therefore a symmetric function with only finitely many + non-zero coefficients. + + INPUT: + + - ``g`` -- other (lazy) symmetric functions + + .. TODO:: + + Allow specification of degree one elements. + + EXAMPLES:: + + sage: P. = QQ[] + sage: s = SymmetricFunctions(P).s() + sage: L = LazySymmetricFunctions(s) + sage: f = s[2] + sage: g = s[3] + sage: L(f)(L(g)) - L(f(g)) + 0 + + sage: f = s[2] + s[2,1] + sage: g = s[1] + s[2,2] + sage: L(f)(L(g)) - L(f(g)) + 0 + + sage: L(f)(g) - L(f(g)) + 0 + + sage: f = s[2] + s[2,1] + sage: g = s[1] + s[2,2] + sage: L(f)(L(q*g)) - L(f(q*g)) + 0 + + The Frobenius character of the permutation action on set + partitions is a plethysm:: + + sage: s = SymmetricFunctions(QQ).s() + sage: S = LazySymmetricFunctions(s) + sage: E1 = S(lambda n: s[n], valuation=1) + sage: E = 1 + E1 + sage: P = E(E1) + sage: P[:5] + [s[], s[1], 2*s[2], s[2, 1] + 3*s[3], 2*s[2, 2] + 2*s[3, 1] + 5*s[4]] + + The plethysm with a tensor product is also implemented:: + + sage: s = SymmetricFunctions(QQ).s() + sage: X = tensor([s[1],s[[]]]) + sage: Y = tensor([s[[]],s[1]]) + sage: S = LazySymmetricFunctions(s) + sage: S2 = LazySymmetricFunctions(tensor([s, s])) + sage: A = S(s[1,1,1]) + sage: B = S2(X+Y) + sage: A(B) + (s[]#s[1,1,1]+s[1]#s[1,1]+s[1,1]#s[1]+s[1,1,1]#s[]) + + sage: H = S(lambda n: s[n]) + sage: H(S2(X*Y)) + (s[]#s[]) + (s[1]#s[1]) + (s[1,1]#s[1,1]+s[2]#s[2]) + + (s[1,1,1]#s[1,1,1]+s[2,1]#s[2,1]+s[3]#s[3]) + O^7 + sage: H(S2(X+Y)) + (s[]#s[]) + (s[]#s[1]+s[1]#s[]) + (s[]#s[2]+s[1]#s[1]+s[2]#s[]) + + (s[]#s[3]+s[1]#s[2]+s[2]#s[1]+s[3]#s[]) + + (s[]#s[4]+s[1]#s[3]+s[2]#s[2]+s[3]#s[1]+s[4]#s[]) + + (s[]#s[5]+s[1]#s[4]+s[2]#s[3]+s[3]#s[2]+s[4]#s[1]+s[5]#s[]) + + (s[]#s[6]+s[1]#s[5]+s[2]#s[4]+s[3]#s[3]+s[4]#s[2]+s[5]#s[1]+s[6]#s[]) + + O^7 + + TESTS:: + + sage: s = SymmetricFunctions(QQ).s() + sage: S = LazySymmetricFunctions(s) + sage: f = 1 / (1 - S(s[2])) + sage: g = f(s[2]); g + s[] + (s[2,2]+s[4]) + O^7 + sage: S(sum(f[i](s[2]) for i in range(5))).truncate(10) == g.truncate(10) + True + sage: f = 1 / (1 - S(s[2])) + sage: g = S(s[1]) / (1 - S(s[1])) + sage: f(g) + s[] + s[2] + (s[1,1,1]+2*s[2,1]+s[3]) + + (2*s[1,1,1,1]+4*s[2,1,1]+5*s[2,2]+5*s[3,1]+3*s[4]) + + (2*s[1,1,1,1,1]+10*s[2,1,1,1]+14*s[2,2,1]+18*s[3,1,1]+16*s[3,2]+14*s[4,1]+4*s[5]) + + (3*s[1,1,1,1,1,1]+22*s[2,1,1,1,1]+38*s[2,2,1,1]+28*s[2,2,2]+48*s[3,1,1,1]+82*s[3,2,1]+25*s[3,3]+51*s[4,1,1]+56*s[4,2]+31*s[5,1]+9*s[6]) + + O^7 + sage: f(0) + 1 + sage: f(s(1)) + Traceback (most recent call last): + ... + ValueError: can only compose with a positive valuation series + + Check that composing the zero series with anything yields + zero in the correct parent:: + + sage: e = SymmetricFunctions(QQ).e() + sage: h = SymmetricFunctions(QQ).h() + sage: s = SymmetricFunctions(QQ).s() + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(tensor([e, h])) + sage: r = (L(0)(s[1], p[1])); r + 0 + sage: r.parent() + Symmetric Functions over Rational Field in the Schur basis + + Check that composing `f` with zero series yields the constant term of `f`:: + + sage: f = 3*L(tensor([s[1], s[1]])) + sage: f(0, 0) + 0 + sage: (3+f)(0, 0) + 3 + """ + fP = parent(self) + if len(args) != fP._arity: + raise ValueError("arity must be equal to the number of arguments provided") + + # Find a good parent for the result + from sage.structure.element import get_coercion_model + cm = get_coercion_model() + P = cm.common_parent(self.base_ring(), *[parent(h) for h in args]) + + # f = 0 + if isinstance(self._coeff_stream, Stream_zero): + return P.zero() + + # g = (0, ..., 0) + if all((not isinstance(h, LazyModuleElement) and not h) + or (isinstance(h, LazyModuleElement) + and isinstance(h._coeff_stream, Stream_zero)) + for h in args): + f = self[0] + # FIXME: TypeError: unable to convert 0 to a rational + if f: + return P(f.leading_coefficient()) + return P.zero() + + if len(args) == 1: + g = args[0] + if (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): + + if not isinstance(g, LazySymmetricFunction): + f = self.symmetric_function() + return f(g) + + if (isinstance(g._coeff_stream, Stream_exact) + and not g._coeff_stream._constant): + f = self.symmetric_function() + gs = g.symmetric_function() + return P(f(gs)) + + if isinstance(g, LazySymmetricFunction): + R = P._laurent_poly_ring + else: + from sage.rings.lazy_series_ring import LazySymmetricFunctions + R = g.parent() + P = LazySymmetricFunctions(R) + g = P(g) + + if check and not (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): + if g._coeff_stream._approximate_order == 0: + if g[0]: + raise ValueError("can only compose with a positive valuation series") + g._coeff_stream._approximate_order = 1 + + if P._arity == 1: + ps = R.realization_of().p() + else: + ps = tensor([R._sets[0].realization_of().p()]*P._arity) + coeff_stream = Stream_plethysm(self._coeff_stream, g._coeff_stream, + ps, R) + return P.element_class(P, coeff_stream) + + else: + raise NotImplementedError("only implemented for arity 1") + + plethysm = __call__ + + def revert(self): + r""" + Return the compositional inverse of ``self``. + + Given a symmetric function `f`, the compositional inverse is + a symmetric function `g` over the same base ring, such that + `f \circ g = p_1`. Thus, it is the inverse with respect to + plethystic substitution. + + The compositional inverse exists if and only if: + + - `val(f) = 1`, or + + - `f = a + b p_1` with `a, b \neq 0`. + + EXAMPLES:: + + sage: h = SymmetricFunctions(QQ).h() + sage: L = LazySymmetricFunctions(h) + sage: f = L(lambda n: h[n]) - 1 + sage: f(f.revert()) + h[1] + O^7 + + TESTS:: + + sage: f = L(lambda n: h[n]) - 1 - h[1] + sage: g = f.revert() + sage: g[1] + Traceback (most recent call last): + ... + ValueError: compositional inverse does not exist + + sage: R. = QQ[] + sage: p = SymmetricFunctions(R.fraction_field()).p() + sage: L = LazySymmetricFunctions(p) + sage: f = L(a + b*p[1]) + sage: f.revert() + (((-a)/b)*p[]) + 1/b*p[1] + + sage: f = L(2*p[1]) + sage: f.revert() + 1/2*p[1] + + sage: f = L(2*p[1] + p[1,1]) + sage: f.revert() + 1/2*p[1] + (-1/8*p[1,1]) + (1/16*p[1,1,1]) + (-5/128*p[1,1,1,1]) + + (7/256*p[1,1,1,1,1]) + (-21/1024*p[1,1,1,1,1,1]) + + (33/2048*p[1,1,1,1,1,1,1]) + O^8 + + sage: f.revert()(f) + p[1] + O^8 + + ALGORITHM: + + Let `F` be a symmetric function with valuation `1`, i.e., + whose constant term vanishes and whose degree one term equals + `b p_1`. Then + + .. MATH:: + + (F - b p_1) \circ G = F \circ G - b p_1 \circ G = p_1 - b G, + + and therefore `G = (p_1 - (F - b p_1) \circ G) / b`, which + allows recursive computation of `G`. + + .. SEEALSO:: + + The compositional inverse `\Omega` of the symmetric + function `h_1 + h_2 + \dots` can be handled much more + efficiently using specialized methods. See + :func:`~sage.combinat.species.generating_series.LogarithmCycleIndexSeries` + + AUTHORS: + + - Andrew Gainer-Dewar + - Martin Rubey + + """ + P = self.parent() + if P._arity != 1: + raise ValueError("arity must be equal to 1") + coeff_stream = self._coeff_stream + if isinstance(coeff_stream, Stream_zero): + raise ValueError("compositional inverse does not exist") + R = P._laurent_poly_ring + if (isinstance(coeff_stream, Stream_exact) + and coeff_stream.order() >= 0 + and coeff_stream._degree == 2): + # self = a + b * p_1; self.revert() = -a/b + 1/b * p_1 + a = coeff_stream[0] + b = coeff_stream[1][Partition([1])] + X = R(Partition([1])) + coeff_stream = Stream_exact((-a/b, 1/b * X), + coeff_stream._is_sparse, + order=0) + return P.element_class(P, coeff_stream) + + # TODO: coefficients should not be checked here, it prevents + # us from using self.define in some cases! + if coeff_stream[0]: + raise ValueError("cannot determine whether the compositional inverse exists") + + la = Partition([1]) + X = R(la) + + def coefficient(n): + if n: + return 0 + c = coeff_stream[1][la] + if c.is_unit(): + return ~c + raise ValueError("compositional inverse does not exist") + + b = P(lambda n: 0 if n else coeff_stream[1][la]) # TODO: we want a lazy version of Stream_exact + b_inv = P(coefficient) # TODO: we want a lazy version of Stream_exact + g = P.undefined(valuation=1) + g.define(b_inv * (X - (self - b * X)(g))) + return g + + plethystic_inverse = revert + + compositional_inverse = revert + + def derivative_with_respect_to_p1(self, n=1): + r""" + Return the symmetric function obtained by taking the + derivative of ``self`` with respect to the power-sum + symmetric function `p_1` when the expansion of ``self`` in + the power-sum basis is considered as a polynomial in `p_k`'s + (with `k \geq 1`). + + This is the same as skewing ``self`` by the first power-sum + symmetric function `p_1`. + + INPUT: + + - ``n`` -- (default: 1) nonnegative integer which determines + which power of the derivative is taken + + EXAMPLES: + + The species `E` of sets satisfies the relationship `E' = E`:: + + sage: h = SymmetricFunctions(QQ).h() + sage: T = LazySymmetricFunctions(h) + sage: E = T(lambda n: h[n]) + sage: E - E.derivative_with_respect_to_p1() + O^6 + + The species `C` of cyclic orderings and the species `L` of linear + orderings satisfy the relationship `C' = L`:: + + sage: p = SymmetricFunctions(QQ).p() + sage: C = T(lambda n: (sum(euler_phi(k)*p([k])**(n//k) for k in divisors(n))/n if n > 0 else 0)) + sage: L = T(lambda n: p([1]*n)) + sage: L - C.derivative_with_respect_to_p1() + O^6 + + TESTS:: + + sage: T = LazySymmetricFunctions(p) + sage: a = T(p([1,1,1])) + sage: a.derivative_with_respect_to_p1() + (3*p[1,1]) + O^9 + sage: a.derivative_with_respect_to_p1(1) + (3*p[1,1]) + O^9 + sage: a.derivative_with_respect_to_p1(2) + 6*p[1] + O^8 + sage: a.derivative_with_respect_to_p1(3) + 6*p[] + O^7 + """ + P = self.parent() + if P._arity != 1: + raise ValueError("arity must be equal to 1") + + coeff_stream = Stream_map_coefficients(self._coeff_stream, + lambda c: c.derivative_with_respect_to_p1(n)) + coeff_stream = Stream_shift(coeff_stream, -n) + return P.element_class(P, coeff_stream) + + def functorial_composition(self, *args): + r""" + Return the functorial composition of ``self`` and ``g``. + + Let `X` be a finite set of cardinality `m`. For a group + action of the symmetric group `g: S_n \to S_X` and a + (possibly virtual) representation of the symmetric group on + `X`, `f: S_X \to GL(V)`, the functorial composition is the + (virtual) representation of the symmetric group `f \Box g: + S_n \to GL(V)` given by `\sigma \mapsto f(g(\sigma))`. + + This is more naturally phrased in the language of + combinatorial species. Let `F` and `G` be species, then + their functorial composition is the species `F \Box G` with + `(F \Box G) [A] = F[ G[A] ]`. In other words, an `(F \Box + G)`-structure on a set `A` of labels is an `F`-structure + whose labels are the set of all `G`-structures on `A`. + + The Frobenius character (or cycle index series) of `F \Box G` + can be computed as follows, see section 2.2 of [BLL]_): + + .. MATH:: + + \sum_{n \geq 0} \frac{1}{n!} \sum_{\sigma \in + \mathfrak{S}_{n}} \operatorname{fix} F[ (G[\sigma])_{1}, + (G[\sigma])_{2}, \ldots ] \, p_{1}^{\sigma_{1}} + p_{2}^{\sigma_{2}} \cdots. + + .. WARNING:: + + The operation `f \Box g` only makes sense when `g` + corresponds to a permutation representation, i.e., a + group action. + + EXAMPLES: + + The species `G` of simple graphs can be expressed in terms of + a functorial composition: `G = \mathfrak{p} \Box + \mathfrak{p}_{2}`, where `\mathfrak{p}` is the + :class:`~sage.combinat.species.subset_species.SubsetSpecies`.:: + + sage: R. = QQ[] + sage: h = SymmetricFunctions(R).h() + sage: m = SymmetricFunctions(R).m() + sage: L = LazySymmetricFunctions(m) + sage: P = L(lambda n: sum(q^k*h[n-k]*h[k] for k in range(n+1))) + sage: P2 = L(lambda n: h[2]*h[n-2], valuation=2) + sage: P.functorial_composition(P2)[:4] + [m[], + m[1], + (q+1)*m[1, 1] + (q+1)*m[2], + (q^3+3*q^2+3*q+1)*m[1, 1, 1] + (q^3+2*q^2+2*q+1)*m[2, 1] + (q^3+q^2+q+1)*m[3]] + + For example, there are:: + + sage: P.functorial_composition(P2)[4].coefficient([4])[3] + 3 + + unlabelled graphs on 4 vertices and 3 edges, and:: + + sage: P.functorial_composition(P2)[4].coefficient([2,2])[3] + 8 + + labellings of their vertices with two 1's and two 2's. + + The symmetric function `h_1 \sum_n h_n` is the neutral + element with respect to functorial composition:: + + sage: p = SymmetricFunctions(QQ).p() + sage: h = SymmetricFunctions(QQ).h() + sage: e = SymmetricFunctions(QQ).e() + sage: L = LazySymmetricFunctions(h) + sage: E = L(lambda n: h[n]) + sage: Ep = p[1]*E.derivative_with_respect_to_p1(); Ep + h[1] + (h[1,1]) + (h[2,1]) + (h[3,1]) + (h[4,1]) + (h[5,1]) + O^7 + sage: f = L(lambda n: h[n-n//2, n//2]) + sage: f - Ep.functorial_composition(f) + O^7 + + The functorial composition distributes over the sum:: - If ``degree`` is not ``None``, the terms of the series of degree greater - than ``degree`` are truncated first. If ``degree`` is ``None`` and the - series is not a polynomial polynomial, a ``ValueError`` is raised. + sage: F1 = L(lambda n: h[n]) + sage: F2 = L(lambda n: e[n]) + sage: f1 = F1.functorial_composition(f) + sage: f2 = F2.functorial_composition(f) + sage: (F1 + F2).functorial_composition(f) - f1 - f2 # long time + O^7 - EXAMPLES:: + TESTS: - sage: L. = LazyTaylorSeriesRing(ZZ) - sage: f = x^2 + y*x - x + 2; f - 2 + (-x) + (x^2+x*y) - sage: f.polynomial() - x^2 + x*y - x + 2 + Check a corner case:: - TESTS:: + sage: h = SymmetricFunctions(QQ).h() + sage: L = LazySymmetricFunctions(h) + sage: L(h[2,1]).functorial_composition(3*h[0]) + 3*h[] + O^7 - sage: g = 1 / (1 + x + y + x*y) - sage: g3 = g.truncate(4); g3 - 1 + (-x-y) + (x^2+x*y+y^2) + (-x^3-x^2*y-x*y^2-y^3) - sage: g.polynomial() + Check an instance of a non-group action:: + + sage: s = SymmetricFunctions(QQ).s() + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(p) + sage: f = L(lambda n: s[n]) + sage: g = 2*s[2, 1, 1] + s[2, 2] + 3*s[4] + sage: r = f.functorial_composition(g); r[4] Traceback (most recent call last): ... - ValueError: not a polynomial - sage: g3.polynomial() - -x^3 - x^2*y - x*y^2 - y^3 + x^2 + x*y + y^2 - x - y + 1 - sage: L.zero().polynomial() - 0 - sage: g3.polynomial() == g.polynomial(3) - True - sage: g3.polynomial(0) - 1 + ValueError: the argument is not the Frobenius character of a permutation representation + """ - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - S = self.parent() - if names is None: - names = S.variable_names() - R = PolynomialRing(S.base_ring(), names=names) - if isinstance(self._coeff_stream, Stream_zero): - return R.zero() + if len(args) != self.parent()._arity: + raise ValueError("arity must be equal to the number of arguments provided") + from sage.combinat.sf.sfa import is_SymmetricFunction + if not all(isinstance(g, LazySymmetricFunction) + or is_SymmetricFunction(g) + or not g for g in args): + raise ValueError("all arguments must be (possibly lazy) symmetric functions") - if degree is None: - if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): - m = self._coeff_stream._degree + if len(args) == 1: + g = args[0] + P = g.parent() + if isinstance(g, LazySymmetricFunction): + R = P._laurent_poly_ring else: - raise ValueError("not a polynomial") - else: - m = degree + 1 + from sage.rings.lazy_series_ring import LazySymmetricFunctions + R = g.parent() + P = LazySymmetricFunctions(R) + g = P(g) - if names is None: - names = S.variable_names() + p = R.realization_of().p() + # TODO: does the following introduce a memory leak? + g = Stream_map_coefficients(g._coeff_stream, p) + f = Stream_map_coefficients(self._coeff_stream, p) - return R.sum(self[:m]) + def g_cycle_type(s, n): + # the cycle type of G[sigma] of any permutation sigma + # with cycle type s, which is a partition of n + if not n: + if g[0]: + return Partition([1]*ZZ(g[0].coefficient([]))) + return Partition([]) + res = [] + # in the species case, k is at most + # factorial(n) * g[n].coefficient([1]*n) + for k in range(1, lcm(s) + 1): + e = 0 + for d in divisors(k): + m = moebius(d) + if not m: + continue + u = s.power(k // d) + # it could be, that we never need to compute + # g[n], so we only do this here + g_u = g[n] + if g_u: + e += m * u.aut() * g_u.coefficient(u) + # e / k might not be an integer if g is not a + # group action, so it is good to check + res.extend([k] * ZZ(e / k)) + res.reverse() + return Partition(res) + def coefficient(n): + terms = {} + t_size = None + for s in Partitions(n): + t = g_cycle_type(s, n) + if t_size is None: + t_size = sum(t) + f_t = f[t_size] + if not f_t: + break + elif t_size != sum(t): + raise ValueError("the argument is not the Frobenius character of a permutation representation") + + terms[s] = t.aut() * f_t.coefficient(t) / s.aut() + return R(p.element_class(p, terms)) + + coeff_stream = Stream_function(coefficient, P._sparse, 0) + return P.element_class(P, coeff_stream) + else: + raise NotImplementedError("only implemented for arity 1") -class LazyCompletionGradedAlgebraElement(LazyCauchyProductSeries): - """ - An element of a completion of a graded algebra that is computed lazily. - """ - def _format_series(self, formatter, format_strings=False): + def arithmetic_product(self, *args, check=True): r""" - Return nonzero ``self`` formatted by ``formatter``. + Return the arithmetic product of ``self`` with ``g``. - TESTS:: + The arithmetic product is a binary operation `\boxdot` on the + ring of symmetric functions which is bilinear in its two + arguments and satisfies - sage: h = SymmetricFunctions(ZZ).h() - sage: e = SymmetricFunctions(ZZ).e() - sage: L = LazySymmetricFunctions(tensor([h, e])) - sage: f = L(lambda n: sum(tensor([h[k], e[n-k]]) for k in range(n+1))) - sage: f._format_series(repr) - '(h[]#e[]) - + (h[]#e[1]+h[1]#e[]) - + (h[]#e[2]+h[1]#e[1]+h[2]#e[]) - + (h[]#e[3]+h[1]#e[2]+h[2]#e[1]+h[3]#e[]) - + (h[]#e[4]+h[1]#e[3]+h[2]#e[2]+h[3]#e[1]+h[4]#e[]) - + (h[]#e[5]+h[1]#e[4]+h[2]#e[3]+h[3]#e[2]+h[4]#e[1]+h[5]#e[]) - + (h[]#e[6]+h[1]#e[5]+h[2]#e[4]+h[3]#e[3]+h[4]#e[2]+h[5]#e[1]+h[6]#e[]) - + O^7' - """ - P = self.parent() - cs = self._coeff_stream - v = cs._approximate_order - if isinstance(cs, Stream_exact): - if not cs._constant: - m = cs._degree - else: - m = cs._degree + P.options.constant_length - else: - m = v + P.options.display_length + .. MATH:: - atomic_repr = P._internal_poly_ring.base_ring()._repr_option('element_is_atomic') - mons = [P._monomial(self[i], i) for i in range(v, m) if self[i]] - if not isinstance(cs, Stream_exact) or cs._constant: - if P._internal_poly_ring.base_ring() is P.base_ring(): - bigO = ["O(%s)" % P._monomial(1, m)] - else: - bigO = ["O^%s" % m] - else: - bigO = [] + p_{\lambda} \boxdot p_{\mu} = \prod\limits_{i \geq 1, j \geq 1} + p_{\mathrm{lcm}(\lambda_i, \mu_j)}^{\mathrm{gcd}(\lambda_i, \mu_j)} + + for any two partitions `\lambda = (\lambda_1, \lambda_2, \lambda_3, + \dots )` and `\mu = (\mu_1, \mu_2, \mu_3, \dots )` (where `p_{\nu}` + denotes the power-sum symmetric function indexed by the partition + `\nu`, and `p_i` denotes the `i`-th power-sum symmetric function). + This is enough to define the arithmetic product if the base ring + is torsion-free as a `\ZZ`-module; for all other cases the + arithmetic product is uniquely determined by requiring it to be + functorial in the base ring. See + http://mathoverflow.net/questions/138148/ for a discussion of + this arithmetic product. + + .. WARNING:: + + The operation `f \boxdot g` was originally defined only + for symmetric functions `f` and `g` without constant + term. We extend this definition using the convention + that the least common multiple of any integer with `0` is + `0`. + + If `f` and `g` are two symmetric functions which are homogeneous + of degrees `a` and `b`, respectively, then `f \boxdot g` is + homogeneous of degree `ab`. + + The arithmetic product is commutative and associative and has + unity `e_1 = p_1 = h_1`. + + For species `M` and `N` such that `M[\varnothing] = + N[\varnothing] = \varnothing`, their arithmetic product is + the species `M \boxdot N` of "`M`-assemblies of cloned + `N`-structures". This operation is defined and several + examples are given in [MM2008]_. - from sage.misc.latex import latex - from sage.typeset.unicode_art import unicode_art - from sage.typeset.ascii_art import ascii_art - from sage.misc.repr import repr_lincomb - from sage.typeset.symbols import ascii_left_parenthesis, ascii_right_parenthesis - from sage.typeset.symbols import unicode_left_parenthesis, unicode_right_parenthesis - if formatter == repr: - poly = repr_lincomb([(1, m) for m in mons + bigO], strip_one=True) - elif formatter == latex: - poly = repr_lincomb([(1, m) for m in mons + bigO], is_latex=True, strip_one=True) - elif formatter == ascii_art: - if atomic_repr: - poly = ascii_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = ascii_art(m) - h = a.height() - return ascii_art(ascii_left_parenthesis.character_art(h), - a, ascii_right_parenthesis.character_art(h)) - poly = ascii_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") - elif formatter == unicode_art: - if atomic_repr: - poly = unicode_art(*(mons + bigO), sep = " + ") - else: - def parenthesize(m): - a = unicode_art(m) - h = a.height() - return unicode_art(unicode_left_parenthesis.character_art(h), - a, unicode_right_parenthesis.character_art(h)) - poly = unicode_art(*([parenthesize(m) for m in mons] + bigO), sep = " + ") + INPUT: - return poly + - ``g`` -- a cycle index series having the same parent as ``self`` + - ``check`` -- (default: ``True``) a Boolean which, when set + to ``False``, will cause input checks to be skipped -class LazySymmetricFunction(LazyCompletionGradedAlgebraElement): - r""" - A symmetric function where each degree is computed lazily. + OUTPUT: - EXAMPLES:: + The arithmetic product of ``self`` with ``g``. - sage: s = SymmetricFunctions(ZZ).s() - sage: L = LazySymmetricFunctions(s) - """ - def __call__(self, *args, check=True): - r""" - Return the composition of ``self`` with ``args``. + .. SEEALSO:: - The arity of ``self`` must be equal to the number of - arguments provided. + :meth:`sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic_Element.arithmetic_product` + + EXAMPLES: - Given two lazy symmetric functions `f` and `g` over the same - base ring, the composition (or plethysm) `(f \circ g)` is - defined if and only if: + For `C` the species of (oriented) cycles and `L_{+}` the + species of nonempty linear orders, `C \boxdot L_{+}` + corresponds to the species of "regular octopuses"; a `(C + \boxdot L_{+})`-structure is a cycle of some length, each of + whose elements is an ordered list of a length which is + consistent for all the lists in the structure. :: - - `g = 0`, - - `g` is non-zero and `f` has only finitely many non-zero coefficients, - - `g` is non-zero and `val(g) > 0`. + sage: R. = QQ[] + sage: p = SymmetricFunctions(R).p() + sage: m = SymmetricFunctions(R).m() + sage: L = LazySymmetricFunctions(m) - INPUT: + sage: C = species.CycleSpecies().cycle_index_series() + sage: c = L(lambda n: C[n]) + sage: Lplus = L(lambda n: p([1]*n), valuation=1) + sage: r = c.arithmetic_product(Lplus); r + m[1] + (3*m[1,1]+2*m[2]) + + (8*m[1,1,1]+4*m[2,1]+2*m[3]) + + (42*m[1,1,1,1]+21*m[2,1,1]+12*m[2,2]+7*m[3,1]+3*m[4]) + + (144*m[1,1,1,1,1]+72*m[2,1,1,1]+36*m[2,2,1]+24*m[3,1,1]+12*m[3,2]+6*m[4,1]+2*m[5]) + + ... + + O^7 - - ``args`` -- other (lazy) symmetric functions + In particular, the number of regular octopuses is:: - EXAMPLES:: + sage: [r[n].coefficient([1]*n) for n in range(8)] + [0, 1, 3, 8, 42, 144, 1440, 5760] - sage: P. = QQ[] - sage: s = SymmetricFunctions(P).s() + It is shown in [MM2008]_ that the exponential generating + function for regular octopuses satisfies `(C \boxdot L_{+}) + (x) = \sum_{n \geq 1} \sigma (n) (n - 1)! \frac{x^{n}}{n!}` + (where `\sigma (n)` is the sum of the divisors of `n`). :: + + sage: [sum(divisors(i))*factorial(i-1) for i in range(1,8)] + [1, 3, 8, 42, 144, 1440, 5760] + + AUTHORS: + + - Andrew Gainer-Dewar (2013) + + REFERENCES: + + - [MM2008]_ + + TESTS: + + Check that the product with zero works:: + + sage: s = SymmetricFunctions(QQ).s() sage: L = LazySymmetricFunctions(s) - sage: f = s[2] - sage: g = s[3] - sage: L(f)(L(g)) - L(f(g)) + sage: L(0).arithmetic_product(s[2]) 0 - - sage: f = s[2] + s[2,1] - sage: g = s[1] + s[2,2] - sage: L(f)(L(g)) - L(f(g)) + sage: L(s[2]).arithmetic_product(0) 0 - sage: L(f)(g) - L(f(g)) - 0 + Check that the arithmetic product of symmetric functions of + finite support works:: - sage: f = s[2] + s[2,1] - sage: g = s[1] + s[2,2] - sage: L(f)(L(q*g)) - L(f(q*g)) - 0 + sage: L(s([2])).arithmetic_product(s([1,1,1])) + s[2, 2, 1, 1] + s[3, 1, 1, 1] + s[3, 2, 1] + s[3, 3] + 2*s[4, 1, 1] - The Frobenius character of the permutation action on set - partitions is a plethysm:: + sage: f = 1/(1-L(s[1])) + sage: f.arithmetic_product(s[1]) - f + O^7 - sage: s = SymmetricFunctions(QQ).s() - sage: S = LazySymmetricFunctions(s) - sage: E1 = S(lambda n: s[n], valuation=1) - sage: E = 1 + E1 - sage: P = E(E1) - sage: [s(x) for x in P[:5]] - [s[], s[1], 2*s[2], s[2, 1] + 3*s[3], 2*s[2, 2] + 2*s[3, 1] + 5*s[4]] + Check that the arithmetic product of symmetric functions with + constant a term works as advertised:: - TESTS:: + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(p) + sage: L(5).arithmetic_product(3*p[2,1]) + 15*p[] + + Check the arithmetic product of symmetric functions over a + finite field works:: + + sage: s = SymmetricFunctions(FiniteField(2)).s() + sage: L = LazySymmetricFunctions(s) + sage: L(s([2])).arithmetic_product(s([1,1,1])) + s[2, 2, 1, 1] + s[3, 1, 1, 1] + s[3, 2, 1] + s[3, 3] - sage: s = SymmetricFunctions(QQ).s() - sage: S = LazySymmetricFunctions(s) - sage: f = 1 / (1 - S(s[2])) - sage: g = f(s[2]); g - s[] + (s[2,2]+s[4]) + O^7 - sage: S(sum(f[i](s[2]) for i in range(5))).truncate(10) == g.truncate(10) - True - sage: f = 1 / (1 - S(s[2])) - sage: g = S(s[1]) / (1 - S(s[1])) - sage: h = f(g) - sage: h - s[] + s[2] + (s[1,1,1]+2*s[2,1]+s[3]) - + (2*s[1,1,1,1]+4*s[2,1,1]+5*s[2,2]+5*s[3,1]+3*s[4]) - + (2*s[1,1,1,1,1]+10*s[2,1,1,1]+14*s[2,2,1]+18*s[3,1,1]+16*s[3,2]+14*s[4,1]+4*s[5]) - + (3*s[1,1,1,1,1,1]+22*s[2,1,1,1,1]+38*s[2,2,1,1]+28*s[2,2,2]+48*s[3,1,1,1]+82*s[3,2,1]+25*s[3,3]+51*s[4,1,1]+56*s[4,2]+31*s[5,1]+9*s[6]) - + O^7 - sage: f(0) - 1 - sage: f(s(1)) - Traceback (most recent call last): - ... - ValueError: can only compose with a positive valuation series """ if len(args) != self.parent()._arity: raise ValueError("arity must be equal to the number of arguments provided") from sage.combinat.sf.sfa import is_SymmetricFunction - if not all(isinstance(g, LazySymmetricFunction) or is_SymmetricFunction(g) or not g for g in args): + if not all(isinstance(g, LazySymmetricFunction) + or is_SymmetricFunction(g) + or not g for g in args): raise ValueError("all arguments must be (possibly lazy) symmetric functions") - if isinstance(self._coeff_stream, Stream_zero): - return self - if len(args) == 1: g = args[0] P = g.parent() - # Handle other types of 0s - if not isinstance(g, LazySymmetricFunction) and not g: - return P(self[0].leading_coefficient()) + # f = 0 or g = (0, ..., 0) + if (isinstance(self._coeff_stream, Stream_zero) + or (not isinstance(g, LazyModuleElement) and not g) + or (isinstance(g, LazyModuleElement) + and isinstance(g._coeff_stream, Stream_zero))): + return P.zero() - if isinstance(self._coeff_stream, Stream_exact) and not self._coeff_stream._constant: - f = self.symmetric_function() - if is_SymmetricFunction(g): - return f(g) - # g must be a LazySymmetricFunction - if isinstance(g._coeff_stream, Stream_exact) and not g._coeff_stream._constant: + if (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): + + if not isinstance(g, LazySymmetricFunction): + f = self.symmetric_function() + return f.arithmetic_product(g) + + if (isinstance(g._coeff_stream, Stream_exact) + and not g._coeff_stream._constant): + f = self.symmetric_function() gs = g.symmetric_function() - return P(f(gs)) + return P(f.arithmetic_product(gs)) if isinstance(g, LazySymmetricFunction): R = P._laurent_poly_ring @@ -3842,22 +5893,42 @@ def __call__(self, *args, check=True): P = LazySymmetricFunctions(R) g = P(g) - # self has (potentially) infinitely many terms - if check: - if g._coeff_stream._approximate_order == 0: - if g[0]: - raise ValueError("can only compose with a positive valuation series") - g._coeff_stream._approximate_order = 1 + # compute the constant term in the case where not both f + # and g have finite support + # TODO: this should be done lazily if possible + c = R.zero() + if self[0]: + if (isinstance(g._coeff_stream, Stream_exact) + and not g._coeff_stream._constant): + gs = g.symmetric_function() + c += self[0].arithmetic_product(gs) + elif check: + raise ValueError("can only take the arithmetic product with a positive valuation series") + if g[0]: + if (isinstance(self._coeff_stream, Stream_exact) + and not self._coeff_stream._constant): + fs = self.symmetric_function() + c += fs.arithmetic_product(g[0]) + elif check: + raise ValueError("can only take the arithmetic product with a positive valuation series") + + p = R.realization_of().p() + # TODO: does the following introduce a memory leak? + g = Stream_map_coefficients(g._coeff_stream, p) + f = Stream_map_coefficients(self._coeff_stream, p) + + def coefficient(n): + if not n: + return c + index_set = ((d, n // d) for d in divisors(n)) + return sum(f[i].arithmetic_product(g[j]) + for i, j in index_set if f[i] and g[j]) - ps = P._laurent_poly_ring.realization_of().p() - coeff_stream = Stream_plethysm(self._coeff_stream, g._coeff_stream, ps) + coeff_stream = Stream_function(coefficient, P._sparse, 0) + return P.element_class(P, coeff_stream) else: raise NotImplementedError("only implemented for arity 1") - return P.element_class(P, coeff_stream) - - plethysm = __call__ - def symmetric_function(self, degree=None): r""" Return ``self`` as a symmetric function if ``self`` is actually so. @@ -3868,9 +5939,10 @@ def symmetric_function(self, degree=None): OUTPUT: - If ``degree`` is not ``None``, the terms of the series of degree greater - than ``degree`` are truncated first. If ``degree`` is ``None`` and the - series is not a polynomial polynomial, a ``ValueError`` is raised. + If ``degree`` is not ``None``, the terms of the series of + degree greater than ``degree`` are first truncated. If + ``degree`` is ``None`` and the series is not a polynomial + polynomial, a ``ValueError`` is raised. EXAMPLES:: @@ -3905,6 +5977,7 @@ def symmetric_function(self, degree=None): 0 sage: f4.symmetric_function(0) s[] + """ S = self.parent() R = S._laurent_poly_ring @@ -3914,7 +5987,7 @@ def symmetric_function(self, degree=None): if degree is None: if (isinstance(self._coeff_stream, Stream_exact) - and not self._coeff_stream._constant): + and not self._coeff_stream._constant): m = self._coeff_stream._degree else: raise ValueError("not a symmetric function") @@ -3923,6 +5996,7 @@ def symmetric_function(self, degree=None): return R.sum(self[:m]) + class LazyDirichletSeries(LazyModuleElement): r""" A Dirichlet series where the coefficients are computed lazily. @@ -3943,6 +6017,30 @@ class LazyDirichletSeries(LazyModuleElement): sage: g == f True """ + def is_unit(self): + """ + Return whether this element is a unit in the ring. + + EXAMPLES:: + + sage: D = LazyDirichletSeriesRing(ZZ, "s") + sage: D([0, 2]).is_unit() + False + + sage: D([-1, 2]).is_unit() + True + + sage: D([3, 2]).is_unit() + False + + sage: D = LazyDirichletSeriesRing(QQ, "s") + sage: D([3, 2]).is_unit() + True + """ + if self.is_zero(): # now 0 != 1 + return False + return self[1].is_unit() + def valuation(self): r""" Return the valuation of ``self``. @@ -4029,12 +6127,12 @@ def _mul_(self, other): and not left._constant and left._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and left.order() == 1): - return other # self == 1 + return other # self == 1 if (isinstance(right, Stream_exact) and not right._constant and right._initial_coefficients == (P._internal_poly_ring.base_ring().one(),) and right.order() == 1): - return self # other == 1 + return self # other == 1 coeff = Stream_dirichlet_convolve(left, right) # Performing exact arithmetic is slow because the series grow large # very quickly as we are multiplying the degree @@ -4062,6 +6160,20 @@ def __invert__(self): sage: ~L(constant=1) - L(moebius) O(1/(8^z)) + Trying to invert a non-invertible 'exact' series raises a + ``ZeroDivisionError``:: + + sage: f = ~L([0,1], constant=1) + sage: f[1] + Traceback (most recent call last): + ... + ZeroDivisionError: the Dirichlet inverse only exists if the coefficient with index 1 is non-zero + + sage: f = ~L(lambda n: n-1) + sage: f[1] + Traceback (most recent call last): + ... + ZeroDivisionError: rational division by zero """ P = self.parent() return P.element_class(P, Stream_dirichlet_invert(self._coeff_stream)) @@ -4166,7 +6278,7 @@ def coefficient(m): except ValueError: return ZZ.zero() R = P._internal_poly_ring.base_ring() - return P.element_class(P, Stream_function(coefficient, R, P._sparse, 1)) + return P.element_class(P, Stream_function(coefficient, P._sparse, 1)) def _format_series(self, formatter, format_strings=False): """ diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index 7ac8caeb7eb..1b540274abd 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -9,11 +9,16 @@ :delim: | :class:`LazyLaurentSeriesRing` | The ring of lazy Laurent series. - :class:`LazyTaylorSeriesRing` | The ring of (possibly multivariate) lazy Taylor series. - :class:`LazyCompletionGradedAlgebra` | The completion of a graded alebra consisting of formal series. + :class:`LazyPowerSeriesRing` | The ring of (possibly multivariate) lazy Taylor series. + :class:`LazyCompletionGradedAlgebra` | The completion of a graded algebra consisting of formal series. :class:`LazySymmetricFunctions` | The ring of (possibly multivariate) lazy symmetric functions. :class:`LazyDirichletSeriesRing` | The ring of lazy Dirichlet series. +.. SEEALSO:: + + :class:`sage.rings.padics.generic_nodes.pAdicRelaxedGeneric`, + :func:`sage.rings.padics.factory.ZpER` + AUTHORS: - Kwankyu Lee (2019-02-24): initial version @@ -38,7 +43,9 @@ from sage.structure.element import parent from sage.categories.algebras import Algebras +from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.categories.rings import Rings +from sage.categories.unique_factorization_domains import UniqueFactorizationDomains from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields from sage.categories.complete_discrete_valuation import (CompleteDiscreteValuationFields, @@ -51,7 +58,8 @@ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.lazy_series import (LazyModuleElement, LazyLaurentSeries, - LazyTaylorSeries, + LazyPowerSeries, + LazyPowerSeries_gcd_mixin, LazyCompletionGradedAlgebraElement, LazySymmetricFunction, LazyDirichletSeries) @@ -62,14 +70,35 @@ from sage.data_structures.stream import ( Stream_zero, Stream_function, + Stream_iterator, Stream_exact, Stream_uninitialized ) +from types import GeneratorType + class LazySeriesRing(UniqueRepresentation, Parent): """ Abstract base class for lazy series. """ + # This will never be called directly (as it is an ABC), but we copy it + # for use in other subclasses. + @staticmethod + def __classcall_private__(cls, base_ring, names, sparse=True, *args, **kwds): + """ + Normalize input to ensure a unique representation. + + EXAMPLES:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: Lp = LazyLaurentSeriesRing(QQ, 'z') + sage: L is Lp + True + """ + from sage.structure.category_object import normalize_names + names = normalize_names(-1, names) + return super().__classcall__(cls, base_ring, names, sparse, *args, **kwds) + def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, coefficients=None): r""" Construct a lazy series from ``x``. @@ -116,7 +145,16 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No coefficients when evaluated at integers. Examples are provided below. - EXAMPLES:: + .. WARNING:: + + If ``x`` is provided as a list, any trailing zeros are + ignored, because ``x`` is immediately converted into a + polynomial. + + EXAMPLES: + + If ``x`` can be converted into an element of the underlying + Laurent polynomial ring, we do this:: sage: L = LazyLaurentSeriesRing(GF(2), 'z') sage: L(2) @@ -124,18 +162,29 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L(3) 1 - sage: L. = LazyLaurentSeriesRing(ZZ) + In particular, ``x`` can be a Laurent polynomial:: + + sage: P. = LaurentPolynomialRing(QQ) + sage: p = x^-2 + 3*x^3 + sage: L. = LazyLaurentSeriesRing(ZZ) + sage: L(p) + x^-2 + 3*x^3 + + sage: L(p, valuation=0) + 1 + 3*x^5 + + sage: L(p, valuation=1) + x + 3*x^6 + + If ``x`` is callable, its evaluation at the integers, + beginning at ``valuation``, defines the coefficients of the series:: + sage: L. = LazyLaurentSeriesRing(ZZ) sage: L(lambda i: i, valuation=5, constant=1, degree=10) 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) sage: L(lambda i: i, valuation=5, constant=(1, 10)) 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) - sage: X = L(constant=5, degree=2); X - 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) - sage: X.valuation() - 2 - sage: def g(i): ....: if i < 0: ....: return 1 @@ -152,6 +201,13 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: f[30] -219 + We can omit ``x``, when defining a series with constant coefficients:: + + sage: X = L(constant=5, degree=2); X + 5*z^2 + 5*z^3 + 5*z^4 + O(z^5) + sage: X.valuation() + 2 + sage: L(valuation=2, constant=1) z^2 + z^3 + z^4 + O(z^5) sage: L(constant=1) @@ -172,19 +228,15 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: g z^5 + 3*z^6 + 5*z^7 + 7*z^8 + 9*z^9 - z^10 - z^11 - z^12 + O(z^13) - Finally, ``x`` can be a Laurent polynomial:: - - sage: P. = LaurentPolynomialRing(QQ) - sage: p = x^-2 + 3*x^3 - sage: L. = LazyLaurentSeriesRing(ZZ) - sage: L(p) - x^-2 + 3*x^3 - - sage: L(p, valuation=0) - 1 + 3*x^5 + If ``x`` is explicitly passed as ``None``, the resulting + series is undefined. This can be used to define it + implicitly, see + :meth:`sage.rings.lazy_series.LazyModuleElement.define`:: - sage: L(p, valuation=1) - x + 3*x^6 + sage: f = L(None, valuation=-1) + sage: f.define(z^-1 + z^2*f^2) + sage: f + z^-1 + 1 + 2*z + 5*z^2 + 14*z^3 + 42*z^4 + 132*z^5 + O(z^6) We construct a lazy Laurent series over another lazy Laurent series:: @@ -235,6 +287,49 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: s[1] 0 + Converting various series from a univariate power series:: + + sage: L = LazyLaurentSeriesRing(GF(2), 'z') + sage: R = LazyPowerSeriesRing(ZZ, 'z') + sage: L.has_coerce_map_from(R) + True + sage: L(R(lambda n: n)) + z + z^3 + z^5 + O(z^7) + sage: L(R([2,4,6])) == L.zero() + True + sage: L(R([2,4,6], valuation=2, constant=4)) == L.zero() + True + sage: L(R([2,4,6], valuation=2, constant=5)) + z^5 + z^6 + z^7 + O(z^8) + sage: L(R([2,3,4], valuation=2, constant=4)) + z^3 + sage: L(R([2,3,4], valuation=2, constant=5)) + z^3 + z^5 + z^6 + z^7 + O(z^8) + + Can only convert from known to be constant multivariate power series:: + + sage: L = LazyLaurentSeriesRing(QQ, 'z') + sage: R. = LazyPowerSeriesRing(QQ) + sage: L(R(2)) + 2 + sage: L(R.zero()) + 0 + sage: L(x) + Traceback (most recent call last): + ... + ValueError: unable to convert ... + sage: L(1 / (1 - x - y)) + Traceback (most recent call last): + ... + ValueError: unable to convert ... + sage: P. = QQ[] + sage: f = R(lambda n: (x+y)^n if n == 0 else P.zero()); f + 1 + O(x,y)^7 + sage: L(f) + Traceback (most recent call last): + ... + ValueError: unable to convert ... + TESTS: Checking the valuation is consistent:: @@ -261,7 +356,6 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: L(z^3/(1-z), valuation=0) 1 + z + z^2 + O(z^3) - sage: L = LazyLaurentSeriesRing(ZZ, 'z') sage: L(lambda n: 1/(n+1), degree=3) Traceback (most recent call last): ... @@ -329,6 +423,11 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No sage: f == g True + We support passing a generator:: + + sage: L(filter(is_odd, NN), -3) + z^-3 + 3*z^-2 + 5*z^-1 + 7 + 9*z + 11*z^2 + 13*z^3 + O(z^4) + .. TODO:: Add a method to change the sparse/dense implementation. @@ -342,6 +441,8 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No raise ValueError("the valuation must be specified") return self.element_class(self, Stream_uninitialized(self._sparse, valuation)) + # WARNING: if x is not explicitly specified as None, it is + # set to 0 by Parent.__call__ if coefficients is not None and (x is not None and (not isinstance(x, int) or x)): raise ValueError("coefficients must be None if x is provided") @@ -356,6 +457,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No if coefficients is None: # Try to build stuff using the internal polynomial ring constructor R = self._internal_poly_ring + try: x = R(x) except (TypeError, ValueError): @@ -376,7 +478,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No return self.element_class(self, coeff_stream) initial_coefficients = [x[i] for i in range(x.valuation(), x.degree() + 1)] coeff_stream = Stream_exact(initial_coefficients, self._sparse, - order=x.valuation(), constant=constant, degree=degree) + order=x.valuation(), degree=degree, constant=constant) return self.element_class(self, coeff_stream) # Handle when it is a lazy series @@ -413,7 +515,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No x._coeff_stream._approximate_order += len(initial_coefficients) initial_coefficients = [] coeff_stream = Stream_exact(initial_coefficients, self._sparse, - order=valuation, constant=constant, degree=degree) + order=valuation, degree=degree, constant=constant) return self.element_class(self, coeff_stream) # We are just possibly shifting the result @@ -422,22 +524,58 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, constant=No return ret return ret.shift(valuation - x._coeff_stream.order()) + # Handle when it is a power series + if isinstance(x, LazyPowerSeries): + stream = x._coeff_stream + if isinstance(stream, Stream_zero): + return self.zero() + elif isinstance(stream, Stream_exact): + BR = self.base_ring() + if x.parent()._arity != 1: + # Special case for constant series + if stream._degree == 1: + return self(BR(stream[0])) + else: + coeffs = [BR(val) for val in stream._initial_coefficients] + valuation = stream._approximate_order + for i, c in enumerate(coeffs): + if c: + valuation += i + coeffs = coeffs[i:] + break + else: + valuation += len(coeffs) + coeffs = [] + return self(coeffs, + degree=stream._degree, + constant=BR(stream._constant), + valuation=valuation) + elif x.parent()._arity == 1: + return self.element_class(self, stream) + raise ValueError(f"unable to convert {x} into {self}") + else: x = coefficients - if callable(x): + if callable(x) or isinstance(x, (GeneratorType, map, filter)): if valuation is None: raise ValueError("the valuation must be specified") if degree is None: if constant is not None: raise ValueError("constant may only be specified if the degree is specified") - coeff_stream = Stream_function(x, self.base_ring(), self._sparse, valuation) + if callable(x): + coeff_stream = Stream_function(lambda i: BR(x(i)), self._sparse, valuation) + else: + coeff_stream = Stream_iterator(map(BR, _skip_leading_zeros(x)), valuation) return self.element_class(self, coeff_stream) # degree is not None if constant is None: constant = BR.zero() - p = [BR(x(i)) for i in range(valuation, degree)] + if callable(x): + p = [BR(x(i)) for i in range(valuation, degree)] + else: + p = [BR(c) for c, _ in zip(_skip_leading_zeros(x), range(valuation, degree))] if not any(p) and not constant: return self.zero() coeff_stream = Stream_exact(p, self._sparse, order=valuation, @@ -455,18 +593,33 @@ def undefined(self, valuation=None): - ``valuation`` -- integer; a lower bound for the valuation of the series Power series can be defined recursively (see - :meth:`sage.rings.lazy_series.LazyModuleElement.define()` for + :meth:`sage.rings.lazy_series.LazyModuleElement.define` for more examples). + .. SEEALSO:: + + :meth:`sage.rings.padics.generic_nodes.pAdicRelaxedGeneric.unknown` + EXAMPLES:: - sage: L. = LazyTaylorSeriesRing(QQ) + sage: L. = LazyPowerSeriesRing(QQ) sage: s = L.undefined(1) sage: s.define(z + (s^2+s(z^2))/2) sage: s z + z^2 + z^3 + 2*z^4 + 3*z^5 + 6*z^6 + 11*z^7 + O(z^8) + + Alternatively:: + + sage: L. = LazyLaurentSeriesRing(QQ) + sage: f = L(None, valuation=-1) + sage: f.define(z^-1 + z^2*f^2) + sage: f + z^-1 + 1 + 2*z + 5*z^2 + 14*z^3 + 42*z^4 + 132*z^5 + O(z^6) """ - return self(None, valuation=valuation) + if valuation is None: + valuation = self._minimal_valuation + coeff_stream = Stream_uninitialized(self._sparse, valuation) + return self.element_class(self, coeff_stream) unknown = undefined @@ -487,8 +640,9 @@ class options(GlobalOptions): sage: LLS. = LazyLaurentSeriesRing(QQ) sage: LLS.options Current options for lazy series rings - - constant_length: 3 - - display_length: 7 + - constant_length: 3 + - display_length: 7 + - halting_precision: None sage: LLS.options.display_length 7 @@ -521,6 +675,9 @@ class options(GlobalOptions): constant_length = dict(default=3, description='the number of coefficients to display for nonzero constant series', checker=lambda x: x in ZZ and x > 0) + halting_precision = dict(default=None, + description='the number of coefficients, beginning with the approximate valuation, to check in equality tests', + checker=lambda x: x is None or x in ZZ and x > 0) @cached_method def one(self): @@ -533,7 +690,7 @@ def one(self): sage: L.one() 1 - sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L = LazyPowerSeriesRing(ZZ, 'z') sage: L.one() 1 @@ -567,7 +724,7 @@ def zero(self): sage: L.zero() 0 - sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L = LazyPowerSeriesRing(ZZ, 'z') sage: L.zero() 0 """ @@ -589,7 +746,7 @@ def characteristic(self): sage: R.characteristic() 11 - sage: R. = LazyTaylorSeriesRing(GF(7)); R + sage: R. = LazyPowerSeriesRing(GF(7)); R Multivariate Lazy Taylor Series Ring in x, y over Finite Field of size 7 sage: R.characteristic() 7 @@ -611,8 +768,22 @@ def _coerce_map_from_(self, S): True sage: L.has_coerce_map_from(GF(2)) True + sage: R = LazyPowerSeriesRing(ZZ, 'z') + sage: L.has_coerce_map_from(R) + True - sage: L = LazyTaylorSeriesRing(GF(2), 'z') + sage: L = LazyLaurentSeriesRing(QQ, 'z') + sage: R = LazyPowerSeriesRing(QQ, 'z') + sage: L.has_coerce_map_from(R) + True + sage: R = LazyPowerSeriesRing(ZZ, 'z') + sage: L.has_coerce_map_from(R) + True + sage: R = LazyPowerSeriesRing(ZZ['t'], 'z') + sage: L.has_coerce_map_from(R) + False + + sage: L = LazyPowerSeriesRing(GF(2), 'z') sage: L.has_coerce_map_from(ZZ) True sage: L.has_coerce_map_from(GF(2)) @@ -629,7 +800,14 @@ def _coerce_map_from_(self, S): return True R = self._laurent_poly_ring - return R.has_coerce_map_from(S) + if R.has_coerce_map_from(S): + return True + + if (isinstance(S, LazySeriesRing) + and self._laurent_poly_ring.has_coerce_map_from(S._laurent_poly_ring)): + return True + + return None def _coerce_map_from_base_ring(self): """ @@ -691,8 +869,142 @@ def is_exact(self): """ return self.base_ring().is_exact() + def _test_invert(self, **options): + """ + Test multiplicative inversion of elements of ``self``. + + INPUT: + + - ``options`` -- any keyword arguments accepted by :meth:`_tester` + + EXAMPLES:: + + sage: LazyLaurentSeriesRing.options.halting_precision(5) + sage: L = LazyLaurentSeriesRing(QQ, 'z') + sage: L._test_invert() + sage: LazyLaurentSeriesRing.options._reset() # reset the options + + .. SEEALSO:: + + :class:`TestSuite` + """ + tester = self._tester(**options) + + elements = tester.some_elements() + for x in elements: + # because of laziness, creating the inverse of x should + # always succeed except if the series is 'exact' + if not x.is_unit(): + continue + y = ~x + e = y * x + tester.assertFalse(x.is_zero(), "zero should not be invertible") + tester.assertTrue(e.is_one(), "an element (%s) times its inverse should be 1" % x) + tester.assertEqual(y.valuation(), -x.valuation(), "the valuation of the inverse should be the negative of the valuation of the element (%s)" % x) + + def _test_div(self, **options): + r""" + Test division of elements of this ring. + + INPUT: + + - ``options`` -- any keyword arguments accepted by :meth:`_tester` + + EXAMPLES:: + + sage: LazyLaurentSeriesRing.options.halting_precision(5) + sage: L = LazyLaurentSeriesRing(QQ, 'z') + sage: L._test_div() + sage: LazyLaurentSeriesRing.options._reset() # reset the options + + .. SEEALSO:: + + :class:`TestSuite` + """ + from sage.misc.misc import some_tuples + tester = self._tester(**options) + + elements = list(tester.some_elements()) + for x, y in some_tuples(elements, 2, tester._max_runs): + # because of laziness, creating the inverse of x should + # always succeed except if the series is 'exact' + if not y.is_unit(): + continue + z = x / y + xx = z * y + try: + v_z = z.valuation() + except Exception as error: + raise ValueError("could not compute the valuation of the quotient (%s)/(%s): %s" % (x, y, error)) + else: + v_x = x.valuation() + v_y = y.valuation() + tester.assertEqual(v_z, v_x - v_y, "the valuation of the quotient should be the difference of the valuations of the elements (%s and %s)" % (x, y)) + tester.assertEqual(xx, x, "the element (%s) should be the quotient times the divisor (%s)" % (x, y)) + + def _test_revert(self, **options): + """ + Test compositional inverse of elements of this ring. + + INPUT: + + - ``options`` -- any keyword arguments accepted by :meth:`_tester` + + EXAMPLES:: + + sage: LazyLaurentSeriesRing.options.halting_precision(5) + sage: L = LazyLaurentSeriesRing(QQ, 'z') + sage: L._test_revert() + sage: LazyLaurentSeriesRing.options._reset() + + .. SEEALSO:: + + :class:`TestSuite` + """ + if not hasattr(self.element_class, "revert") or self._arity != 1: + return + tester = self._tester(**options) + + elements = tester.some_elements() + count = 0 + for x in elements: + # because of laziness, creating the compositional inverse + # of x should always succeed, except if the series is + # 'exact' or if it has negative valuation + vx = x.valuation() + if (vx != 1 + and not (isinstance(x._coeff_stream, Stream_exact) + and ((vx == 0 + and x._coeff_stream._degree == 2 + and not x._coeff_stream._constant) + or (vx == -1 + and x._coeff_stream._degree == 0 + and not x._coeff_stream._constant)))): + continue + try: + y = x.revert() + except Exception as error: + raise AssertionError("compositional inverse of %s should exist: %s" % (x, error)) + try: + vy = y.valuation() + _ = y[vy] + except NotImplementedError: + pass + except (ValueError, TypeError): + tester.assertFalse(vx == 1 and x[vx].is_unit(), + ("the series %s should be reversible " + "- its valuation is one and its leading coefficient is a unit") % x) + else: + count += 1 + e1 = y(x) + e2 = x(y) + tester.assertEqual(e1, e2, "y(x) and x(y) differ for x = %s and y = %s" %(x, y)) + # tester.assertEqual(e1, self.gen()) + # we want to test at least 2 elements + tester.assertGreater(count, 1, msg="only %s elements in %s.some_elements() have a compositional inverse" % (count, self)) + class LazyLaurentSeriesRing(LazySeriesRing): - """ + r""" The ring of lazy Laurent series. The ring of Laurent series over a ring with the usual arithmetic @@ -726,8 +1038,7 @@ class LazyLaurentSeriesRing(LazySeriesRing): Finite Field of size 3 Series can be defined by specifying a coefficient function - along with a valuation or a degree where after the series - is evenutally constant:: + and a valuation:: sage: R. = QQ[] sage: L. = LazyLaurentSeriesRing(R) @@ -747,9 +1058,9 @@ class LazyLaurentSeriesRing(LazySeriesRing): -5*z^-3 - 4*z^-2 - 3*z^-1 + 6 + (x + y)*z + (y^2 + x)*z^2 + x*z^3 + x*z^4 + x*z^5 + O(z^6) - Similarly, we can specify a polynomial or the initial - coefficients with anything that converts into the - corresponding Laurent polynomial ring:: + We can also specify a polynomial or the initial coefficients. + Additionally, we may specify that all coefficients are equal to a + given constant, beginning at a given degree:: sage: L([1, x, y, 0, x+y]) 1 + x*z + y*z^2 + (x + y)*z^4 @@ -780,8 +1091,8 @@ class LazyLaurentSeriesRing(LazySeriesRing): sage: L(x^-2 + 3 + x, valuation=-5, degree=0, constant=2) z^-5 + 3*z^-3 + z^-2 + 2 + 2*z + 2*z^2 + O(z^3) - We can also truncate, shift, and make eventually constant any - Laurent series:: + We can truncate a series, shift its coefficients, or replace all + coefficients beginning with a given degree by a constant:: sage: f = 1 / (z + z^2) sage: f @@ -798,20 +1109,20 @@ class LazyLaurentSeriesRing(LazySeriesRing): z - z^2 + z^3 + 5*z^4 + 5*z^5 + 5*z^6 + O(z^7) Power series can be defined recursively (see - :meth:`sage.rings.lazy_series.LazyModuleElement.define()` for + :meth:`sage.rings.lazy_series.LazyModuleElement.define` for more examples):: sage: L. = LazyLaurentSeriesRing(ZZ) - sage: s = L(None, valuation=0) + sage: s = L.undefined(valuation=0) sage: s.define(1 + z*s^2) sage: s 1 + z + 2*z^2 + 5*z^3 + 14*z^4 + 42*z^5 + 132*z^6 + O(z^7) - If we do not explcitly know the exact value of every coefficient, - then equality checking will depend on the computed coefficients. - If at a certain point we cannot prove two series are different - (which involves the coefficients we have computed), then we will - raise an error:: + If the series is not specified by a finite number of initial + coefficients and a constant for the remaining coefficients, then + equality checking will depend on the coefficients which have + already been computed. If this information is not enough to + check that two series are different we raise an error:: sage: f = 1 / (z + z^2); f z^-1 - 1 + z - z^2 + z^3 - z^4 + z^5 + O(z^6) @@ -837,38 +1148,67 @@ class LazyLaurentSeriesRing(LazySeriesRing): sage: L. = LazyLaurentSeriesRing(ZZ, sparse=False) sage: L.is_sparse() False - """ Element = LazyLaurentSeries + # Follow the "generic" normalization + __classcall_private__ = LazySeriesRing.__classcall_private__ + def __init__(self, base_ring, names, sparse=True, category=None): """ Initialize ``self``. TESTS:: + sage: LazyLaurentSeriesRing.options.halting_precision(12) + sage: L = LazyLaurentSeriesRing(ZZ, 't') - sage: elts = L.some_elements()[:-2] # skip the non-exact elements - sage: TestSuite(L).run(elements=elts, skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) + sage: TestSuite(L).run() sage: L.category() Category of infinite commutative no zero divisors algebras over (euclidean domains and infinite enumerated sets and metric spaces) sage: L = LazyLaurentSeriesRing(QQ, 't') + sage: TestSuite(L).run() sage: L.category() Join of Category of complete discrete valuation fields and Category of commutative algebras over (number fields and quotient fields and metric spaces) and Category of infinite sets - sage: L = LazyLaurentSeriesRing(ZZ['x,y'], 't') + + sage: L = LazyLaurentSeriesRing(ZZ['x, y'], 't') + sage: TestSuite(L).run() sage: L.category() Category of infinite commutative no zero divisors algebras over (unique factorization domains and commutative algebras over (euclidean domains and infinite enumerated sets and metric spaces) and infinite sets) + + sage: L = LazyLaurentSeriesRing(GF(5), 't') + sage: TestSuite(L).run() + + sage: L = LazyLaurentSeriesRing(GF(5)['x'], 't') + sage: TestSuite(L).run() + + sage: L = LazyLaurentSeriesRing(GF(5)['x, y'], 't') + sage: TestSuite(L).run() + + sage: L = LazyLaurentSeriesRing(Zmod(6), 't') + sage: TestSuite(L).run(skip=['_test_revert']) + sage: L.category() + Category of infinite commutative algebras over + (finite commutative rings and subquotients of monoids + and quotients of semigroups and finite enumerated sets) + sage: E. = ExteriorAlgebra(QQ) sage: L = LazyLaurentSeriesRing(E, 't') # not tested + + sage: LazyLaurentSeriesRing.options._reset() # reset the options """ self._sparse = sparse + if len(names) != 1: + raise ValueError("only univariate lazy Laurent series are implemented") + self._arity = 1 + self._minimal_valuation = None # We always use the dense because our CS_exact is implemented densely self._laurent_poly_ring = LaurentPolynomialRing(base_ring, names) self._internal_poly_ring = self._laurent_poly_ring @@ -876,11 +1216,10 @@ def __init__(self, base_ring, names, sparse=True, category=None): category = Algebras(base_ring.category()) if base_ring in Fields(): category &= CompleteDiscreteValuationFields() - else: - if "Commutative" in base_ring.category().axioms(): - category = category.Commutative() - if base_ring in IntegralDomains(): - category &= IntegralDomains() + elif base_ring in IntegralDomains(): + category &= IntegralDomains() + elif "Commutative" in base_ring.category().axioms(): + category = category.Commutative() if base_ring.is_zero(): category = category.Finite() @@ -972,12 +1311,12 @@ def _an_element_(self): sage: L = LazyLaurentSeriesRing(ZZ, 'z') sage: L.an_element() - z^-2 + 3*z^-1 + 2*z + z^2 + z^3 + z^4 + z^5 + O(z^6) + z^-2 + z^3 + z^4 + z^5 + O(z^6) """ - R = self.base_ring() - coeff_stream = Stream_exact([R.an_element(), 3, 0, 2*R.an_element(), 1], - self._sparse, order=-2, constant=R.one()) - return self.element_class(self, coeff_stream) + return self(self._laurent_poly_ring.an_element(), + valuation=-2, + degree=3, + constant=self.base_ring().an_element()) def some_elements(self): """ @@ -986,32 +1325,35 @@ def some_elements(self): EXAMPLES:: sage: L = LazyLaurentSeriesRing(ZZ, 'z') - sage: L.some_elements() + sage: L.some_elements()[:7] [0, 1, z, -3*z^-4 + z^-3 - 12*z^-2 - 2*z^-1 - 10 - 8*z + z^2 + z^3, - z^-2 + 3*z^-1 + 2*z + z^2 + z^3 + z^4 + z^5 + O(z^6), + z^-2 + z^3 + z^4 + z^5 + O(z^6), -2*z^-3 - 2*z^-2 + 4*z^-1 + 11 - z - 34*z^2 - 31*z^3 + O(z^4), 4*z^-2 + z^-1 + z + 4*z^2 + 9*z^3 + 16*z^4 + O(z^5)] sage: L = LazyLaurentSeriesRing(GF(2), 'z') - sage: L.some_elements() + sage: L.some_elements()[:7] [0, 1, z, z^-4 + z^-3 + z^2 + z^3, - z^-1 + z^2 + z^3 + z^4 + z^5 + O(z^6), + z^-2, 1 + z + z^3 + z^4 + z^6 + O(z^7), z^-1 + z + z^3 + O(z^5)] sage: L = LazyLaurentSeriesRing(GF(3), 'z') - sage: L.some_elements() + sage: L.some_elements()[:7] [0, 1, z, z^-3 + z^-1 + 2 + z + z^2 + z^3, - z^2 + z^3 + z^4 + z^5 + O(z^6), + z^-2, z^-3 + z^-2 + z^-1 + 2 + 2*z + 2*z^2 + O(z^3), z^-2 + z^-1 + z + z^2 + z^4 + O(z^5)] """ z = self.gen() elts = [self.zero(), self.one(), z, (z-3)*(z**-2+2+z)**2, self.an_element(), - (1 - 2*z**-3)/(1 - z + 3*z**2), self(lambda n: n**2, valuation=-2)] + (1 - 2*z**-3)/(1 - z + 3*z**2), + self(lambda n: n**2, valuation=-2), + self(lambda n: n**2, valuation=1), + self([3, 2, 1], valuation=1, constant=1)] return elts def series(self, coefficient, valuation, degree=None, constant=None): @@ -1115,9 +1457,40 @@ def _monomial(self, c, n): """ return self._laurent_poly_ring(c).shift(n) + def uniformizer(self): + """ + Return a uniformizer of ``self``.. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(QQ, 'z') + sage: L.uniformizer() + z + """ + R = self.base_ring() + if R not in Fields(): + raise TypeError("the base ring is not a field") + return self.gen() + + def residue_field(self): + """ + Return the residue field of the ring of integers of ``self``. + + EXAMPLES:: + + sage: L = LazyLaurentSeriesRing(QQ, 'z') + sage: L.residue_field() + Rational Field + """ + R = self.base_ring() + if R not in Fields(): + raise TypeError("the base ring is not a field") + return R + ###################################################################### -class LazyTaylorSeriesRing(LazySeriesRing): + +class LazyPowerSeriesRing(LazySeriesRing): """ The ring of (possibly multivariate) lazy Taylor series. @@ -1129,13 +1502,16 @@ class LazyTaylorSeriesRing(LazySeriesRing): EXAMPLES:: - sage: LazyTaylorSeriesRing(ZZ, 't') + sage: LazyPowerSeriesRing(ZZ, 't') Lazy Taylor Series Ring in t over Integer Ring - sage: L. = LazyTaylorSeriesRing(QQ); L + sage: L. = LazyPowerSeriesRing(QQ); L Multivariate Lazy Taylor Series Ring in x, y over Rational Field """ - Element = LazyTaylorSeries + Element = LazyPowerSeries + + # Follow the "generic" normalization + __classcall_private__ = LazySeriesRing.__classcall_private__ def __init__(self, base_ring, names, sparse=True, category=None): """ @@ -1143,26 +1519,90 @@ def __init__(self, base_ring, names, sparse=True, category=None): TESTS:: - sage: L = LazyTaylorSeriesRing(ZZ, 't') - sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) + sage: LazyPowerSeriesRing.options.halting_precision(12) + + sage: L = LazyPowerSeriesRing(ZZ, 't') + sage: TestSuite(L).run(skip="_test_fraction_field") + sage: L = LazyPowerSeriesRing(ZZ, 's, t') + sage: TestSuite(L).run(skip="_test_fraction_field") + + sage: L = LazyPowerSeriesRing(QQ, 't') + sage: TestSuite(L).run(skip="_test_fraction_field") + sage: L = LazyPowerSeriesRing(QQ, 's, t') + sage: TestSuite(L).run(skip="_test_fraction_field") + + sage: L = LazyPowerSeriesRing(GF(5), 't') + sage: TestSuite(L).run() + + sage: L = LazyPowerSeriesRing(GF(5), 's, t') + sage: TestSuite(L).run(skip=['_test_fraction_field']) + + sage: L = LazyPowerSeriesRing(Zmod(6), 't') + sage: TestSuite(L).run(skip=['_test_revert']) + sage: L = LazyPowerSeriesRing(Zmod(6), 's, t') + sage: TestSuite(L).run(skip=['_test_revert']) + + sage: L = LazyPowerSeriesRing(QQ['q'], 't') + sage: TestSuite(L).run(skip="_test_fraction_field") + sage: L = LazyPowerSeriesRing(QQ['q'], 's, t') + sage: TestSuite(L).run(skip="_test_fraction_field") # long time + + sage: L = LazyPowerSeriesRing(ZZ['q'], 't') + sage: TestSuite(L).run(skip="_test_fraction_field") + sage: L = LazyPowerSeriesRing(ZZ['q'], 's, t') + sage: TestSuite(L).run(skip="_test_fraction_field") # long time + + sage: LazyPowerSeriesRing.options._reset() # reset the options + + Check that :trac:`34470` is fixed:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: L in CompleteDiscreteValuationRings + True + sage: L.uniformizer() + t + sage: lcm(1/(1 - t^2) - 1, t) + t^2 + + sage: L. = LazyPowerSeriesRing(ZZ) + sage: L in PrincipalIdealDomains + False + + The ideal generated by `s` and `t` is not principal:: + + sage: L = LazyPowerSeriesRing(QQ, 's, t') + sage: L in PrincipalIdealDomains + False """ - from sage.structure.category_object import normalize_names - names = normalize_names(-1, names) self._sparse = sparse + self._minimal_valuation = 0 self._laurent_poly_ring = PolynomialRing(base_ring, names) - if len(names) == 1: + self._arity = len(names) + if self._arity == 1: self._internal_poly_ring = self._laurent_poly_ring else: - coeff_ring = PolynomialRing(base_ring, names) - self._internal_poly_ring = PolynomialRing(coeff_ring, "DUMMY_VARIABLE") + self._internal_poly_ring = PolynomialRing(self._laurent_poly_ring, "DUMMY_VARIABLE") category = Algebras(base_ring.category()) - if base_ring in Fields(): - category &= CompleteDiscreteValuationRings() - elif base_ring in IntegralDomains(): + mixin_gcd = False + if self._arity == 1: + if base_ring in Fields(): + category &= CompleteDiscreteValuationRings() + mixin_gcd = True + elif base_ring in Fields(): + category &= UniqueFactorizationDomains() + mixin_gcd = True + if base_ring in IntegralDomains(): category &= IntegralDomains() elif base_ring in Rings().Commutative(): category = category.Commutative() + if mixin_gcd: + from sage.structure.dynamic_class import dynamic_class + self.Element = dynamic_class( + f"{self.Element.__name__}_gcd", + (self.Element, LazyPowerSeries_gcd_mixin), + doccls=self.Element) + if base_ring.is_zero(): category = category.Finite() else: @@ -1176,7 +1616,7 @@ def _repr_(self): EXAMPLES:: - sage: LazyTaylorSeriesRing(GF(2), 'z') + sage: LazyPowerSeriesRing(GF(2), 'z') Lazy Taylor Series Ring in z over Finite Field of size 2 """ BR = self.base_ring() @@ -1191,7 +1631,7 @@ def _latex_(self): EXAMPLES:: - sage: L = LazyTaylorSeriesRing(GF(2), 'z') + sage: L = LazyPowerSeriesRing(GF(2), 'z') sage: latex(L) \Bold{F}_{2} [\![z]\!] """ @@ -1205,7 +1645,7 @@ def _monomial(self, c, n): EXAMPLES:: - sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L = LazyPowerSeriesRing(ZZ, 'z') sage: L._monomial(2, 3) 2*z^3 """ @@ -1222,7 +1662,7 @@ def gen(self, n=0): EXAMPLES:: - sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L = LazyPowerSeriesRing(ZZ, 'z') sage: L.gen() z sage: L.gen(3) @@ -1250,7 +1690,7 @@ def ngens(self): EXAMPLES:: - sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L. = LazyPowerSeriesRing(ZZ) sage: L.ngens() 1 """ @@ -1263,13 +1703,13 @@ def gens(self): EXAMPLES:: - sage: L = LazyTaylorSeriesRing(ZZ, 'x,y') + sage: L = LazyPowerSeriesRing(ZZ, 'x,y') sage: L.gens() (x, y) """ return tuple([self.gen(n) for n in range(self.ngens())]) - def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None, check=True): + def _element_constructor_(self, x=None, valuation=None, constant=None, degree=None, coefficients=None, check=True): """ Construct a Taylor series from ``x``. @@ -1281,15 +1721,22 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No - ``degree`` -- (optional) the degree when the series is ``constant`` - ``check`` -- (optional) check that coefficients are homogeneous of the correct degree when they are retrieved + .. WARNING:: + + The behaviour of ``LazyPowerSeries(c)`` for a list ``c`` + with non-zero last element `e` changed with + :trac:`32367`. To obtain the old behaviour, use + ``LazyPowerSeries(c, constant=e)``. + EXAMPLES:: - sage: L = LazyTaylorSeriesRing(GF(2), 'z') + sage: L = LazyPowerSeriesRing(GF(2), 'z') sage: L(2) 0 sage: L(3) 1 - sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L = LazyPowerSeriesRing(ZZ, 'z') sage: L(lambda i: i, 5, 1, 10) 5*z^5 + 6*z^6 + 7*z^7 + 8*z^8 + 9*z^9 + z^10 + z^11 + z^12 + O(z^13) sage: L(lambda i: i, 5, (1, 10)) @@ -1334,7 +1781,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: P. = QQ[] sage: p = x + 3*x^2 + x^5 - sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L. = LazyPowerSeriesRing(ZZ) sage: L(p) x + 3*x^2 + x^5 @@ -1343,13 +1790,13 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No sage: P. = QQ[] sage: p = x + y^2 + x*y - sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L. = LazyPowerSeriesRing(ZZ) sage: L(p) x + (x*y+y^2) TESTS:: - sage: L. = LazyTaylorSeriesRing(ZZ) + sage: L. = LazyPowerSeriesRing(ZZ) sage: L(constant=1) Traceback (most recent call last): ... @@ -1376,10 +1823,11 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No """ if valuation is not None: if valuation < 0: - raise ValueError("the valuation of a Taylor series must be positive") - if len(self.variable_names()) > 1: + raise ValueError("the valuation of a Taylor series must be non-negative") + # TODO: the following is nonsense, think of an iterator + if self._arity > 1: raise ValueError("valuation must not be specified for multivariate Taylor series") - if len(self.variable_names()) > 1: + if self._arity > 1: valuation = 0 R = self._laurent_poly_ring @@ -1388,6 +1836,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No assert degree is None coeff_stream = Stream_uninitialized(self._sparse, valuation) return self.element_class(self, coeff_stream) + try: # Try to build stuff using the polynomial ring constructor x = R(x) @@ -1396,9 +1845,10 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No if isinstance(constant, (tuple, list)): constant, degree = constant if constant is not None: - if len(self.variable_names()) > 1 and constant: + if self._arity > 1 and constant: raise ValueError("constant must be zero for multivariate Taylor series") constant = BR(constant) + if x in R: if not x and not constant: coeff_stream = Stream_zero(self._sparse) @@ -1410,7 +1860,7 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No constant=constant) return self.element_class(self, coeff_stream) - if len(self.variable_names()) == 1: + if self._arity == 1: v = x.valuation() d = x.degree() p_list = [x[i] for i in range(v, d + 1)] @@ -1428,21 +1878,46 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No degree=degree) return self.element_class(self, coeff_stream) - if isinstance(x, LazyTaylorSeries): + if isinstance(x, LazyPowerSeries): if x._coeff_stream._is_sparse is self._sparse: - return self.element_class(self, x._coeff_stream) + stream = x._coeff_stream + if isinstance(stream, Stream_exact): + if self._arity == 1: + BR = self.base_ring() + else: + BR = self._laurent_poly_ring + coeffs = [BR(val) for val in stream._initial_coefficients] + valuation = stream._approximate_order + for i, c in enumerate(coeffs): + if c: + valuation += i + coeffs = coeffs[i:] + break + else: + valuation += len(coeffs) + coeffs = [] + return self(coeffs, + degree=stream._degree, + constant=self.base_ring()(stream._constant), + valuation=valuation) + return self.element_class(self, stream) # TODO: Implement a way to make a self._sparse copy raise NotImplementedError("cannot convert between sparse and dense") - if callable(x): + + if callable(x) or isinstance(x, (GeneratorType, map, filter)): if valuation is None: valuation = 0 if degree is not None: if constant is None: constant = ZZ.zero() - if len(self.variable_names()) == 1: - p = [BR(x(i)) for i in range(valuation, degree)] + if callable(x): + p = [x(i) for i in range(valuation, degree)] + else: + p = [c for c, _ in zip(_skip_leading_zeros(x), range(valuation, degree))] + if self._arity == 1: + p = [BR(c) for c in p] else: - p = [R(x(i)) for i in range(valuation, degree)] + p = [R(c) for c in p] if not all(e.is_homogeneous() and e.degree() == i for i, e in enumerate(p, valuation)): raise ValueError("coefficients must be homogeneous polynomials of the correct degree") @@ -1451,16 +1926,21 @@ def _element_constructor_(self, x=None, valuation=None, constant=None, degree=No constant=constant, degree=degree) return self.element_class(self, coeff_stream) - coeff_ring = self._internal_poly_ring.base_ring() - if check and len(self.variable_names()) > 1: - def y(n): - e = R(x(n)) - if not e or e.is_homogeneous() and e.degree() == n: - return e - raise ValueError("coefficient %s at degree %s is not a homogeneous polynomial" % (e, n)) - coeff_stream = Stream_function(y, coeff_ring, self._sparse, valuation) + if check and self._arity > 1: + if callable(x): + def y(n): + e = R(x(n)) + if not e or e.is_homogeneous() and e.degree() == n: + return e + raise ValueError("coefficient %s at degree %s is not a homogeneous polynomial" % (e, n)) + coeff_stream = Stream_function(y, self._sparse, valuation) + else: + coeff_stream = Stream_iterator(map(R, _skip_leading_zeros(x)), valuation) else: - coeff_stream = Stream_function(x, coeff_ring, self._sparse, valuation) + if callable(x): + coeff_stream = Stream_function(lambda i: BR(x(i)), self._sparse, valuation) + else: + coeff_stream = Stream_iterator(map(BR, _skip_leading_zeros(x)), valuation) return self.element_class(self, coeff_stream) raise ValueError(f"unable to convert {x} into a lazy Taylor series") @@ -1470,21 +1950,123 @@ def _an_element_(self): EXAMPLES:: - sage: L = LazyTaylorSeriesRing(ZZ, 'z') + sage: L = LazyPowerSeriesRing(ZZ, 'z') + sage: L.an_element() + z + z^2 + z^3 + O(z^4) + + sage: L = LazyPowerSeriesRing(ZZ, 'x, y') sage: L.an_element() - z + z^2 + z^3 + z^4 + O(z^5) + x """ - c = self.base_ring().an_element() - R = self._laurent_poly_ring - coeff_stream = Stream_exact([R.one()], self._sparse, order=1, constant=c) - return self.element_class(self, coeff_stream) + if self._arity == 1: + return self(self._laurent_poly_ring.an_element(), + constant=self.base_ring().an_element()) + return self(self._laurent_poly_ring.an_element()) + def uniformizer(self): + """ + Return a uniformizer of ``self``. + + EXAMPLES:: + + sage: L = LazyPowerSeriesRing(QQ, 'x') + sage: L.uniformizer() + x + """ + R = self.base_ring() + if R not in Fields(): + raise TypeError("the base ring is not a field") + if self._arity != 1: + raise TypeError("the arity must be one") + return self.gen() + + def residue_field(self): + """ + Return the residue field of the ring of integers of ``self``. + + EXAMPLES:: + + sage: L = LazyPowerSeriesRing(QQ, 'x') + sage: L.residue_field() + Rational Field + """ + R = self.base_ring() + if R not in Fields(): + raise TypeError("the base ring is not a field") + if self._arity != 1: + raise TypeError("the arity must be one") + return R + + def fraction_field(self): + """ + Return the fraction field of ``self``. + + If this is with a single variable over a field, then the fraction + field is the field of (lazy) formal Laurent series. + + .. TODO:: + + Implement other fraction fields. + + EXAMPLES:: + + sage: L. = LazyPowerSeriesRing(QQ) + sage: L.fraction_field() + Lazy Laurent Series Ring in x over Rational Field + """ + if self not in IntegralDomains(): + raise TypeError("must be an integral domain") + R = self.base_ring() + if self._arity == 1 and R in Fields(): + return LazyLaurentSeriesRing(R, names=self.variable_names()) + raise NotImplementedError("the fraction field is not yet implemented") + + def some_elements(self): + """ + Return a list of elements of ``self``. + + EXAMPLES:: + + sage: L = LazyPowerSeriesRing(ZZ, 'z') + sage: L.some_elements()[:6] + [0, 1, z + z^2 + z^3 + O(z^4), + -12 - 8*z + z^2 + z^3, + 1 + z - 2*z^2 - 7*z^3 - z^4 + 20*z^5 + 23*z^6 + O(z^7), + z + 4*z^2 + 9*z^3 + 16*z^4 + 25*z^5 + 36*z^6 + O(z^7)] + + sage: L = LazyPowerSeriesRing(GF(3)["q"], 'z') + sage: L.some_elements()[:6] + [0, 1, z + q*z^2 + q*z^3 + q*z^4 + O(z^5), + z + z^2 + z^3, + 1 + z + z^2 + 2*z^3 + 2*z^4 + 2*z^5 + O(z^6), + z + z^2 + z^4 + z^5 + O(z^7)] + + sage: L = LazyPowerSeriesRing(GF(3), 'q, t') + sage: L.some_elements()[:6] + [0, 1, q, + q + q^2 + q^3, + 1 + q + q^2 + (-q^3) + (-q^4) + (-q^5) + (-q^6) + O(q,t)^7, + 1 + (q+t) + (q^2-q*t+t^2) + (q^3+t^3) + + (q^4+q^3*t+q*t^3+t^4) + + (q^5-q^4*t+q^3*t^2+q^2*t^3-q*t^4+t^5) + + (q^6-q^3*t^3+t^6) + O(q,t)^7] + """ + z = self.gen(0) + elts = [self.zero(), self.one(), self.an_element()] + if self._arity == 1: + elts.extend([(z-3)*(2+z)**2, (1 - 2*z**3)/(1 - z + 3*z**2), self(lambda n: n**2)]) + else: + PR = self._laurent_poly_ring + sum_gens = PR.sum(PR.gens()) + elts.extend([(z-3)*(2+z)**2, (1 - 2*z**3)/(1 - z + 3*z**2), self(lambda n: sum_gens**n)]) + return elts ###################################################################### + class LazyCompletionGradedAlgebra(LazySeriesRing): r""" - The completion of a graded alebra consisting of formal series. + The completion of a graded algebra consisting of formal series. For a graded algebra `A`, we can form a completion of `A` consisting of all formal series of `A` such that each homogeneous component is @@ -1532,21 +2114,57 @@ def __init__(self, basis, sparse=True, category=None): TESTS:: + sage: LazySymmetricFunctions.options.halting_precision(6) + + sage: s = SymmetricFunctions(QQ).s() + sage: L = LazySymmetricFunctions(s) + sage: TestSuite(L).run() + + sage: p = SymmetricFunctions(GF(5)).p() + sage: L = LazySymmetricFunctions(p) + sage: TestSuite(L).run() + + Reversion will only work when the base ring is a field:: + sage: s = SymmetricFunctions(ZZ).s() sage: L = LazySymmetricFunctions(s) - sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) + sage: TestSuite(L).run(skip=['_test_revert']) + + sage: s = SymmetricFunctions(QQ["q"]).s() + sage: L = LazySymmetricFunctions(s) + sage: TestSuite(L).run(skip=['_test_revert']) + + Options are remembered across doctests:: + + sage: LazySymmetricFunctions.options._reset() + + Check that :trac:`34470` is fixed. The ideal generated by + `p[1]` and `p[2]` is not principal:: + + sage: p = SymmetricFunctions(QQ).p() + sage: L = LazySymmetricFunctions(s) + sage: L in PrincipalIdealDomains + False + + Check that a basis which is not graded is not enough:: + + sage: ht = SymmetricFunctions(ZZ).ht() + sage: L = LazySymmetricFunctions(ht) + Traceback (most recent call last): + ... + ValueError: basis should be in GradedAlgebrasWithBasis + """ base_ring = basis.base_ring() + self._minimal_valuation = 0 if basis in Algebras.TensorProducts: self._arity = len(basis._sets) else: - if basis not in Algebras.Graded: - raise ValueError("basis should be a graded algebra") + if basis not in GradedAlgebrasWithBasis: + raise ValueError("basis should be in GradedAlgebrasWithBasis") self._arity = 1 category = Algebras(base_ring.category()) - if base_ring in Fields(): - category &= CompleteDiscreteValuationRings() - elif base_ring in IntegralDomains(): + if base_ring in IntegralDomains(): category &= IntegralDomains() elif base_ring in Rings().Commutative(): category = category.Commutative() @@ -1605,7 +2223,7 @@ def _monomial(self, c, n): L = self._laurent_poly_ring return L(c) - def _element_constructor_(self, x=None, valuation=None, degree=None, check=True): + def _element_constructor_(self, x=None, valuation=None, degree=None, constant=None, check=True): r""" Construct a lazy element in ``self`` from ``x``. @@ -1713,7 +2331,7 @@ def _element_constructor_(self, x=None, valuation=None, degree=None, check=True) d = f.degree() except (TypeError, ValueError, AttributeError): # FIXME: Fallback for symmetric functions in multiple variables - d = sum(p.size() for p in f.support()) + d = sum(sum(mu.size() for mu in p) for p in f.support()) p_dict[d] = p_dict.get(d, 0) + f v = min(p_dict) d = max(p_dict) @@ -1781,16 +2399,15 @@ def check_homogeneous_of_degree(f, d): constant=0, degree=degree) return self.element_class(self, coeff_stream) - coeff_ring = self._internal_poly_ring.base_ring() if check: def y(n): e = R(x(n)) check_homogeneous_of_degree(e, n) return e - coeff_stream = Stream_function(y, coeff_ring, self._sparse, valuation) + coeff_stream = Stream_function(y, self._sparse, valuation) else: - coeff_stream = Stream_function(x, coeff_ring, self._sparse, valuation) + coeff_stream = Stream_function(x, self._sparse, valuation) return self.element_class(self, coeff_stream) raise ValueError(f"unable to convert {x} into a lazy completion element") @@ -1803,12 +2420,54 @@ def _an_element_(self): sage: m = SymmetricFunctions(ZZ).m() sage: L = LazySymmetricFunctions(m) sage: L.an_element() - m[] + 2*m[] + 2*m[1] + 3*m[2] """ - R = self._laurent_poly_ring - coeff_stream = Stream_exact([R.one()], self._sparse, order=1, constant=0) - return self.element_class(self, coeff_stream) + return self(self._laurent_poly_ring.an_element()) + def some_elements(self): + """ + Return a list of elements of ``self``. + + EXAMPLES:: + + sage: m = SymmetricFunctions(GF(5)).m() + sage: L = LazySymmetricFunctions(m) + sage: L.some_elements()[:5] + [0, m[], 2*m[] + 2*m[1] + 3*m[2], 2*m[1] + 3*m[2], + 3*m[] + 2*m[1] + (m[1,1]+m[2]) + + (2*m[1,1,1]+m[3]) + + (2*m[1,1,1,1]+4*m[2,1,1]+2*m[2,2]) + + (3*m[2,1,1,1]+3*m[3,1,1]+4*m[3,2]+m[5]) + + (2*m[2,2,1,1]+m[2,2,2]+2*m[3,2,1]+2*m[3,3]+m[4,1,1]+3*m[4,2]+4*m[5,1]+4*m[6]) + + O^7] + + sage: NCSF = NonCommutativeSymmetricFunctions(QQ) + sage: S = NCSF.Complete() + sage: L = S.formal_series_ring() + sage: L.some_elements()[:4] + [0, S[], 2*S[] + 2*S[1] + (3*S[1,1]), 2*S[1] + (3*S[1,1])] + + """ + elt = self.an_element() + elts = [self.zero(), self.one(), elt] + # an element with no constant term + elts.append(elt - elt[0]) + # the inverse of an element + try: + if elt.is_unit(): + elts.append(~elt) + else: + elts.append(~(1 - elt[0] + elt)) + except NotImplementedError: + pass + # an element with no constant term and an invertible + # coefficient of the linear term + it = iter(self._laurent_poly_ring.basis()) + temp = self.sum(b for _ in range(4) if (b := next(it)).degree()) + if temp: + elts.append(temp) + + return elts ###################################################################### @@ -1838,7 +2497,7 @@ class LazySymmetricFunctions(LazyCompletionGradedAlgebra): ###################################################################### class LazyDirichletSeriesRing(LazySeriesRing): - """ + r""" The ring of lazy Dirichlet series. INPUT: @@ -1847,28 +2506,87 @@ class LazyDirichletSeriesRing(LazySeriesRing): - ``names`` -- name of the generator of this Dirichlet series ring - ``sparse`` -- (default: ``True``) whether this series is sparse or not + Unlike formal univariate Laurent/power series (over a field), + the ring of formal Dirichlet series is not a + :wikipedia:`discrete_valuation_ring`. On the other hand, it + is a :wikipedia:`local_ring`. The unique maximal ideal + consists of all non-invertible series, i.e., series with + vanishing constant term. + + .. TODO:: + + According to the answers in + https://mathoverflow.net/questions/5522/dirichlet-series-with-integer-coefficients-as-a-ufd, + (which, in particular, references :arxiv:`math/0105219`) + the ring of formal Dirichlet series is actually a + :wikipedia:`Unique_factorization_domain` over `\ZZ`. + + .. NOTE:: + + An interesting valuation is described in Emil Daniel + Schwab; Gheorghe Silberberg *A note on some discrete + valuation rings of arithmetical functions*, Archivum + Mathematicum, Vol. 36 (2000), No. 2, 103-109, + http://dml.cz/dmlcz/107723. Let `J_k` be the ideal of + Dirichlet series whose coefficient `f[n]` of `n^s` + vanishes if `n` has less than `k` prime factors, counting + multiplicities. For any Dirichlet series `f`, let `D(f)` + be the largest integer `k` such that `f` is in `J_k`. + Then `D` is surjective, `D(f g) = D(f) + D(g)` for + nonzero `f` and `g`, and `D(f + g) \geq \min(D(f), D(g))` + provided that `f + g` is nonzero. + + For example, `J_1` are series with no constant term, and + `J_2` are series such that `f[1]` and `f[p]` for prime + `p` vanish. + + Since this is a chain of increasing ideals, the ring of + formal Dirichlet series is not a + :wikipedia:`Noetherian_ring`. + + Evidently, this valuation cannot be computed for a given + series. + EXAMPLES:: sage: LazyDirichletSeriesRing(ZZ, 't') Lazy Dirichlet Series Ring in t over Integer Ring + + The ideal generated by `2^-s` and `3^-s` is not principal:: + + sage: L = LazyDirichletSeriesRing(QQ, 's') + sage: L in PrincipalIdealDomains + False """ Element = LazyDirichletSeries + # Follow the "generic" normalization + __classcall_private__ = LazySeriesRing.__classcall_private__ + def __init__(self, base_ring, names, sparse=True, category=None): - """ + r""" Initialize the ring. TESTS:: + sage: LazyDirichletSeriesRing.options.halting_precision(12) + sage: L = LazyDirichletSeriesRing(ZZ, 't') - sage: TestSuite(L).run(skip=['_test_elements', '_test_associativity', '_test_distributivity', '_test_zero']) + sage: TestSuite(L).run() + + sage: L = LazyDirichletSeriesRing(QQ, 't') + sage: TestSuite(L).run() + + sage: LazyDirichletSeriesRing.options._reset() # reset the options + """ if base_ring.characteristic() > 0: raise ValueError("positive characteristic not allowed for Dirichlet series") self._sparse = sparse - # TODO: it would be good to have something better than the symbolic ring - self._laurent_poly_ring = SR + self._minimal_valuation = 1 + self._arity = 1 + self._laurent_poly_ring = SR # TODO: it would be good to have something better than the symbolic ring self._internal_poly_ring = PolynomialRing(base_ring, names, sparse=True) category = Algebras(base_ring.category()) @@ -2051,6 +2769,36 @@ def _an_element_(self): c = self.base_ring().an_element() return self.element_class(self, Stream_exact([], self._sparse, constant=c, order=4)) + def some_elements(self): + """ + Return a list of elements of ``self``. + + EXAMPLES:: + + sage: L = LazyDirichletSeriesRing(ZZ, 'z') + sage: L.some_elements() + [0, 1, + 1/(4^z) + 1/(5^z) + 1/(6^z) + O(1/(7^z)), + 1/(2^z) - 1/(3^z) + 2/4^z - 2/5^z + 3/6^z - 3/7^z + 4/8^z - 4/9^z, + 1/(2^z) - 1/(3^z) + 2/4^z - 2/5^z + 3/6^z - 3/7^z + 4/8^z - 4/9^z + 1/(10^z) + 1/(11^z) + 1/(12^z) + O(1/(13^z)), + 1 + 4/2^z + 9/3^z + 16/4^z + 25/5^z + 36/6^z + 49/7^z + O(1/(8^z))] + + sage: L = LazyDirichletSeriesRing(QQ, 'z') + sage: L.some_elements() + [0, 1, + 1/2/4^z + 1/2/5^z + 1/2/6^z + O(1/(7^z)), + 1/2 - 1/2/2^z + 2/3^z - 2/4^z + 1/(6^z) - 1/(7^z) + 42/8^z + 2/3/9^z, + 1/2 - 1/2/2^z + 2/3^z - 2/4^z + 1/(6^z) - 1/(7^z) + 42/8^z + 2/3/9^z + 1/2/10^z + 1/2/11^z + 1/2/12^z + O(1/(13^z)), + 1 + 4/2^z + 9/3^z + 16/4^z + 25/5^z + 36/6^z + 49/7^z + O(1/(8^z))] + """ + R = self.base_ring() + some_numbers = [c for c, _ in zip(R.some_elements(), range(9))] + elts = [self.zero(), self.one(), self.an_element(), + self(some_numbers), + self(some_numbers, constant=R.an_element()), + self(lambda n: n**2)] + return elts + def _monomial(self, c, n): r""" Return the interpretation of the coefficient ``c`` at index ``n``. @@ -2067,3 +2815,27 @@ def _monomial(self, c, n): except (ValueError, TypeError): return '({})/{}^{}'.format(self.base_ring()(c), n, self.variable_name()) +def _skip_leading_zeros(iterator): + """ + Return an iterator which discards all leading zeros. + + EXAMPLES:: + + sage: from sage.rings.lazy_series_ring import _skip_leading_zeros + sage: it = map(lambda x: 0 if x < 10 else x, NN) + sage: [x for x, _ in zip(_skip_leading_zeros(it), range(10))] + [10, 11, 12, 13, 14, 15, 16, 17, 18, 19] + + sage: it = map(GF(3), NN) + sage: [x for x, _ in zip(it, range(10))] + [0, 1, 2, 0, 1, 2, 0, 1, 2, 0] + sage: it = map(GF(3), NN) + sage: [x for x, _ in zip(_skip_leading_zeros(it), range(10))] + [1, 2, 0, 1, 2, 0, 1, 2, 0, 1] + """ + while True: + c = next(iterator) + if c: + yield c + break + yield from iterator diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 5a38cb794b6..a2f0e3d047c 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() @@ -6283,7 +6288,7 @@ def _normalize_prime_list(self, v): v = [] elif not isinstance(v, (list, tuple)): v = [v] - + v = [ZZ(p).abs() for p in v] v = sorted(set(v)) @@ -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_element.pyx b/src/sage/rings/number_field/number_field_element.pyx index 784c239dc10..b78bc33078c 100644 --- a/src/sage/rings/number_field/number_field_element.pyx +++ b/src/sage/rings/number_field/number_field_element.pyx @@ -493,7 +493,7 @@ cdef class NumberFieldElement(FieldElement): return codomain(f(im_gens[0])) def _latex_(self): - """ + r""" Returns the latex representation for this element. EXAMPLES:: @@ -3988,8 +3988,8 @@ cdef class NumberFieldElement(FieldElement): return ht def global_height_non_arch(self, prec=None): - """ - Returns the total non-archimedean component of the height of self. + r""" + Return the total non-archimedean component of the height of ``self``. INPUT: diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pyx b/src/sage/rings/number_field/number_field_element_quadratic.pyx index 24fc7db909e..04224f2f208 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -4,7 +4,7 @@ # distutils: library_dirs = NTL_LIBDIR # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -""" +r""" Optimized Quadratic Number Field Elements This file defines a Cython class ``NumberFieldElement_quadratic`` to speed up @@ -23,16 +23,15 @@ AUTHORS: The ``_new()`` method should be overridden in this class to copy the ``D`` and ``standard_embedding`` attributes """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 Robert Bradshaw # # 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/ +# **************************************************************************** include "sage/libs/ntl/decl.pxi" from cpython.object cimport Py_EQ, Py_NE, Py_LE, Py_GE, Py_LT, Py_GT @@ -1634,7 +1633,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): ################################################################################# def __hash__(self): - """ + r""" Return hash of this number field element. For elements in `\ZZ` or `\QQ` the hash coincides with the one in the @@ -2019,10 +2018,11 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): mpq_canonicalize(res.value) return res - def norm(self, K=None): - """ - Return the norm of self. If the second argument is None, this is the + r""" + Return the norm of ``self``. + + If the second argument is ``None``, this is the norm down to `\QQ`. Otherwise, return the norm down to K (which had better be either `\QQ` or this number field). diff --git a/src/sage/rings/number_field/number_field_morphisms.pyx b/src/sage/rings/number_field/number_field_morphisms.pyx index 7216384a23b..62ced44997d 100644 --- a/src/sage/rings/number_field/number_field_morphisms.pyx +++ b/src/sage/rings/number_field/number_field_morphisms.pyx @@ -4,8 +4,7 @@ Embeddings into ambient fields This module provides classes to handle embeddings of number fields into ambient fields (generally `\RR` or `\CC`). """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Robert Bradshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -17,8 +16,8 @@ fields (generally `\RR` or `\CC`). # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import sage.rings.complex_double @@ -345,7 +344,7 @@ cpdef matching_root(poly, target, ambient_field=None, margin=1, max_prec=None): target best approximates as compared in ambient_field. If the parent of target is exact, the equality is required, otherwise - find closest root (with respect to the \code{abs} function) in the + find closest root (with respect to the ``abs`` function) in the ambient field to the target, and return the root of poly (if any) that approximates it best. @@ -405,7 +404,7 @@ cpdef matching_root(poly, target, ambient_field=None, margin=1, max_prec=None): cpdef closest(target, values, margin=1): """ This is a utility function that returns the item in values closest to - target (with respect to the \code{abs} function). If margin is greater + target (with respect to the ``abs`` function). If margin is greater than 1, and x and y are the first and second closest elements to target, then only return x if x is margin times closer to target than y, i.e. margin * abs(target-x) < abs(target-y). 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/number_field/splitting_field.py b/src/sage/rings/number_field/splitting_field.py index 6dc15cc6bc9..d61b9f25226 100644 --- a/src/sage/rings/number_field/splitting_field.py +++ b/src/sage/rings/number_field/splitting_field.py @@ -378,7 +378,7 @@ def splitting_field(poly, name, map=False, degree_multiple=None, abort_degree=No abort_rel_degree = abort_degree//absolute_degree if abort_rel_degree and rel_degree_divisor > abort_rel_degree: raise SplittingFieldAbort(absolute_degree * rel_degree_divisor, degree_multiple) - + # First, factor polynomials in Lred and store the result in L verbose("SplittingData to factor: %s"%[s._repr_tuple() for s in Lred]) t = cputime() diff --git a/src/sage/rings/padics/padic_capped_absolute_element.pyx b/src/sage/rings/padics/padic_capped_absolute_element.pyx index b8f7598251f..91e973ccf7e 100644 --- a/src/sage/rings/padics/padic_capped_absolute_element.pyx +++ b/src/sage/rings/padics/padic_capped_absolute_element.pyx @@ -9,8 +9,7 @@ AUTHORS: - Genya Zaytman: documentation - David Harvey: doctests """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007-2013 David Roe # William Stein # @@ -18,9 +17,8 @@ AUTHORS: # 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/ +# **************************************************************************** include "sage/libs/linkages/padics/mpz.pxi" include "CA_template.pxi" @@ -89,6 +87,8 @@ cdef class pAdicCappedAbsoluteElement(CAElement): """ def lift(self): """ + EXAMPLES:: + sage: R = ZpCA(3) sage: R(10).lift() 10 diff --git a/src/sage/rings/padics/relaxed_template.pxi b/src/sage/rings/padics/relaxed_template.pxi index f87034e56e3..4de2b197ad1 100644 --- a/src/sage/rings/padics/relaxed_template.pxi +++ b/src/sage/rings/padics/relaxed_template.pxi @@ -702,7 +702,7 @@ cdef class RelaxedElement(pAdicGenericElement): use the default halting precision of the parent - ``secure`` -- a boolean (default: ``False`` if ``prec`` is given, - ``True`` otherwise); when the elements cannot be distingiushed + ``True`` otherwise); when the elements cannot be distinguished at the given precision, raise an error if ``secure`` is ``True``, return ``True`` otherwise. diff --git a/src/sage/rings/polynomial/all.py b/src/sage/rings/polynomial/all.py index a05a36ebca1..816db5efe2a 100644 --- a/src/sage/rings/polynomial/all.py +++ b/src/sage/rings/polynomial/all.py @@ -22,7 +22,7 @@ # Quotient of polynomial ring from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing from sage.rings.polynomial.polynomial_quotient_ring_element import PolynomialQuotientRingElement - + # Univariate Polynomial Rings from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import polygen, polygens 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/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index c82cf65eb0f..5e4188ed80f 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -294,10 +294,11 @@ cdef class LaurentPolynomial(CommutativeAlgebraElement): R = R.change_ring(new_base_ring) elif isinstance(f, Map): R = R.change_ring(f.codomain()) - return R(dict([(k,f(v)) for (k,v) in self.dict().items()])) + return R(dict([(k, f(v)) for (k, v) in self.dict().items()])) + cdef class LaurentPolynomial_univariate(LaurentPolynomial): - """ + r""" A univariate Laurent polynomial in the form of `t^n \cdot f` where `f` is a polynomial in `t`. @@ -1118,12 +1119,27 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): x^3 + 3*x^4 + 3*x^5 + 10*x^6 + 18*x^7 + 9*x^8 + 27*x^9 + 27*x^10 + 27*x^12 sage: g^4 x^-40 - 4*x^-29 + 6*x^-18 - 4*x^-7 + x^4 + + sage: R. = LaurentPolynomialRing(Zmod(6)) + sage: x^-2 + x^-2 + sage: (5*x^2)^-4 + x^-8 + sage: (5*x^-4)^-3 + 5*x^12 """ cdef LaurentPolynomial_univariate self = _self cdef long right = r if right != r: raise ValueError("exponent must be an integer") - return self._parent.element_class(self._parent, self.__u**right, self.__n*right) + try: + return self._parent.element_class(self._parent, self.__u**right, self.__n*right) + except TypeError as err: + # we need to handle the special case of negative powers and a unit + if not self.__u.is_constant() or not self.__u.leading_coefficient().is_unit(): + raise + c = self._parent._R(self.__u.leading_coefficient() ** right) + return self._parent.element_class(self._parent, c, self.__n*right) cpdef _floordiv_(self, rhs): """ diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 24d8f05546b..f205371d822 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -112,7 +112,7 @@ def set_hint(self, hint): Ideal (x + 3*y) of Multivariate Polynomial Ring in x, y, z over Rational Field """ self._hint = hint - + def hint(self): """ Return the hint of this ideal. @@ -130,7 +130,7 @@ def hint(self): Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field """ return self._hint - + # Comparisons, using the associated polynomial ideal. def _richcmp_(self, right_r, op): r""" @@ -192,9 +192,9 @@ def __contains__(self, f): f = self.ring()(f) g = f.__reduce__()[1][0] return (g in self.polynomial_ideal()) - + # Operations on ideals - + def change_ring(self, R, hint=None): """ Coerce an ideal into a new ring. @@ -313,7 +313,7 @@ def toric_coordinate_change(self, M, forward_hint=True): apply_to_hint = None return self.apply_map(lambda x, M=M: x.toric_coordinate_change(M), apply_to_hint=apply_to_hint) - + def __add__(self, other): """ Return the sum of two ideals in the same ring. @@ -361,7 +361,7 @@ def normalize_gens(self): Ideal (x - 1, y + 1) of Multivariate Laurent Polynomial Ring in x, y over Rational Field """ return self.ring().ideal(self.groebner_basis(), hint=self._hint) - + # Structural queries and properties def polynomial_ideal(self, saturate=True): @@ -406,7 +406,7 @@ def polynomial_ideal(self, saturate=True): self._hint = I self._saturated = True return I - + def groebner_basis(self, saturate=True): """ Return the reduced Groebner basis for the specified term order. @@ -456,7 +456,7 @@ def is_binomial(self, groebner_basis=False): else: l = self.gens() return all(not f or f.number_of_terms() == 2 for f in l) - + def associated_primes(self): """ Return associated primes of this ideal. 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.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index ce14319f63a..1a80a2cbb1f 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -196,12 +196,12 @@ cdef class MPolynomial(CommutativeRingElement): var = R.variable_name() if var in self._parent.variable_names(): return R(self.polynomial(self._parent(var))) - else: - return R([self]) + return R([self]) def coefficients(self): - """ + r""" Return the nonzero coefficients of this polynomial in a list. + The returned list is decreasingly ordered by the term ordering of ``self.parent()``, i.e. the list of coefficients matches the list of monomials returned by @@ -1315,11 +1315,12 @@ cdef class MPolynomial(CommutativeRingElement): return R(dict([(k,f(v)) for (k,v) in self.dict().items()])) def _norm_over_nonprime_finite_field(self): - """ + r""" Given a multivariate polynomial over a nonprime finite field - `\GF{p**e}`, compute the norm of the polynomial down to `\GF{p}`, which - is the product of the conjugates by the Frobenius action on - coefficients, where Frobenius acts by p-th power. + `\GF{p^e}`, compute the norm of the polynomial down to `\GF{p}`. + + This is the product of the conjugates by the Frobenius action + on coefficients, where Frobenius acts by p-th power. This is (currently) an internal function used in factoring over finite fields. diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index 4e1937a4645..8202930a1de 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. """ @@ -2815,37 +2816,41 @@ def hilbert_polynomial(self, algorithm='sage'): sage: I = Ideal([x^3*y^2 + 3*x^2*y^2*z + y^3*z^2 + z^5]) sage: I.hilbert_polynomial() 5*t - 5 + + Check for :trac:`33597`:: + + sage: R. = QQ[] + sage: I = R.ideal([X^2*Y^3, X*Z]) + sage: I.hilbert_polynomial() + t + 5 """ if not self.is_homogeneous(): raise TypeError("ideal must be homogeneous") - if algorithm == 'sage': from sage.misc.misc_c import prod hilbert_poincare = self.hilbert_series() - denom = hilbert_poincare.denominator().factor() - second_hilbert = hilbert_poincare.numerator() - t = second_hilbert.parent().gen() - if denom: - s = denom[0][1] # this is the pole order of the Hilbert-Poincaré series at t=1 - else: - return t.parent().zero() - # we assume the denominator of the Hilbert series is of the form (1-t)^s, scale if needed - if hilbert_poincare.denominator().leading_coefficient() == 1: - second_hilbert = second_hilbert*(-1)**s - denom = ZZ(s-1).factorial() - out = sum(c / denom * prod(s - 1 - n - nu + t for nu in range(s-1)) - for n,c in enumerate(second_hilbert)) + t.parent().zero() - return out - elif algorithm == 'singular': + denom = hilbert_poincare.denominator() + if denom.degree() == 0: + return denom.parent().zero() + t = denom.parent().gen() + s = denom.valuation(t - 1) + numerator = hilbert_poincare.numerator() + # we assume the denominator of the Hilbert series is of + # the form (1 - t)^s, need to scale numerator + scalar = ~(denom[0] * (s - 1).factorial()) + st = s - 1 + t + out = scalar * sum(c * prod(st - n - nu for nu in range(s - 1)) + for n, c in enumerate(numerator)) + return t.parent().zero() + out + if algorithm == 'singular': from sage.libs.singular.function_factory import ff hilbPoly = ff.polylib__lib.hilbPoly hp = hilbPoly(self) t = ZZ['t'].gen() - fp = ZZ(len(hp)-1).factorial() - return sum(ZZ(coeff) * t**i for i,coeff in enumerate(hp)) / fp - else: - raise ValueError("'algorithm' must be 'sage' or 'singular'") + fp = ZZ(len(hp) - 1).factorial() + return sum(ZZ(coeff) * t**i for i, coeff in enumerate(hp)) / fp + raise ValueError("'algorithm' must be 'sage' or 'singular'") @require_field @handle_AA_and_QQbar @@ -4089,7 +4094,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 +4220,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 +5462,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/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 2109c516a1c..4dad016b33f 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -1984,7 +1984,6 @@ cdef class MPolynomial_libsingular(MPolynomial): sage: R. = QQ[] sage: x._new_constant_poly(2/1,R) 2 - """ if not x: return new_MP(P, NULL) @@ -1993,7 +1992,7 @@ cdef class MPolynomial_libsingular(MPolynomial): return new_MP(P, _p) def __call__(self, *x, **kwds): - """ + r""" Evaluate this multi-variate polynomial at ``x``, where ``x`` is either the tuple of values to substitute in, or one can use functional notation ``f(a_0,a_1,a_2, \ldots)`` to evaluate @@ -2261,7 +2260,7 @@ cdef class MPolynomial_libsingular(MPolynomial): return new_MP((left)._parent,_p) cpdef _div_(left, right_ringelement): - """ + r""" Divide left by right EXAMPLES:: @@ -4576,7 +4575,7 @@ cdef class MPolynomial_libsingular(MPolynomial): return Sequence(l, check=False, immutable=True) def reduce(self,I): - """ + r""" Return a remainder of this polynomial modulo the polynomials in ``I``. @@ -5288,15 +5287,14 @@ cdef class MPolynomial_libsingular(MPolynomial): return new_MP(self._parent,p) def integral(self, MPolynomial_libsingular var): - """ - Integrates this polynomial with respect to the provided - variable. + r""" + Integrate this polynomial with respect to the provided variable. One requires that `\QQ` is contained in the ring. INPUT: - - ``variable`` - the integral is taken with respect to variable + - ``variable`` -- the integral is taken with respect to variable EXAMPLES:: diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index 02eeb51bacf..bdd40bfdda2 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -1184,6 +1184,27 @@ cdef class MPolynomialRing_base(sage.rings.ring.CommutativeRing): """ return self({exponents: self.base_ring().one()}) + def monomials_of_degree(self, degree): + r""" + Return a list of all monomials of the given total degree in this + multivariate polynomial ring. + + EXAMPLES:: + + sage: R. = ZZ[] + sage: mons = R.monomials_of_degree(2) + sage: mons + [x^2, x*y, x*z, y^2, y*z, z^2] + + The number of such monomials equals `\binom{n+k-1}{k}` + where `n` is the number of variables and `k` the degree:: + + sage: len(mons) == binomial(3+2-1,2) + True + """ + from sage.combinat.integer_vector import IntegerVectors + return [self.monomial(*a) for a in IntegerVectors(degree, self.ngens())] + def _macaulay_resultant_getS(self, mon_deg_tuple, dlist): r""" In the Macaulay resultant algorithm the list of all monomials of the total degree is partitioned into sets `S_i`. diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pyx b/src/sage/rings/polynomial/ore_polynomial_element.pyx index d1492a35946..858ec02cbfa 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pyx +++ b/src/sage/rings/polynomial/ore_polynomial_element.pyx @@ -1705,11 +1705,11 @@ cdef class OrePolynomial(AlgebraElement): var = "|%s"%name else: var = "" - s += "%s %s"%(x,var) + s += "%s %s" % (x, var) s = s.replace(" + -", " - ") - s = re.sub(" 1(\.0+)? \|"," ", s) - s = re.sub(" -1(\.0+)? \|", " -", s) - s = s.replace("|","") + s = re.sub(r" 1(\.0+)? \|", " ", s) + s = re.sub(r" -1(\.0+)? \|", " -", s) + s = s.replace("|", "") if s == " ": return "0" return s[1:].lstrip().rstrip() 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/plural.pyx b/src/sage/rings/polynomial/plural.pyx index 92e70f25343..9a996550975 100644 --- a/src/sage/rings/polynomial/plural.pyx +++ b/src/sage/rings/polynomial/plural.pyx @@ -250,10 +250,9 @@ cdef class NCPolynomialRing_plural(Ring): sage: H. = A.g_algebra({z*x:x*z+2*x, z*y:y*z-2*y}) sage: x*y == y*x True - """ def __init__(self, base_ring, names, c, d, order, category, check=True): - """ + r""" Construct a noncommutative polynomial G-algebra subject to the following conditions: INPUT: diff --git a/src/sage/rings/polynomial/polynomial_complex_arb.pyx b/src/sage/rings/polynomial/polynomial_complex_arb.pyx index ed4617dd951..5fc4ff1f6af 100644 --- a/src/sage/rings/polynomial/polynomial_complex_arb.pyx +++ b/src/sage/rings/polynomial/polynomial_complex_arb.pyx @@ -717,6 +717,44 @@ cdef class Polynomial_complex_arb(Polynomial): sig_off() return res + def _lgamma_series(self, long n): + r""" + Return the series expansion of the log-gamma function composed + with this polynomial, truncated before degree ``n``. + + EXAMPLES:: + + sage: Pol. = CBF[] + sage: (1000 + x)._lgamma_series(3) + ([0.00050025008333331...])*x^2 + ([6.9072551956488...])*x + [5905.2204232091...] + """ + cdef Polynomial_complex_arb res = self._new() + if n < 0: + n = 0 + sig_on() + acb_poly_lgamma_series(res.__poly, self.__poly, n, prec(self)) + sig_off() + return res + + def _rgamma_series(self, long n): + r""" + Return the series expansion of the reciprocal gamma function composed + with this polynomial, truncated before degree ``n``. + + EXAMPLES:: + + sage: Pol. = CBF[] + sage: (-1 + x)._rgamma_series(4) + ([1.23309373642178...])*x^3 + ([0.422784335098467...])*x^2 - x + """ + cdef Polynomial_complex_arb res = self._new() + if n < 0: + n = 0 + sig_on() + acb_poly_rgamma_series(res.__poly, self.__poly, n, prec(self)) + sig_off() + return res + def _lambert_w_series(self, long n, branch=0): r""" Return the series expansion of the specified branch of the Lambert W diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 7f781c65060..cea15d34764 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) """ # **************************************************************************** @@ -2744,9 +2749,9 @@ cdef class Polynomial(CommutativeAlgebraElement): var = "" s += "%s %s" % (x, var) s = s.replace(" + -", " - ") - s = re.sub(" 1(\.0+)? \|"," ", s) - s = re.sub(" -1(\.0+)? \|", " -", s) - s = s.replace("|","") + s = re.sub(r" 1(\.0+)? \|", " ", s) + s = re.sub(r" -1(\.0+)? \|", " -", s) + s = s.replace("|", "") if s == " ": return "0" return s[1:].lstrip().rstrip() @@ -2845,7 +2850,7 @@ cdef class Polynomial(CommutativeAlgebraElement): raise IndexError("polynomials are immutable") cpdef _floordiv_(self, right): - """ + r""" Quotient of division of self by other. This is denoted //. If self = quotient \* right + remainder, this function returns @@ -4954,9 +4959,10 @@ cdef class Polynomial(CommutativeAlgebraElement): return ~(q.leading_coefficient())*q # make monic (~ is inverse in python) def is_primitive(self, n=None, n_prime_divs=None): - """ - Return ``True`` if the polynomial is primitive. The semantics of - "primitive" depend on the polynomial coefficients. + r""" + Return ``True`` if the polynomial is primitive. + + The semantics of "primitive" depend on the polynomial coefficients. - (field theory) A polynomial of degree `m` over a finite field `\GF{q}` is primitive if it is irreducible and its root in @@ -11336,7 +11342,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 +11642,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_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index 38586320dcc..868a5f691f9 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -36,7 +36,7 @@ from sage.libs.pari.all import pari_gen from sage.structure.richcmp import richcmp, richcmp_item, rich_to_bool, rich_to_bool_sgn -from sage.structure.element import coerce_binop +from sage.structure.element import coerce_binop, parent from sage.rings.infinity import infinity, Infinity from sage.rings.integer_ring import ZZ @@ -543,6 +543,29 @@ def degree(self, gen=None): return -1 return max(self.__coeffs) + def __floordiv__(self, right): + """ + Return the quotient upon division (no remainder). + + EXAMPLES:: + + sage: R. = PolynomialRing(QQbar, sparse=True) + sage: f = (1+2*x)^3 + 3*x; f + 8*x^3 + 12*x^2 + 9*x + 1 + sage: g = f // (1+2*x); g + 4*x^2 + 4*x + 5/2 + sage: f - g * (1+2*x) + -3/2 + sage: f.quo_rem(1+2*x) + (4*x^2 + 4*x + 5/2, -3/2) + + """ + P = self.parent() + if P is parent(right): + return self._floordiv_(right) + d = P.base_ring()(right) + return self.map_coefficients(lambda c: c // d) + def _add_(self, right): r""" EXAMPLES:: diff --git a/src/sage/rings/polynomial/polynomial_gf2x.pyx b/src/sage/rings/polynomial/polynomial_gf2x.pyx index 3c90a42e033..284e319be99 100644 --- a/src/sage/rings/polynomial/polynomial_gf2x.pyx +++ b/src/sage/rings/polynomial/polynomial_gf2x.pyx @@ -100,14 +100,14 @@ cdef class Polynomial_GF2X(Polynomial_template): sage: pari(f) Mod(1, 2)*x^3 + Mod(1, 2)*x^2 + Mod(1, 2) """ - #TODO: put this in a superclass + # TODO: put this in a superclass parent = self._parent if variable is None: variable = parent.variable_name() return pari(self.list()).Polrev(variable) * pari(1).Mod(2) def modular_composition(Polynomial_GF2X self, Polynomial_GF2X g, Polynomial_GF2X h, algorithm=None): - """ + r""" Compute `f(g) \pmod h`. Both implementations use Brent-Kung's Algorithm 2.1 (*Fast Algorithms diff --git a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx index 38a8324fde1..bde23684615 100644 --- a/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_integer_dense_flint.pyx @@ -4,7 +4,7 @@ # distutils: library_dirs = NTL_LIBDIR # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -""" +r""" Dense univariate polynomials over `\ZZ`, implemented using FLINT AUTHORS: @@ -1394,7 +1394,7 @@ cdef class Polynomial_integer_dense_flint(Polynomial): return smallInteger(fmpz_poly_degree(self.__poly)) def pseudo_divrem(self, B): - """ + r""" Write ``A = self``. This function computes polynomials `Q` and `R` and an integer `d` such that diff --git a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx index 643ef81027a..2b55a681a32 100644 --- a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx @@ -4,7 +4,7 @@ # distutils: library_dirs = NTL_LIBDIR # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -""" +r""" Dense univariate polynomials over `\ZZ/n\ZZ`, implemented using NTL This implementation is generally slower than the FLINT implementation in @@ -22,16 +22,15 @@ AUTHORS: - Robert Bradshaw: Split off from polynomial_element_generic.py (2007-09) - Robert Bradshaw: Major rewrite to use NTL directly (2007-09) """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 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 cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_on, sig_off diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index 93e4a741925..4f018a42937 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -256,7 +256,7 @@ def is_PolynomialQuotientRing(x): return isinstance(x, PolynomialQuotientRing_generic) -class PolynomialQuotientRing_generic(CommutativeRing): +class PolynomialQuotientRing_generic(QuotientRing_generic): """ Quotient of a univariate polynomial ring by an ideal. @@ -418,7 +418,9 @@ def __init__(self, ring, polynomial, name=None, category=None): # Note that is_finite() is cheap so it does not seem to do a lazy # _refine_category_() in is_finite() as we do for is_field() category = category.Finite() - CommutativeRing.__init__(self, ring, names=name, category=category) + + QuotientRing_generic.__init__(self, ring, ring.ideal(polynomial), names=name, category=category) + self._base = ring # backwards compatibility -- different from QuotientRing_generic _ideal_class_ = QuotientRing_generic._ideal_class_ @@ -780,11 +782,11 @@ def construction(self): -- Simon King (2010-05) """ from sage.categories.pushout import QuotientFunctor - Cover = self.base() + Cover = self.__ring + kwds = {} if Cover in CommutativeRings(): - return QuotientFunctor([self.modulus()]*Cover, self.variable_names(), - domain=CommutativeRings(), codomain=CommutativeRings()), Cover - return QuotientFunctor([self.modulus()]*self.base(), self.variable_names()), Cover + kwds['domain'] = kwds['codomain'] = CommutativeRings() + return QuotientFunctor([self.modulus()]*Cover, self.variable_names(), **kwds), Cover @cached_method def base_ring(self): 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/polynomial_zmod_flint.pyx b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx index 001ace2194c..fd92a626555 100644 --- a/src/sage/rings/polynomial/polynomial_zmod_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_zmod_flint.pyx @@ -4,7 +4,7 @@ # distutils: library_dirs = NTL_LIBDIR # distutils: extra_link_args = NTL_LIBEXTRA # distutils: language = c++ -""" +r""" Dense univariate polynomials over `\ZZ/n\ZZ`, implemented using FLINT This module gives a fast implementation of `(\ZZ/n\ZZ)[x]` whenever `n` is at diff --git a/src/sage/rings/polynomial/real_roots.pyx b/src/sage/rings/polynomial/real_roots.pyx index 1315d68c4a9..b939908ef92 100644 --- a/src/sage/rings/polynomial/real_roots.pyx +++ b/src/sage/rings/polynomial/real_roots.pyx @@ -1258,8 +1258,9 @@ def de_casteljau_intvec(Vector_integer_dense c, int c_bitsize, Rational x, int u # double-rounding on x86 PCs. cdef double half_ulp = ldexp(1.0 * 65/64, -54) + def intvec_to_doublevec(Vector_integer_dense b, long err): - """ + r""" Given a vector of integers A = [a1, ..., an], and an integer error bound E, returns a vector of floating-point numbers B = [b1, ..., bn], lower and upper error bounds F1 and F2, and @@ -2139,19 +2140,22 @@ cdef int subsample_vec(int a, int slen, int llen): sage: [subsample_vec_doctest(a, 3, 4) for a in range(3)] [1, 2, 3] """ - # round((a + 0.5) * (llen - 1) / slen) # round((2*a + 1) * (llen - 1) / (2 * slen) # floor(((2*a + 1) * (llen - 1) + slen) / (2 * slen)) return ((2*a + 1) * (llen - 1) + slen) // (2 * slen) + def subsample_vec_doctest(a, slen, llen): return subsample_vec(a, slen, llen) + def maximum_root_first_lambda(p): - """ + r""" Given a polynomial with real coefficients, computes an upper bound - on its largest real root, using the first-\lambda algorithm from + on its largest real root. + + This is using the first-\lambda algorithm from "Implementations of a New Theorem for Computing Bounds for Positive Roots of Polynomials", by Akritas, Strzebo\'nski, and Vigklas. diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx index 220c9b87c1d..289784b94b3 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx @@ -822,10 +822,9 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): factors.reverse() return Factorization(factors, sort=False, unit=unit) - cdef _factor_uniform_c(self): r""" - Compute a uniformly distrbuted factorization of ``self``. + Compute a uniformly distributed factorization of ``self``. This is the low level implementation of :meth:`factor`. """ 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/polynomial/symmetric_reduction.pyx b/src/sage/rings/polynomial/symmetric_reduction.pyx index c8c08e1c61f..25213e1318a 100644 --- a/src/sage/rings/polynomial/symmetric_reduction.pyx +++ b/src/sage/rings/polynomial/symmetric_reduction.pyx @@ -1,4 +1,4 @@ -""" +r""" Symmetric Reduction of Infinite Polynomials :class:`~sage.rings.polynomial.symmetric_reduction.SymmetricReductionStrategy` @@ -102,7 +102,7 @@ Symmetric Reduction Strategy is created:: """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Simon King # # Distributed under the terms of the GNU General Public License (GPL) @@ -114,9 +114,8 @@ Symmetric Reduction Strategy is created:: # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** - +# https://www.gnu.org/licenses/ +# **************************************************************************** import copy import operator import sys diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 7b7c957fdf4..e0aeed19815 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -4059,7 +4059,7 @@ def __bool__(self): self.exactify() return bool(self) - + def is_square(self): """ diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index cae440d543d..ea096e68343 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -956,9 +956,8 @@ def ideal(self, *gens, **kwds): """ if len(gens) == 1: gens = gens[0] - from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular - if not isinstance(self.__R, MPolynomialRing_libsingular) and \ - (not hasattr(self.__R, '_has_singular') or not self.__R._has_singular): + from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base + if not (isinstance(self.__R, MPolynomialRing_base) and self.__R._has_singular): # pass through return super().ideal(gens, **kwds) if is_SingularElement(gens): @@ -1224,7 +1223,8 @@ def _singular_(self, singular=singular_default): Q._check_valid() return Q except (AttributeError, ValueError): - return self._singular_init_(singular) + self.__singular = self._singular_init_(singular) + return self.__singular def _singular_init_(self, singular=None): """ diff --git a/src/sage/rings/quotient_ring_element.py b/src/sage/rings/quotient_ring_element.py index 69df8d3319e..e2f190a4b1c 100644 --- a/src/sage/rings/quotient_ring_element.py +++ b/src/sage/rings/quotient_ring_element.py @@ -153,7 +153,7 @@ def __bool__(self): """ return self.__rep not in self.parent().defining_ideal() - + def is_unit(self): """ diff --git a/src/sage/rings/real_arb.pyx b/src/sage/rings/real_arb.pyx index 4fc1de6cce8..23a41c2bf6a 100644 --- a/src/sage/rings/real_arb.pyx +++ b/src/sage/rings/real_arb.pyx @@ -238,7 +238,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.cpython.string cimport char_to_str, str_to_bytes cdef void mpfi_to_arb(arb_t target, const mpfi_t source, const long precision): - """ + r""" Convert an MPFI interval to an Arb ball. INPUT: @@ -282,7 +282,7 @@ cdef void mpfi_to_arb(arb_t target, const mpfi_t source, const long precision): mpfr_clear(right) cdef int arb_to_mpfi(mpfi_t target, arb_t source, const long precision) except -1: - """ + r""" Convert an Arb ball to an MPFI interval. INPUT: @@ -798,7 +798,7 @@ class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): # Ball functions of non-ball arguments def sinpi(self, x): - """ + r""" Return a ball enclosing `\sin(\pi x)`. This works even if ``x`` itself is not a ball, and may be faster or @@ -844,7 +844,7 @@ class RealBallField(UniqueRepresentation, sage.rings.abc.RealBallField): return res def cospi(self, x): - """ + r""" Return a ball enclosing `\cos(\pi x)`. This works even if ``x`` itself is not a ball, and may be faster or @@ -2986,7 +2986,7 @@ cdef class RealBall(RingElement): return res def sqrt1pm1(self): - """ + r""" Return `\sqrt{1+\mathrm{self}}-1`, computed accurately when ``self`` is close to zero. @@ -3728,7 +3728,7 @@ cdef class RealBall(RingElement): return res def gamma(self, a=None): - """ + r""" Image of this ball by the (upper incomplete) Euler Gamma function For `a` real, return the upper incomplete Gamma function @@ -3770,7 +3770,7 @@ cdef class RealBall(RingElement): gamma_inc = gamma def gamma_inc_lower(self, a): - """ + r""" Image of this ball by the lower incomplete Euler Gamma function For `a` real, return the lower incomplete Gamma function @@ -3828,7 +3828,7 @@ cdef class RealBall(RingElement): return res def rising_factorial(self, n): - """ + r""" Return the ``n``-th rising factorial of this ball. The `n`-th rising factorial of `x` is equal to `x (x+1) \cdots (x+n-1)`. @@ -3934,7 +3934,7 @@ cdef class RealBall(RingElement): return res def polylog(self, s): - """ + r""" Return the polylogarithm `\operatorname{Li}_s(\mathrm{self})`. EXAMPLES:: 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/rings/universal_cyclotomic_field.py b/src/sage/rings/universal_cyclotomic_field.py index 2291f0ed393..d238bce3450 100644 --- a/src/sage/rings/universal_cyclotomic_field.py +++ b/src/sage/rings/universal_cyclotomic_field.py @@ -332,7 +332,7 @@ def __bool__(self): """ return bool(self._obj) - + def __reduce__(self): r""" diff --git a/src/sage/sandpiles/examples.py b/src/sage/sandpiles/examples.py index b34129f3ed8..9ccc08d314f 100644 --- a/src/sage/sandpiles/examples.py +++ b/src/sage/sandpiles/examples.py @@ -11,7 +11,7 @@ The examples are accessible by typing ``sandpiles.NAME``, where ``NAME`` is the name of the example. You can get a list by typing -``sandpiles.`` and hitting the TAB key:: +``sandpiles.`` and hitting the :kbd:`Tab` key:: sandpiles.Complete sandpiles.Cycle 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/affine/affine_homset.py b/src/sage/schemes/affine/affine_homset.py index b9260996204..98b3b3a8994 100644 --- a/src/sage/schemes/affine/affine_homset.py +++ b/src/sage/schemes/affine/affine_homset.py @@ -23,15 +23,16 @@ - Ben Hutz (2018): add numerical point support """ - -#***************************************************************************** -# Copyright (C) 2006 William Stein +# ***************************************************************************** +# Copyright (C) 2006 William Stein # -# 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/ -#***************************************************************************** +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# ***************************************************************************** + +from copy import copy from sage.misc.verbose import verbose from sage.rings.integer_ring import ZZ @@ -42,13 +43,13 @@ from sage.categories.number_fields import NumberFields from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -import sage.schemes.generic.homset -from copy import copy +from sage.schemes.generic.homset import SchemeHomset_points, SchemeHomset_generic + +# ******************************************************************* +# Affine varieties +# ******************************************************************* -#******************************************************************* -# Affine varieties -#******************************************************************* -class SchemeHomset_points_spec(sage.schemes.generic.homset.SchemeHomset_generic): +class SchemeHomset_points_spec(SchemeHomset_generic): """ Set of rational points of an affine variety. @@ -62,7 +63,6 @@ class SchemeHomset_points_spec(sage.schemes.generic.homset.SchemeHomset_generic) sage: SchemeHomset_points_spec(Spec(QQ), Spec(QQ)) Set of rational points of Spectrum of Rational Field """ - def _element_constructor_(self, *args, **kwds): """ The element constructor. @@ -86,7 +86,7 @@ def _element_constructor_(self, *args, **kwds): Defn: Ring endomorphism of Rational Field Defn: 1 |--> 1 """ - return sage.schemes.generic.homset.SchemeHomset_generic._element_constructor_(self, *args, **kwds) + return super()._element_constructor_(*args, **kwds) def _repr_(self): """ @@ -101,14 +101,47 @@ def _repr_(self): sage: S._repr_() 'Set of rational points of Spectrum of Rational Field' """ - return 'Set of rational points of '+str(self.codomain()) + return 'Set of rational points of {}'.format(self.codomain()) + + +class SchemeHomset_polynomial_affine_space(SchemeHomset_generic): + """ + Set of morphisms between affine spaces defined by polynomials. + + EXAMPLES:: + + sage: A. = AffineSpace(2, QQ) + sage: Hom(A, A) + Set of morphisms + From: Affine Space of dimension 2 over Rational Field + To: Affine Space of dimension 2 over Rational Field + """ + def identity(self): + """ + The identity morphism of this homset. + + EXAMPLES:: + + sage: A. = AffineSpace(2, QQ) + sage: I = A.identity_morphism() + sage: I.parent() + Set of morphisms + From: Affine Space of dimension 2 over Rational Field + To: Affine Space of dimension 2 over Rational Field + sage: _.identity() == I + True + """ + if self.is_endomorphism_set(): + from sage.schemes.generic.morphism import SchemeMorphism_polynomial_id + return SchemeMorphism_polynomial_id(self.domain()) + raise TypeError("identity map is only defined for endomorphisms") +# ******************************************************************* +# Affine varieties +# ******************************************************************* -#******************************************************************* -# Affine varieties -#******************************************************************* -class SchemeHomset_points_affine(sage.schemes.generic.homset.SchemeHomset_points): +class SchemeHomset_points_affine(SchemeHomset_points): """ Set of rational points of an affine variety. diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index 7aa998461c5..3d78393b496 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -21,21 +21,24 @@ from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.categories.map import Map from sage.categories.fields import Fields -_Fields = Fields() +from sage.categories.homset import Hom from sage.categories.number_fields import NumberFields from sage.misc.latex import latex from sage.misc.mrange import cartesian_product_iterator +from sage.matrix.constructor import matrix from sage.structure.category_object import normalize_names from sage.schemes.generic.scheme import AffineScheme from sage.schemes.generic.ambient_space import AmbientSpace -from sage.schemes.affine.affine_homset import SchemeHomset_points_affine +from sage.schemes.affine.affine_homset import (SchemeHomset_points_affine, + SchemeHomset_polynomial_affine_space) from sage.schemes.affine.affine_morphism import (SchemeMorphism_polynomial_affine_space, SchemeMorphism_polynomial_affine_space_field, SchemeMorphism_polynomial_affine_space_finite_field) from sage.schemes.affine.affine_point import (SchemeMorphism_point_affine, SchemeMorphism_point_affine_field, SchemeMorphism_point_affine_finite_field) -from sage.matrix.constructor import matrix + +_Fields = Fields() def is_AffineSpace(x): r""" @@ -226,7 +229,6 @@ def __iter__(self): for v in cartesian_product_iterator([R for _ in range(n)]): yield C._point(AHom, v, check=False) - def ngens(self): """ Return the number of generators of self, i.e. the number of @@ -364,6 +366,20 @@ def _morphism(self, *args, **kwds): """ return SchemeMorphism_polynomial_affine_space(*args, **kwds) + def _homset(self, *args, **kwds): + """ + Construct the Hom-set. + + EXAMPLES:: + + sage: A. = AffineSpace(2, QQ) + sage: Hom(A, A) + Set of morphisms + From: Affine Space of dimension 2 over Rational Field + To: Affine Space of dimension 2 over Rational Field + """ + return SchemeHomset_polynomial_affine_space(*args, **kwds) + def _point_homset(self, *args, **kwds): """ Construct a Hom-set for this affine space. diff --git a/src/sage/schemes/cyclic_covers/charpoly_frobenius.py b/src/sage/schemes/cyclic_covers/charpoly_frobenius.py index 70be2448a99..960c0343889 100644 --- a/src/sage/schemes/cyclic_covers/charpoly_frobenius.py +++ b/src/sage/schemes/cyclic_covers/charpoly_frobenius.py @@ -1,16 +1,11 @@ r""" - Computation of the Frobenius polynomial using Newton's identities - """ - - # ***************************************************************************** # Copyright (C) 2018 Edgar Costa # Distributed under the terms of the GNU General Public License (GPL) # https://www.gnu.org/licenses/ # ***************************************************************************** - from sage.rings.integer_ring import ZZ from sage.misc.lazy_import import lazy_import lazy_import("sage.functions.log", "log") @@ -24,15 +19,15 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= - ``frob_matrix`` -- a matrix representing the Frobenius matrix up to some precision - - ``charpoly_prec`` -- a vector ai, such that, `frob_matrix.change_ring(ZZ).charpoly()[i]` - will be correct mod `p^ai`, this can be easily deduced from the Hodge numbers and - knowing the q-adic precision of ``frob_matrix`` + - ``charpoly_prec`` -- a vector ai, such that, ``frob_matrix.change_ring(ZZ).charpoly()[i]`` + will be correct mod `p^ai`, this can be easily deduced from the + Hodge numbers and knowing the q-adic precision of ``frob_matrix`` - ``p`` -- prime `p` - ``weight`` -- weight of the motive - - ``a`` -- `q = q^a` + - ``a`` -- `p = q^a` - ``known_factor`` -- the list of coefficients of the known factor @@ -196,14 +191,12 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= sage: F+= F.base_ring()(0).add_bigoh(6)*ones_matrix(*F.dimensions()) sage: charpoly_frobenius(F, [6, 5, 4, 4], 17, 2) [-4913, -221, 13, 1] - - """ assert known_factor[-1] == 1 try: cp = frob_matrix.change_ring(ZZ).charpoly().list() except ValueError: - # the given matrix wasn't integral + # the given matrix was not integral cp = frob_matrix.charpoly().change_ring(ZZ).list() assert len(charpoly_prec) == len(cp) - (len(known_factor) - 1) assert cp[-1] == 1 @@ -217,7 +210,7 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= # figure out the sign # i.e., if it is a reciprocal or an antireciprocal polynomial - if weight % 2 == 1: + if weight % 2: # for odd weight the sign is always 1 # it's the charpoly of a USp matrix # and charpoly of a symplectic matrix is reciprocal @@ -228,7 +221,7 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= raise NotImplementedError() # we compare ith coefficient and (degree - i)th coefficient to deduce the sign # note, if degree is even, the middle coefficient will not help us determine the sign - for i in range((degree + 1)//2): + for i in range((degree + 1) // 2): # Note: degree*weight is even p_power = p**min( charpoly_prec[i], @@ -249,19 +242,21 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= # note, this includes the middle coefficient if degree is even halfdegree = degree // 2 + 1 - cp[0] = sign * p**((a * degree * weight) // 2) # Note: degree*weight is even + cp[0] = sign * p**((a * degree * weight) // 2) + # Note: degree*weight is even + # calculate the i-th power sum of the roots and correct cp along the way e = cp[-halfdegree:] e.reverse() for k in range(halfdegree): - if k % 2 != 0: + if k % 2: e[k] = -e[k] % mod[degree - k] # e[k] = cp[degree - k] if (k%2 ==0) else -cp[degree - k] if k > 0: # verify if p^charpoly_prec[degree - k] > 2*degree/k * q^(w*k/2) assert ( - log(k) / log(p) + charpoly_prec[degree - k] - > log(2 * degree) / log(p) + a * 0.5 * weight * k + log(k, p) + charpoly_prec[degree - k] + > log(2 * degree, p) + a * 0.5 * weight * k ), ( "log(k)/log(p) + charpoly_prec[degree - k] <= log(2*degree)/log(p) + a*0.5*weight*k, k = %d" % k @@ -272,7 +267,7 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= if len(fix_e) < halfdegree: fix_e.extend([0] * (halfdegree - len(fix_e))) for i in range(halfdegree): - if i % 2 != 0: + if i % 2: fix_e[i] *= -1 # e[k] = \sum x_{i_1} x_{i_2} ... x_{i_k} # where x_* are eigenvalues @@ -281,7 +276,9 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= # s[k] = \sum x_i ^k for k>0 s = [None] * (halfdegree) res = [None] * len(charpoly_prec) - res[0] = sign * p**((a * degree * weight) // 2) # Note: degree*weight is even + res[0] = sign * p**((a * degree * weight) // 2) + # Note: degree*weight is even + res[-1] = 1 e[1] -= fix_e[1] e[1] = e[1] % mod[degree - 1] @@ -307,8 +304,9 @@ def charpoly_frobenius(frob_matrix, charpoly_prec, p, weight, a=1, known_factor= # (-1)^(k-1) s[k] - S = k*e[k] e[k] = (-S + (-1)**(k - 1) * s[k]) // k assert (-S + (-1)**(k - 1) * s[k]) % k == 0 - res[degree - k] = e[k] if k % 2 == 0 else -e[k] + res[degree - k] = e[k] if not k % 2 else -e[k] # Note: degree*weight is even + res[k] = sign * res[degree - k] * p**((a * (degree - 2 * k) * weight) // 2) # fix e[k + 1] if k + 1 < halfdegree: diff --git a/src/sage/schemes/elliptic_curves/cardinality.py b/src/sage/schemes/elliptic_curves/cardinality.py index ea12ffa0965..cc93b9ecf74 100644 --- a/src/sage/schemes/elliptic_curves/cardinality.py +++ b/src/sage/schemes/elliptic_curves/cardinality.py @@ -2,28 +2,23 @@ Specific algorithms to compute cardinality of elliptic curves over a finite field Since point counting now uses PARI/GP, this code is only used when a -specific algorithm was specified or when the j-invariant lies in a -subfield. +specific algorithm was specified or when the j-invariant lies in a subfield. AUTHORS: - John Cremona (2008-2009): Original point counting code -- Jeroen Demeyer (2017-2018): Refactored and moved to - ``cardinality.py``. +- Jeroen Demeyer (2017-2018): Refactored and moved to ``cardinality.py``. """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008-2009 John Cremona # # 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 .constructor import EllipticCurve, EllipticCurve_from_j from sage.schemes.curves.projective_curve import Hasse_bounds from sage.rings.all import Integer, ZZ, GF, polygen @@ -40,19 +35,19 @@ def _cardinality_with_j_invariant_1728(self): An example with q=p=1 (mod 4):: - sage: F=GF(10009) + sage: F = GF(10009) sage: [_cardinality_with_j_invariant_1728(EllipticCurve(F,[0,0,0,11^i,0])) for i in range(4)] [10016, 10210, 10004, 9810] An example with q=p=3 (mod 4):: - sage: F=GF(10007) + sage: F = GF(10007) sage: [_cardinality_with_j_invariant_1728(EllipticCurve(F,[0,0,0,5^i,0])) for i in range(4)] [10008, 10008, 10008, 10008] An example with `q=p^2`, p=3 (mod 4):: - sage: F.=GF(10007^2,'a') + sage: F. = GF(10007^2,'a') sage: [_cardinality_with_j_invariant_1728(EllipticCurve(F,[0,0,0,a^i,0])) for i in range(4)] [100160064, 100140050, 100120036, 100140050] @@ -90,11 +85,11 @@ def _cardinality_with_j_invariant_1728(self): Examples with `q=3^d`, d even (6 isomorphism classes):: - sage: F.=GF(3^18,'g') - sage: i=F(-1).sqrt() - sage: a=g^8 # has trace 1 - sage: ais= [[0,0,0,1,0],[0,0,0,1,i*a],[0,0,0,g,0],[0,0,0,g^3,0],[0,0,0,g^2,0], [0,0,0,g^2,i*a*g^3]] - sage: curves=[EllipticCurve(F,ai) for ai in ais] + sage: F. = GF(3^18,'g') + sage: i = F(-1).sqrt() + sage: a = g^8 # has trace 1 + sage: ais = [[0,0,0,1,0],[0,0,0,1,i*a],[0,0,0,g,0],[0,0,0,g^3,0],[0,0,0,g^2,0], [0,0,0,g^2,i*a*g^3]] + sage: curves = [EllipticCurve(F,ai) for ai in ais] sage: all((e1 == e2 or not e1.is_isomorphic(e2)) for e1 in curves for e2 in curves) True sage: [_cardinality_with_j_invariant_1728(e) for e in curves] @@ -104,7 +99,7 @@ def _cardinality_with_j_invariant_1728(self): Check that a bug noted at :trac:`15667` is fixed:: - sage: F.=GF(3^6,'a') + sage: F. = GF(3^6,'a') sage: EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a, a^4 + a^3 + 2*a + 1]).cardinality() 784 sage: EllipticCurve([a^5 + 2*a^3 + 2*a^2 + 2*a, a^4 + a^3 + 2*a + 1]).cardinality_exhaustive() @@ -116,27 +111,27 @@ def _cardinality_with_j_invariant_1728(self): pass k = self.base_ring() - assert self.j_invariant()==k(1728) + assert self.j_invariant() == k(1728) q = k.cardinality() p = k.characteristic() d = k.degree() - x=polygen(ZZ) + x = polygen(ZZ) # p=2, j=0=1728 # # Number of isomorphism classes is 3 (in odd degree) or 7 (in even degree) # - if p==2: - if d%2==1: + if p == 2: + if d % 2: # The 3 classes are represented, independently of d, # by [0,0,1,0,0], [0,0,1,1,0], [0,0,1,1,1] - E=EllipticCurve(k,[0,0,1,0,0]) + E = EllipticCurve(k, [0, 0, 1, 0, 0]) if self.is_isomorphic(E): t = 0 else: - n = (d+1)//2 + n = (d + 1) // 2 t = 2**n - n = n%4 + n = n % 4 if n == 0 or n == 1: t = -t E = EllipticCurve(k, [0, 0, 1, 1, 1]) @@ -153,31 +148,31 @@ def _cardinality_with_j_invariant_1728(self): # unity, so the traces are 2*pi, -2*pi, 0, -pi, +pi; # -pi, +pi. delta = self.discriminant() - discube = (delta**((q-1)//3) == k(1)) - pi = (-2)**(d//2) + discube = (delta**((q - 1) // 3) == k(1)) + pi = (-2)**(d // 2) if discube: a = k.gen() b = a while b.trace() == 0: b *= a - if self.is_isomorphic(EllipticCurve(k,[0,0,1,b,0])): + if self.is_isomorphic(EllipticCurve(k, [0, 0, 1, b, 0])): t = 0 else: - t = 2*pi - if not self.is_isomorphic(EllipticCurve(k,[0,0,1,0,0])): + t = 2 * pi + if not self.is_isomorphic(EllipticCurve(k, [0, 0, 1, 0, 0])): t = -t else: t = pi - if self.is_isomorphic(EllipticCurve(k,[0,0,delta,0,0])): + if self.is_isomorphic(EllipticCurve(k, [0, 0, delta, 0, 0])): t = -t # p=3, j=0=1728 # # Number of isomorphism classes is 4 (odd degree) or 6 (even degree) # - elif p==3: - if d%2==1: + elif p == 3: + if d % 2: # The 4 classes are represented by [0,0,0,1,0], # [0,0,0,-1,0], [0,0,0,-1,a], [0,0,0,-1,-a] where a # has trace 1 @@ -188,13 +183,13 @@ def _cardinality_with_j_invariant_1728(self): u = delta.sqrt() if not u.is_square(): u = -u - tr = ((self.a3()**2+self.a6())/u).trace() - if tr==0: + tr = ((self.a3()**2 + self.a6()) / u).trace() + if tr == 0: t = 0 else: - d2 = (d+1)//2 + d2 = (d + 1) // 2 t = 3**d2 - if d2%2 == 1: + if d2 % 2: t = -t if tr == -1: t = -t @@ -207,13 +202,13 @@ def _cardinality_with_j_invariant_1728(self): # The curve is isomorphic to [0,0,0,A4,A6] - A4 = self.a4() - self.a1()*self.a3() # = -b4 = 2*b4 + A4 = self.a4() - self.a1() * self.a3() # = -b4 = 2*b4 if A4.is_square(): u = A4.sqrt() - t = (-3)**(d//2) + t = (-3)**(d // 2) i = k(-1).sqrt() A6 = self.a3()**2 + self.a6() # = b6 - if (A6/(i*u*A4)).trace()==0: + if (A6 / (i * u * A4)).trace() == 0: t *= 2 else: t *= -1 @@ -226,16 +221,16 @@ def _cardinality_with_j_invariant_1728(self): # # Number of isomorphism classes is 4 if q=1 (mod 4), else 2 # - elif p%4==3: - if d%2==1: + elif p % 4 == 3: + if d % 2: t = 0 else: - t = (-p)**(d//2) - w = (self.c4()/k(48))**((q-1)//4) + t = (-p)**(d // 2) + w = (self.c4() / k(48))**((q - 1) // 4) if w == 1: - t = 2*t + t = 2 * t elif w == -1: - t = -2*t + t = -2 * t else: t = 0 @@ -243,31 +238,31 @@ def _cardinality_with_j_invariant_1728(self): # N(pi)=p and N(pi-1)=0 (mod 8). # else: - R = ZZ.extension(x**2+1,'i') + R = ZZ.extension(x**2 + 1, 'i') i = R.gen(1) pi = R.fraction_field().factor(p)[0][0].gens_reduced()[0] - a,b = pi.list() - if a%2==0: - a,b = -b,a - if (a+b+1)%4==0: - a,b = -a,-b - pi = a+b*i # Now pi=a+b*i with (a,b)=(1,0),(3,2) mod 4 + a, b = pi.list() + if a % 2 == 0: + a, b = -b, a + if (a + b + 1) % 4 == 0: + a, b = -a, -b + pi = a + b * i # Now pi=a+b*i with (a,b)=(1,0),(3,2) mod 4 # Lift to Frobenius for [0,0,0,-1,0] over GF(p^d): - if d>1: + if d > 1: pi = pi**d - a,b = pi.list() + a, b = pi.list() # Compute appropriate quartic twist: - w = (self.c4()/k(48))**((q-1)//4) - if w==1: - t = 2*a - elif w==-1: - t = -2*a - elif k(b)==w*k(a): - t = 2*b + w = (self.c4() / k(48))**((q - 1) // 4) + if w == 1: + t = 2 * a + elif w == -1: + t = -2 * a + elif k(b) == w * k(a): + t = 2 * b else: - t = -2*b + t = -2 * b return Integer(q + 1 - t) @@ -282,19 +277,19 @@ def _cardinality_with_j_invariant_0(self): An example with q=p=1 (mod 6):: - sage: F=GF(1009) + sage: F = GF(1009) sage: [_cardinality_with_j_invariant_0(EllipticCurve(F,[0,0,0,0,11^i])) for i in range(6)] [948, 967, 1029, 1072, 1053, 991] An example with q=p=5 (mod 6):: - sage: F=GF(1013) + sage: F = GF(1013) sage: [_cardinality_with_j_invariant_0(EllipticCurve(F,[0,0,0,0,3^i])) for i in range(6)] [1014, 1014, 1014, 1014, 1014, 1014] An example with `q=p^2`, p=5 (mod 6):: - sage: F.=GF(1013^2,'a') + sage: F. = GF(1013^2,'a') sage: [_cardinality_with_j_invariant_0(EllipticCurve(F,[0,0,0,0,a^i])) for i in range(6)] [1028196, 1027183, 1025157, 1024144, 1025157, 1027183] @@ -302,29 +297,29 @@ def _cardinality_with_j_invariant_0(self): :func:`_cardinality_with_j_invariant_1728`. """ k = self.base_ring() - assert self.j_invariant()==k(0) + assert self.j_invariant() == k.zero() p = k.characteristic() - if p==2 or p==3: # then 0==1728 + if p == 2 or p == 3: # then 0==1728 return _cardinality_with_j_invariant_1728(self) q = k.cardinality() d = k.degree() - x=polygen(ZZ) + x = polygen(ZZ) # p>3, j=0 # # Number of isomorphism classes is 4 if q=1 (mod 4), else 2 # - if p%6==5: - if d%2==1: + if p % 6 == 5: + if d % 2: t = 0 else: - t = (-p)**(d//2) - w = (self.c6()/k(-864))**((q-1)//6) + t = (-p)**(d // 2) + w = (self.c6() / k(-864))**((q - 1) // 6) if w == 1: - t = 2*t + t = 2 * t elif w == -1: - t = -2*t + t = -2 * t elif w**3 == 1: t = -t @@ -332,45 +327,46 @@ def _cardinality_with_j_invariant_0(self): # N(pi)=p and N(pi-1)=0 (mod 12). # else: - R = ZZ.extension(x**2-x+1,'zeta6') + R = ZZ.extension(x**2 - x + 1, 'zeta6') zeta6 = R.gen(1) pi = R.fraction_field().factor(p)[0][0].gens_reduced()[0] while (pi - 1).norm() % 12: pi *= zeta6 - a,b = pi.list() - z = k(-b)/k(a) # a *specific* 6th root of unity in k + a, b = pi.list() + z = k(-b) / k(a) # a *specific* 6th root of unity in k # Now pi=a+b*zeta6 with N(pi-1)=0 (mod 12) # Lift to Frobenius for [0,0,0,0,1] over GF(p^d): - if d>1: + if d > 1: pi = pi**d - a,b = pi.list() + a, b = pi.list() # Compute appropriate sextic twist: - w = (self.c6()/k(-864))**((q-1)//6) + w = (self.c6() / k(-864))**((q - 1) // 6) if w == 1: - t = 2*a+b # = Trace(pi) + t = 2 * a + b # = Trace(pi) elif w == -1: - t = -2*a-b # = Trace(-pi) + t = -2 * a - b # = Trace(-pi) elif w == z: - t = a-b # = Trace(pi*zeta6) + t = a - b # = Trace(pi*zeta6) elif w == z**2: - t = -a-2*b # = Trace(pi*zeta6**2) + t = -a - 2 * b # = Trace(pi*zeta6**2) elif w == z**4: - t = b-a # = Trace(pi*zeta6**4) + t = b - a # = Trace(pi*zeta6**4) elif w == z**5: - t = a+2*b # = Trace(pi*zeta6**5) + t = a + 2 * b # = Trace(pi*zeta6**5) return Integer(q + 1 - t) def cardinality_exhaustive(self): r""" - Return the cardinality of self over the base field. Simply adds up - the number of points with each x-coordinate: only used for small - field sizes! + Return the cardinality of ``self`` over the base field. + + This simply adds up the number of points with each x-coordinate: + only used for small field sizes! EXAMPLES:: @@ -382,13 +378,14 @@ def cardinality_exhaustive(self): sage: E.cardinality_exhaustive() 64 """ - self._order = Integer(1+sum([len(self.lift_x(x,all=True)) for x in self.base_field()])) + self._order = Integer(1 + sum(len(self.lift_x(x, all=True)) + for x in self.base_field())) return self._order def cardinality_bsgs(self, verbose=False): r""" - Return the cardinality of self over the base field. + Return the cardinality of ``self`` over the base field. ALGORITHM: A variant of "Mestre's trick" extended to all finite fields by Cremona and Sutherland, 2008. @@ -404,15 +401,15 @@ def cardinality_bsgs(self, verbose=False): EXAMPLES:: - sage: p=next_prime(10^3) - sage: E=EllipticCurve(GF(p),[3,4]) + sage: p = next_prime(10^3) + sage: E = EllipticCurve(GF(p),[3,4]) sage: E.cardinality_bsgs() 1020 - sage: E=EllipticCurve(GF(3^4,'a'),[1,1]) + sage: E = EllipticCurve(GF(3^4,'a'),[1,1]) sage: E.cardinality_bsgs() 64 - sage: F.=GF(101^3,'a') - sage: E=EllipticCurve([2*a^2 + 48*a + 27, 89*a^2 + 76*a + 24]) + sage: F. = GF(101^3,'a') + sage: E = EllipticCurve([2*a^2 + 48*a + 27, 89*a^2 + 76*a + 24]) sage: E.cardinality_bsgs() 1031352 """ @@ -431,12 +428,12 @@ def cardinality_bsgs(self, verbose=False): bounds = Hasse_bounds(q) lower, upper = bounds - B = upper-q-1 # = floor(2*sqrt(q)) + B = upper - q - 1 # = floor(2*sqrt(q)) a = ZZ(0) N1 = N2 = M = ZZ(1) kmin = -B kmax = B - q1 = q+1 + q1 = q + 1 # Throughout, we have #E=q+1-t where |t|<=B and t=a+k*M = a # (mod M) where kmin <= k <= kmax. @@ -445,28 +442,28 @@ def cardinality_bsgs(self, verbose=False): # kmin=kmax. if q > 2**10: - N1 = ZZ(2)**sum([e for P,e in E1._p_primary_torsion_basis(2)]) - N2 = ZZ(2)**sum([e for P,e in E2._p_primary_torsion_basis(2)]) + N1 = ZZ(2)**sum([e for P, e in E1._p_primary_torsion_basis(2)]) + N2 = ZZ(2)**sum([e for P, e in E2._p_primary_torsion_basis(2)]) if q > 2**20: - N1 *= ZZ(3)**sum([e for P,e in E1._p_primary_torsion_basis(3)]) - N2 *= ZZ(3)**sum([e for P,e in E2._p_primary_torsion_basis(3)]) + N1 *= ZZ(3)**sum([e for P, e in E1._p_primary_torsion_basis(3)]) + N2 *= ZZ(3)**sum([e for P, e in E2._p_primary_torsion_basis(3)]) if q > 2**40: - N1 *= ZZ(5)**sum([e for P,e in E1._p_primary_torsion_basis(5)]) - N2 *= ZZ(5)**sum([e for P,e in E2._p_primary_torsion_basis(5)]) + N1 *= ZZ(5)**sum([e for P, e in E1._p_primary_torsion_basis(5)]) + N2 *= ZZ(5)**sum([e for P, e in E2._p_primary_torsion_basis(5)]) # We now know that t=q+1 (mod N1) and t=-(q+1) (mod N2) a = q1 M = N1 - g,u,v = M.xgcd(N2) # g==u*M+v*N2 - if N2>g: - a = (a*v*N2-q1*u*M)//g - M *= (N2//g) # = lcm(M,N2) - a = a%M + g, u, v = M.xgcd(N2) # g==u*M+v*N2 + if N2 > g: + a = (a * v * N2 - q1 * u * M) // g + M *= (N2 // g) # = lcm(M,N2) + a = a % M if verbose: print("(a,M)=", (a, M)) - kmin = ((-B-a)/M).ceil() - kmax = ((B-a)/M).floor() - if kmin==kmax: - self._order = q1-a-kmin*M + kmin = ((-B - a) / M).ceil() + kmax = ((B - a) / M).floor() + if kmin == kmax: + self._order = q1 - a - kmin * M if verbose: print("no random points were needed") return self._order @@ -478,51 +475,51 @@ def cardinality_bsgs(self, verbose=False): # points on each curve. For large q it is worth initializing # these with the full order of the (2,3,5)-torsion which are # often non-trivial. - while kmax!=kmin: + while kmax != kmin: # Get a random point on E1 and find its order, using the # Hasse bounds and the fact that we know that the group # order is a multiple of N1: - n = order_from_bounds(E1.random_point(),bounds,N1,operation='+') + n = order_from_bounds(E1.random_point(), bounds, N1, operation='+') if verbose: print("New point on E has order ", n) # update N1 and M N1 = N1.lcm(n) - g,u,v = M.xgcd(n) # g==u*M+v*n - if n>g: + g, u, v = M.xgcd(n) # g==u*M+v*n + if n > g: # update congruence a (mod M) with q+1 (mod n) - a = (a*v*n+q1*u*M)//g - M *= (n//g) # = lcm(M,n) - a = a%M + a = (a * v * n + q1 * u * M) // g + M *= (n // g) # = lcm(M,n) + a = a % M if verbose: print("(a,M)=", (a, M)) - kmin = ((-B-a)/M).ceil() - kmax = ((B-a)/M).floor() - if kmin==kmax: - self._order = q1-a-kmin*M + kmin = ((-B - a) / M).ceil() + kmax = ((B - a) / M).floor() + if kmin == kmax: + self._order = q1 - a - kmin * M return self._order if verbose: - print("number of possibilities is now ",kmax-kmin+1) + print("number of possibilities is now ", kmax - kmin + 1) # Get a random point on E2 and find its order, using the # Hasse bounds and the fact that we know that the group # order is a multiple of N2: - n = order_from_bounds(E2.random_point(),bounds,N2,operation='+') + n = order_from_bounds(E2.random_point(), bounds, N2, operation='+') if verbose: print("New point on E' has order ", n) # update N2 and M N2 = N2.lcm(n) - g,u,v = M.xgcd(n) # g==u*M+v*n - if n>g: + g, u, v = M.xgcd(n) # g==u*M+v*n + if n > g: # update congruence a (mod M) with -(q+1) (mod n) - a = (a*v*n-q1*u*M)//g - M *= (n//g) # = lcm(M,n) - a = a%M + a = (a * v * n - q1 * u * M) // g + M *= (n // g) # = lcm(M,n) + a = a % M if verbose: print("(a,M)=", (a, M)) - kmin = ((-B-a)/M).ceil() - kmax = ((B-a)/M).floor() - if kmin==kmax: - self._order = q1-a-kmin*M + kmin = ((-B - a) / M).ceil() + kmax = ((B - a) / M).floor() + if kmin == kmax: + self._order = q1 - a - kmin * M return self._order if verbose: print("number of possibilities is now ", kmax - kmin + 1) @@ -598,4 +595,4 @@ def _cardinality_subfield(self, jpol): return N else: q = k.cardinality() - return 2*(q+1) - N + return 2 * (q + 1) - N diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index 9c3cb195eff..d03346deacc 100644 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -18,14 +18,18 @@ sage: Q = E(6,5) sage: phi = E.isogeny(Q) sage: phi - Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x + 1 over Finite Field of size 11 to Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 11 + Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x + 1 over + Finite Field of size 11 to Elliptic Curve defined by y^2 = x^3 + 7*x + 8 + over Finite Field of size 11 sage: P = E(4,5) sage: phi(P) (10 : 0 : 1) sage: phi.codomain() Elliptic Curve defined by y^2 = x^3 + 7*x + 8 over Finite Field of size 11 sage: phi.rational_maps() - ((x^7 + 4*x^6 - 3*x^5 - 2*x^4 - 3*x^3 + 3*x^2 + x - 2)/(x^6 + 4*x^5 - 4*x^4 - 5*x^3 + 5*x^2), (x^9*y - 5*x^8*y - x^7*y + x^5*y - x^4*y - 5*x^3*y - 5*x^2*y - 2*x*y - 5*y)/(x^9 - 5*x^8 + 4*x^6 - 3*x^4 + 2*x^3)) + ((x^7 + 4*x^6 - 3*x^5 - 2*x^4 - 3*x^3 + 3*x^2 + x - 2)/(x^6 + 4*x^5 - 4*x^4 + - 5*x^3 + 5*x^2), (x^9*y - 5*x^8*y - x^7*y + x^5*y - x^4*y - 5*x^3*y - + 5*x^2*y - 2*x*y - 5*y)/(x^9 - 5*x^8 + 4*x^6 - 3*x^4 + 2*x^3)) The methods directly accessible from an elliptic curve ``E`` over a field are @@ -337,7 +341,6 @@ def compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3): w = 3*(s1**3 - 3*s1*s2 + 3*s3) + (b2*temp1 + b4*s1)/2 return v, w - def compute_vw_kohel_odd(b2, b4, b6, s1, s2, s3, n): r""" Compute Vélu's `(v,w)` using Kohel's formulas for isogenies of odd @@ -374,7 +377,6 @@ def compute_vw_kohel_odd(b2, b4, b6, s1, s2, s3, n): w = 10*(s1**3 - 3*s1*s2 + 3*s3) + 2*b2*(s1**2 - 2*s2) + 3*b4*s1 + n*b6 return v, w - def compute_codomain_kohel(E, kernel): r""" Compute the codomain from the kernel polynomial using Kohel's @@ -481,7 +483,6 @@ def compute_codomain_kohel(E, kernel): return compute_codomain_formula(E, v, w) - def two_torsion_part(E, psi): r""" Return the greatest common divisor of ``psi`` and the 2-torsion @@ -516,6 +517,7 @@ def two_torsion_part(E, psi): psi_2 = E.two_division_polynomial(x) return psi.gcd(psi_2) + class EllipticCurveIsogeny(EllipticCurveHom): r""" This class implements separable isogenies of elliptic curves. @@ -813,18 +815,15 @@ class EllipticCurveIsogeny(EllipticCurveHom): sage: phi.codomain() Elliptic Curve defined by y^2 + x*y = x^3 + 24*x + 6 over Finite Field of size 31 - Composition tests (see :trac:`16245`):: + Composition tests (see :trac:`16245`, cf. :trac:`34410`):: sage: E = EllipticCurve(j=GF(7)(0)) sage: phi = E.isogeny([E(0), E((0,1)), E((0,-1))]); phi Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 sage: phi2 = phi * phi; phi2 - Composite map: + Composite morphism of degree 9 = 3^2: From: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 To: Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 - Defn: Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 - then - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 to Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 7 Examples over relative number fields used not to work (see :trac:`16779`):: @@ -1276,6 +1275,52 @@ def __neg__(self): sage: P = E((7,13)) sage: phi(P) + negphi(P) == 0 True + + sage: E = EllipticCurve(GF(23), [0,0,0,1,0]) + sage: f = E.torsion_polynomial(3)/3 + sage: phi = EllipticCurveIsogeny(E, f, E) + sage: phi.rational_maps() == E.multiplication_by_m(3) + False + sage: negphi = -phi + sage: negphi.rational_maps() == E.multiplication_by_m(3) + True + + sage: E = EllipticCurve(GF(17), [-2, 3, -5, 7, -11]) + sage: R. = GF(17)[] + sage: f = x+6 + sage: phi = EllipticCurveIsogeny(E, f) + sage: phi + Isogeny of degree 2 from Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 7*x + 6 over Finite Field of size 17 to Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 4*x + 8 over Finite Field of size 17 + sage: phi.rational_maps() + ((x^2 + 6*x + 4)/(x + 6), (x^2*y - 5*x*y + 8*x - 2*y)/(x^2 - 5*x + 2)) + sage: negphi = -phi + sage: negphi + Isogeny of degree 2 from Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 7*x + 6 over Finite Field of size 17 to Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 4*x + 8 over Finite Field of size 17 + sage: negphi.rational_maps() + ((x^2 + 6*x + 4)/(x + 6), + (2*x^3 - x^2*y - 5*x^2 + 5*x*y - 4*x + 2*y + 7)/(x^2 - 5*x + 2)) + + sage: E = EllipticCurve('11a1') + sage: R. = QQ[] + sage: f = x^2 - 21*x + 80 + sage: phi = EllipticCurveIsogeny(E, f) + sage: (xmap1, ymap1) = phi.rational_maps() + sage: negphi = -phi + sage: (xmap2, ymap2) = negphi.rational_maps() + sage: xmap1 == xmap2 + True + sage: ymap1 == -ymap2 - E.a1()*xmap2 - E.a3() + True + + sage: K. = NumberField(x^2 + 1) + sage: E = EllipticCurve(K, [0,0,0,1,0]) + sage: R. = K[] + sage: phi = EllipticCurveIsogeny(E, x-a) + sage: phi.rational_maps() + ((x^2 + (-a)*x - 2)/(x + (-a)), (x^2*y + (-2*a)*x*y + y)/(x^2 + (-2*a)*x - 1)) + sage: negphi = -phi + sage: negphi.rational_maps() + ((x^2 + (-a)*x - 2)/(x + (-a)), (-x^2*y + (2*a)*x*y - y)/(x^2 + (-2*a)*x - 1)) """ output = copy(self) E2 = output._codomain @@ -1345,8 +1390,7 @@ def __clear_cached_values(self): sage: phi = EllipticCurveIsogeny(E, x) sage: old_ratl_maps = phi.rational_maps() sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: phi.set_post_isomorphism(WeierstrassIsomorphism(phi.codomain(), (-1,0,0,0))) - ... + sage: phi._set_post_isomorphism(WeierstrassIsomorphism(phi.codomain(), (-1,0,0,0))) sage: old_ratl_maps == phi.rational_maps() False sage: old_ratl_maps[1] == -phi.rational_maps()[1] @@ -1358,8 +1402,7 @@ def __clear_cached_values(self): sage: phi = EllipticCurveIsogeny(E, f) sage: old_ratl_maps = phi.rational_maps() sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: phi.set_post_isomorphism(WeierstrassIsomorphism(phi.codomain(), (-13,13,-13,13))) - ... + sage: phi._set_post_isomorphism(WeierstrassIsomorphism(phi.codomain(), (-13,13,-13,13))) sage: old_ratl_maps == phi.rational_maps() False sage: phi._EllipticCurveIsogeny__clear_cached_values() @@ -1384,12 +1427,10 @@ def __perform_inheritance_housekeeping(self): sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: E2 = phi.codomain() sage: post_isom = WeierstrassIsomorphism(E2, (41, 37, 31, 29)) - sage: phi.set_post_isomorphism(post_isom) - ... + sage: phi._set_post_isomorphism(post_isom) sage: E1pr = WeierstrassIsomorphism(E, (-1, 2, -3, 4)).codomain() sage: pre_isom = E1pr.isomorphism_to(E) - sage: phi.set_pre_isomorphism(pre_isom) - ... + sage: phi._set_pre_isomorphism(pre_isom) """ EllipticCurveHom.__init__(self, self._domain, self._codomain) @@ -1582,8 +1623,7 @@ def __set_pre_isomorphism(self, domain, isomorphism): sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: E1pr = WeierstrassIsomorphism(E, (-1, 2, -3, 4)).codomain() sage: pre_isom = E1pr.isomorphism_to(E) - sage: phi.set_pre_isomorphism(pre_isom) - ... + sage: phi._set_pre_isomorphism(pre_isom) sage: phi._EllipticCurveIsogeny__set_pre_isomorphism(E, WeierstrassIsomorphism(E, (-1, 3, -3, 4))) sage: E == phi.domain() True @@ -1625,8 +1665,7 @@ def __set_post_isomorphism(self, codomain, isomorphism): sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism sage: E2 = phi.codomain() sage: isom = WeierstrassIsomorphism(E2, (-1,2,-3,4)) - sage: phi.set_post_isomorphism(isom) - ... + sage: phi._set_post_isomorphism(isom) sage: phi._EllipticCurveIsogeny__set_post_isomorphism(E2, WeierstrassIsomorphism(phi.codomain(), (1,-2,3,-4))) sage: E2 == phi.codomain() True @@ -1702,7 +1741,6 @@ def __setup_post_isomorphism(self, codomain, model): post_isom = oldE2.isomorphism_to(codomain) self.__set_post_isomorphism(codomain, post_isom) - ########################### # Velu's Formula Functions ########################### @@ -1836,7 +1874,6 @@ def __compute_codomain_via_velu(self): """ return compute_codomain_formula(self._domain, self.__v, self.__w) - @staticmethod def __velu_sum_helper(xQ, Qvalues, a1, a3, x, y): r""" @@ -1885,7 +1922,6 @@ def __velu_sum_helper(xQ, Qvalues, a1, a3, x, y): return tX, tY - def __compute_via_velu_numeric(self, xP, yP): r""" Private function that sorts the list of points in the kernel @@ -1915,7 +1951,6 @@ def __compute_via_velu_numeric(self, xP, yP): return self.__compute_via_velu(xP,yP) - def __compute_via_velu(self, xP, yP): r""" Private function for Vélu's formulas, to perform the summation. @@ -1981,7 +2016,6 @@ def __compute_via_velu(self, xP, yP): return X, Y - def __initialize_rational_maps_via_velu(self): r""" Private function for Vélu's formulas, helper function to @@ -2003,7 +2037,6 @@ def __initialize_rational_maps_via_velu(self): y = self.__mpoly_ring.gen(1) return self.__compute_via_velu(x,y) - def __init_kernel_polynomial_velu(self): r""" Private function for Vélu's formulas, helper function to @@ -2033,7 +2066,6 @@ def __init_kernel_polynomial_velu(self): self.__kernel_polynomial = psi - ################################### # Kohel's Variant of Velu's Formula ################################### @@ -2225,7 +2257,6 @@ def __init_even_kernel_polynomial(self, E, psi_G): return phi, omega, v, w, n, d - def __init_odd_kernel_polynomial(self, E, psi): r""" Return the isogeny parameters for a cyclic isogeny of odd degree. @@ -2326,7 +2357,6 @@ def __init_odd_kernel_polynomial(self, E, psi): return phi, omega, v, w, n, d - # # This is the fast omega computation that works when characteristic is not 2 # @@ -2655,36 +2685,6 @@ def scaling_factor(self): sc *= self.__post_isomorphism.scaling_factor() return sc - def as_morphism(self): - r""" - Return this isogeny as a morphism of projective schemes. - - EXAMPLES:: - - sage: k = GF(11) - sage: E = EllipticCurve(k, [1,1]) - sage: Q = E(6,5) - sage: phi = E.isogeny(Q) - sage: mor = phi.as_morphism() - sage: mor.domain() == E - True - sage: mor.codomain() == phi.codomain() - True - sage: mor(Q) == phi(Q) - True - - TESTS:: - - sage: mor(0*Q) - (0 : 1 : 0) - sage: mor(1*Q) - (0 : 1 : 0) - """ - from sage.schemes.curves.constructor import Curve - X_affine = Curve(self.domain()).affine_patch(2) - Y_affine = Curve(self.codomain()).affine_patch(2) - return X_affine.hom(self.rational_maps(), Y_affine).homogenize(2) - def kernel_polynomial(self): r""" Return the kernel polynomial of this isogeny. @@ -2716,76 +2716,6 @@ def kernel_polynomial(self): return self.__kernel_polynomial - def set_pre_isomorphism(self, preWI): - r""" - Modify this isogeny by precomposing with a Weierstrass isomorphism. - - .. WARNING:: - - Isogenies will be immutable in a future release of Sage. - This method is deprecated in favor of using the ``*`` operator - to compose elliptic-curve morphisms. - - EXAMPLES:: - - sage: E = EllipticCurve(GF(31), [1,1,0,1,-1]) - sage: R. = GF(31)[] - sage: f = x^3 + 9*x^2 + x + 30 - sage: phi = EllipticCurveIsogeny(E, f) - sage: Epr = E.short_weierstrass_model() - sage: isom = Epr.isomorphism_to(E) - sage: phi.set_pre_isomorphism(isom) - ... - sage: phi.rational_maps() - ((-6*x^4 - 3*x^3 + 12*x^2 + 10*x - 1)/(x^3 + x - 12), (3*x^7 + x^6*y - 14*x^6 - 3*x^5 + 5*x^4*y + 7*x^4 + 8*x^3*y - 8*x^3 - 5*x^2*y + 5*x^2 - 14*x*y + 14*x - 6*y - 6)/(x^6 + 2*x^4 + 7*x^3 + x^2 + 7*x - 11)) - sage: phi(Epr((0,22))) - (13 : 21 : 1) - sage: phi(Epr((3,7))) - (14 : 17 : 1) - - sage: E = EllipticCurve(GF(29), [0,0,0,1,0]) - sage: R. = GF(29)[] - sage: f = x^2 + 5 - sage: phi = EllipticCurveIsogeny(E, f) - sage: phi - Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 29 to Elliptic Curve defined by y^2 = x^3 + 20*x over Finite Field of size 29 - sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: inv_isom = WeierstrassIsomorphism(E, (1,-2,5,10)) - sage: Epr = inv_isom.codomain() - sage: isom = Epr.isomorphism_to(E) - sage: phi.set_pre_isomorphism(isom) - ... - sage: phi - Isogeny of degree 5 from Elliptic Curve defined by y^2 + 10*x*y + 20*y = x^3 + 27*x^2 + 6 over Finite Field of size 29 to Elliptic Curve defined by y^2 = x^3 + 20*x over Finite Field of size 29 - sage: phi(Epr((12,1))) - (26 : 0 : 1) - sage: phi(Epr((2,9))) - (0 : 0 : 1) - sage: phi(Epr((21,12))) - (3 : 0 : 1) - sage: phi.rational_maps()[0] - (x^5 - 10*x^4 - 6*x^3 - 7*x^2 - x + 3)/(x^4 - 8*x^3 + 5*x^2 - 14*x - 6) - - sage: E = EllipticCurve('11a1') - sage: R. = QQ[] - sage: f = x^2 - 21*x + 80 - sage: phi = EllipticCurveIsogeny(E, f); phi - Isogeny of degree 5 from Elliptic Curve defined by y^2 + y = x^3 - x^2 - 10*x - 20 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field - sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: Epr = E.short_weierstrass_model() - sage: isom = Epr.isomorphism_to(E) - sage: phi.set_pre_isomorphism(isom) - ... - sage: phi - Isogeny of degree 5 from Elliptic Curve defined by y^2 = x^3 - 13392*x - 1080432 over Rational Field to Elliptic Curve defined by y^2 + y = x^3 - x^2 - 7820*x - 263580 over Rational Field - sage: phi(Epr((168,1188))) - (0 : 1 : 0) - """ - from sage.misc.superseded import deprecation - deprecation(32388, 'Elliptic-curve isogenies will be immutable in a future release of Sage.' - ' Use phi*psi instead of phi.set_pre_isomorphism(psi) to obtain the composite isogeny.') - return self._set_pre_isomorphism(preWI) - def _set_pre_isomorphism(self, preWI): """ Modify this isogeny by pre-composing with a @@ -2793,9 +2723,7 @@ def _set_pre_isomorphism(self, preWI): For internal use only. - TESTS: - - These tests were copied from :meth:`set_pre_isomorphism`:: + TESTS:: sage: E = EllipticCurve(GF(31), [1,1,0,1,-1]) sage: R. = GF(31)[] @@ -2868,58 +2796,6 @@ def _set_pre_isomorphism(self, preWI): self.__set_pre_isomorphism(domain, isom) - def set_post_isomorphism(self, postWI): - r""" - Modify this isogeny by postcomposing with a Weierstrass isomorphism. - - .. WARNING:: - - Isogenies will be immutable in a future release of Sage. - This method is deprecated in favor of using the ``*`` operator - to compose elliptic-curve morphisms. - - EXAMPLES:: - - sage: E = EllipticCurve(j=GF(31)(0)) - sage: R. = GF(31)[] - sage: phi = EllipticCurveIsogeny(E, x+18) - sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: phi.set_post_isomorphism(WeierstrassIsomorphism(phi.codomain(), (6,8,10,12))) - ... - sage: phi - Isogeny of degree 3 from Elliptic Curve defined by y^2 = x^3 + 1 over Finite Field of size 31 to Elliptic Curve defined by y^2 + 24*x*y + 7*y = x^3 + 22*x^2 + 16*x + 20 over Finite Field of size 31 - - sage: E = EllipticCurve(j=GF(47)(0)) - sage: f = E.torsion_polynomial(3)/3 - sage: phi = EllipticCurveIsogeny(E, f) - sage: E2 = phi.codomain() - sage: post_isom = E2.isomorphism_to(E) - sage: phi.set_post_isomorphism(post_isom) - ... - sage: phi.rational_maps() == E.multiplication_by_m(3) - False - sage: phi.switch_sign() - ... - sage: phi.rational_maps() == E.multiplication_by_m(3) - True - - Example over a number field:: - - sage: R. = QQ[] - sage: K. = NumberField(x^2 + 2) - sage: E = EllipticCurve(j=K(1728)) - sage: ker_list = E.torsion_points() - sage: phi = EllipticCurveIsogeny(E, ker_list) - sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: post_isom = WeierstrassIsomorphism(phi.codomain(), (a,2,3,5)) - sage: phi - Isogeny of degree 4 from Elliptic Curve defined by y^2 = x^3 + x over Number Field in a with defining polynomial x^2 + 2 to Elliptic Curve defined by y^2 = x^3 + (-44)*x + 112 over Number Field in a with defining polynomial x^2 + 2 - """ - from sage.misc.superseded import deprecation - deprecation(32388, 'Elliptic-curve isogenies will be immutable in a future release of Sage.' - ' Use psi*phi instead of phi.set_post_isomorphism(psi) to obtain the composite isogeny.') - return self._set_post_isomorphism(postWI) - def _set_post_isomorphism(self, postWI): """ Modify this isogeny by post-composing with a @@ -2927,9 +2803,7 @@ def _set_post_isomorphism(self, postWI): For internal use only. - TESTS: - - These tests were copied from :meth:`set_post_isomorphism`:: + TESTS:: sage: E = EllipticCurve(j=GF(31)(0)) sage: R. = GF(31)[] @@ -2982,150 +2856,6 @@ def _set_post_isomorphism(self, postWI): self.__set_post_isomorphism(codomain, isom) - def get_pre_isomorphism(self): - r""" - Return the pre-isomorphism of this isogeny, or ``None``. - - .. NOTE:: - - Pre- and post-isomorphisms are an implementation detail of - how isogenies are currently represented in Sage. They have - limited inherent mathematical meaning and this method may - disappear in a future release. - - EXAMPLES:: - - sage: E = EllipticCurve(GF(31), [1,1,0,1,-1]) - sage: R. = GF(31)[] - sage: f = x^3 + 9*x^2 + x + 30 - sage: phi = EllipticCurveIsogeny(E, f) - sage: phi.get_post_isomorphism() - sage: Epr = E.short_weierstrass_model() - sage: isom = Epr.isomorphism_to(E) - sage: phi.set_pre_isomorphism(isom) - ... - sage: isom == phi.get_pre_isomorphism() - True - - sage: E = EllipticCurve(GF(83), [1,0,1,1,0]) - sage: R. = GF(83)[]; f = x+24 - sage: phi = EllipticCurveIsogeny(E, f) - sage: E2 = phi.codomain() - sage: phi2 = EllipticCurveIsogeny(E, None, E2, 2) - sage: phi2.get_pre_isomorphism() - Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x over Finite Field of size 83 - To: Elliptic Curve defined by y^2 = x^3 + 62*x + 74 over Finite Field of size 83 - Via: (u,r,s,t) = (1, 76, 41, 3) - """ - return self.__pre_isomorphism - - def get_post_isomorphism(self): - r""" - Return the post-isomorphism of this isogeny, or ``None``. - - .. NOTE:: - - Pre- and post-isomorphisms are an implementation detail of - how isogenies are currently represented in Sage. They have - limited inherent mathematical meaning and this method may - disappear in a future release. - - EXAMPLES:: - - sage: E = EllipticCurve(j=GF(31)(0)) - sage: R. = GF(31)[] - sage: phi = EllipticCurveIsogeny(E, x+18) - sage: phi.get_post_isomorphism() - sage: from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism - sage: isom = WeierstrassIsomorphism(phi.codomain(), (6,8,10,12)) - sage: phi.set_post_isomorphism(isom) - ... - sage: isom == phi.get_post_isomorphism() - True - - sage: E = EllipticCurve(GF(83), [1,0,1,1,0]) - sage: R. = GF(83)[]; f = x+24 - sage: phi = EllipticCurveIsogeny(E, f) - sage: E2 = phi.codomain() - sage: phi2 = EllipticCurveIsogeny(E, None, E2, 2) - sage: phi2.get_post_isomorphism() - Elliptic-curve morphism: - From: Elliptic Curve defined by y^2 = x^3 + 65*x + 69 over Finite Field of size 83 - To: Elliptic Curve defined by y^2 + x*y + y = x^3 + 4*x + 16 over Finite Field of size 83 - Via: (u,r,s,t) = (1, 7, 42, 42) - """ - return self.__post_isomorphism - - - def switch_sign(self): - r""" - Compose this isogeny with `[-1]` (negation). - - .. WARNING:: - - Isogenies will be immutable in a future version of Sage. - This method is deprecated in favor of using the unary ``-`` - operator to negate elliptic-curve morphisms. - - EXAMPLES:: - - sage: E = EllipticCurve(GF(23), [0,0,0,1,0]) - sage: f = E.torsion_polynomial(3)/3 - sage: phi = EllipticCurveIsogeny(E, f, E) - sage: phi.rational_maps() == E.multiplication_by_m(3) - False - sage: phi.switch_sign() - ... - sage: phi.rational_maps() == E.multiplication_by_m(3) - True - - sage: E = EllipticCurve(GF(17), [-2, 3, -5, 7, -11]) - sage: R. = GF(17)[] - sage: f = x+6 - sage: phi = EllipticCurveIsogeny(E, f) - sage: phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 7*x + 6 over Finite Field of size 17 to Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 4*x + 8 over Finite Field of size 17 - sage: phi.rational_maps() - ((x^2 + 6*x + 4)/(x + 6), (x^2*y - 5*x*y + 8*x - 2*y)/(x^2 - 5*x + 2)) - sage: phi.switch_sign() - ... - sage: phi - Isogeny of degree 2 from Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 7*x + 6 over Finite Field of size 17 to Elliptic Curve defined by y^2 + 15*x*y + 12*y = x^3 + 3*x^2 + 4*x + 8 over Finite Field of size 17 - sage: phi.rational_maps() - ((x^2 + 6*x + 4)/(x + 6), - (2*x^3 - x^2*y - 5*x^2 + 5*x*y - 4*x + 2*y + 7)/(x^2 - 5*x + 2)) - - sage: E = EllipticCurve('11a1') - sage: R. = QQ[] - sage: f = x^2 - 21*x + 80 - sage: phi = EllipticCurveIsogeny(E, f) - sage: (xmap1, ymap1) = phi.rational_maps() - sage: phi.switch_sign() - ... - sage: (xmap2, ymap2) = phi.rational_maps() - sage: xmap1 == xmap2 - True - sage: ymap1 == -ymap2 - E.a1()*xmap2 - E.a3() - True - - sage: K. = NumberField(x^2 + 1) - sage: E = EllipticCurve(K, [0,0,0,1,0]) - sage: R. = K[] - sage: phi = EllipticCurveIsogeny(E, x-a) - sage: phi.rational_maps() - ((x^2 + (-a)*x - 2)/(x + (-a)), (x^2*y + (-2*a)*x*y + y)/(x^2 + (-2*a)*x - 1)) - sage: phi.switch_sign() - ... - sage: phi.rational_maps() - ((x^2 + (-a)*x - 2)/(x + (-a)), (-x^2*y + (2*a)*x*y - y)/(x^2 + (-2*a)*x - 1)) - """ - from sage.misc.superseded import deprecation - deprecation(32388, 'Elliptic-curve isogenies will be immutable in a future release of Sage.' - ' Use -phi instead of phi.switch_sign() to obtain the negated isogeny.') - E2 = self._codomain - self._set_post_isomorphism(WeierstrassIsomorphism(E2, (-1, 0, -E2.a1(), -E2.a3()))) - def dual(self): r""" Return the isogeny dual to this isogeny. @@ -3479,7 +3209,6 @@ def split_kernel_polynomial(poly): from sage.misc.misc_c import prod return prod([p for p,e in poly.squarefree_decomposition()]) - def compute_isogeny_kernel_polynomial(E1, E2, ell, algorithm="starks"): r""" Return the kernel polynomial of an isogeny of degree ``ell`` @@ -3720,7 +3449,6 @@ def compute_sequence_of_maps(E1, E2, ell): return pre_isom, post_isom, E1pr, E2pr, ker_poly - # Utility functions for manipulating isogeny degree matrices def fill_isogeny_matrix(M): 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/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index 926ae310ea8..154a581bc2a 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -1918,9 +1918,9 @@ def division_polynomial(self, m, x=None, two_torsion_multiplicity=2, force_evalu and x.lift().base_ring() is self.base_ring(): d = x.parent().modulus().degree() evaluate = m < 220 or \ - (d < 10 and m < 420) or (d < 15 and m < 340) or \ - (d < 30 and m < 280) or (d < 100 and m < 250) or \ - m <= min(250, d) + (d < 10 and m < 420) or (d < 15 and m < 340) or \ + (d < 30 and m < 280) or (d < 100 and m < 250) or \ + m <= min(250, d) # Check if we should (attempt to) compute the result by simply # evaluating a cached polynomial at the given input. @@ -2849,7 +2849,7 @@ def montgomery_model(self, twisted=False, morphism=False): return E, self.isomorphism_to(E) return E - P2, (x,y,z) = self.ambient_space().objgens() + P2, (x, y, z) = self.ambient_space().objgens() f = B * y**2*z - x * (x * (x + A*z) + z**2) C = plane_curve.ProjectivePlaneCurve(P2, f) @@ -2857,8 +2857,8 @@ def montgomery_model(self, twisted=False, morphism=False): return C t = ~(B * s).sqrt() - iso_maps = (x - r * z, t * y , s * z) - inv_maps = (x * s + r * z, s * y/t, z) + iso_maps = (x - r * z, t * y, s * z) + inv_maps = (x * s + r * z, s * y / t, z) w = self.isomorphism_to(Ew) wmap, winv = w.rational_maps(), (~w).rational_maps() @@ -2868,7 +2868,7 @@ def montgomery_model(self, twisted=False, morphism=False): inv = [f(*inv_maps) for f in winv] from sage.schemes.elliptic_curves.weierstrass_transform \ - import WeierstrassTransformationWithInverse as WTI + import WeierstrassTransformationWithInverse as WTI iso = WTI(self, C, iso, 1, inv, s**-3) return C, iso @@ -3194,7 +3194,7 @@ def _p_primary_torsion_basis(self, p, m=None): k = 1 log_order = 2 if m <= log_order: - return [[P1,1],[P2,1]] + return [[P1, 1], [P2, 1]] pts1 = P1.division_points(p) pts2 = P2.division_points(p) @@ -3255,7 +3255,7 @@ def _p_primary_torsion_basis(self, p, m=None): return [[P1, n], [P2, k]] pts = P1.division_points(p) if not pts: - for Q in generic.multiples(P2,p-1,P1+P2,operation='+'): + for Q in generic.multiples(P2, p-1, P1+P2, operation='+'): # Q runs through P1+a*P2 for a=1,2,...,p-1 pts = Q.division_points(p) if pts: diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 9c9038e0eb5..98c0dee32c7 100644 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -523,7 +523,7 @@ def __bool__(self): """ return bool(self[2]) - + def has_finite_order(self): """ diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index 2b699fd6cf8..298f44fedc6 100644 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -117,7 +117,7 @@ from sage.modular.modsym.p1list import P1List -################################################################################## +############################################################################### # # The exported functions, which are in most cases enough to get the # user going working with Heegner points: @@ -125,7 +125,7 @@ # heegner_points -- all of them with given level, discriminant, conductor # heegner_point -- a specific one # -################################################################################## +############################################################################### def heegner_points(N, D=None, c=None): """ @@ -135,11 +135,11 @@ def heegner_points(N, D=None, c=None): INPUT: - - `N` -- level (positive integer) + - `N` -- level (positive integer) - - `D` -- discriminant (negative integer) + - `D` -- discriminant (negative integer) - - `c` -- conductor (positive integer) + - `c` -- conductor (positive integer) EXAMPLES:: @@ -155,9 +155,10 @@ def heegner_points(N, D=None, c=None): if D is not None and c is None: return HeegnerPoints_level_disc(N, D) if D is not None and c is not None: - return HeegnerPoints_level_disc_cond(N,D,c) + return HeegnerPoints_level_disc_cond(N, D, c) raise TypeError + def heegner_point(N, D=None, c=1): """ Return a specific Heegner point of level `N` with given @@ -167,11 +168,11 @@ def heegner_point(N, D=None, c=1): INPUT: - - `N` -- level (positive integer) + - `N` -- level (positive integer) - - `D` -- discriminant (optional: default first valid `D`) + - `D` -- discriminant (optional: default first valid `D`) - - `c` -- conductor (positive integer, optional, default: 1) + - `c` -- conductor (positive integer, optional, default: 1) EXAMPLES:: @@ -185,20 +186,20 @@ def heegner_point(N, D=None, c=1): Heegner point 1/778*sqrt(-20) - 165/389 of discriminant -20 on X_0(389) """ if D is not None: - return heegner_points(N,D,c)[0] + return heegner_points(N, D, c)[0] H = heegner_points(N) D = H.discriminants(1)[0] - return heegner_points(N,D,c)[0] + return heegner_points(N, D, c)[0] -################################################################################## +############################################################################### # # Ring class fields, represented as abstract objects. These do not # derive from number fields, since we do not need to work with their # elements, and explicitly representing them as number fields would be # far too difficult. # -################################################################################## +############################################################################### class RingClassField(SageObject): """ @@ -352,9 +353,8 @@ def _repr_(self): """ c = self.__c if c == 1: - return "Hilbert class field of QQ[sqrt(%s)]"%self.__D - else: - return "Ring class field extension of QQ[sqrt(%s)] of conductor %s"%(self.__D, self.__c) + return "Hilbert class field of QQ[sqrt(%s)]" % self.__D + return "Ring class field extension of QQ[sqrt(%s)] of conductor %s" % (self.__D, self.__c) @cached_method def degree_over_K(self): @@ -6533,7 +6533,8 @@ def heegner_point_height(self, D, prec=2, check_rank=True): return IR(alpha-MIN_ERR,alpha+MIN_ERR) * IR(LE1-err_E,LE1+err_E) * IR(LF1-err_F,LF1+err_F) -def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, verbose_mwrank=False, check_rank=True): +def heegner_index(self, D, min_p=2, prec=5, descent_second_limit=12, + verbose_mwrank=False, check_rank=True): r""" Return an interval that contains the index of the Heegner point `y_K` in the group of `K`-rational points modulo torsion @@ -6745,7 +6746,7 @@ def _adjust_heegner_index(self, a): return a.sqrt() -def heegner_index_bound(self, D=0, prec=5, max_height=None): +def heegner_index_bound(self, D=0, prec=5, max_height=None): r""" Assume ``self`` has rank 0. diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py index 8d707e8e6b7..bdf2c969079 100644 --- a/src/sage/schemes/elliptic_curves/hom.py +++ b/src/sage/schemes/elliptic_curves/hom.py @@ -20,7 +20,6 @@ - Lorenz Panny (2021): Refactor isogenies and isomorphisms into the common :class:`EllipticCurveHom` interface. """ - from sage.misc.cachefunc import cached_method from sage.structure.richcmp import richcmp_not_equal, richcmp, op_EQ, op_NE @@ -75,12 +74,9 @@ def _composition_(self, other, homset): sage: phi * iso Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 9*x over Finite Field of size 19 to Elliptic Curve defined by y^2 = x^3 + 15*x over Finite Field of size 19 sage: phi.dual() * phi - Composite map: + Composite morphism of degree 4 = 2^2: From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19 To: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19 - Defn: Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19 to Elliptic Curve defined by y^2 = x^3 + 15*x over Finite Field of size 19 - then - Isogeny of degree 2 from Elliptic Curve defined by y^2 = x^3 + 15*x over Finite Field of size 19 to Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 19 """ if not isinstance(self, EllipticCurveHom) or not isinstance(other, EllipticCurveHom): raise TypeError(f'cannot compose {type(self)} with {type(other)}') @@ -93,9 +89,8 @@ def _composition_(self, other, homset): if ret is not NotImplemented: return ret - # fall back to generic formal composite map - return Morphism._composition_(self, other, homset) - + from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite + return EllipticCurveHom_composite.from_factors([other, self]) @staticmethod def _comparison_impl(left, right, op): @@ -197,7 +192,6 @@ def _richcmp_(self, other, op): return richcmp(self.rational_maps(), other.rational_maps(), op) - def degree(self): r""" Return the degree of this elliptic-curve morphism. @@ -221,7 +215,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) @@ -331,11 +324,10 @@ def x_rational_map(self): ... NotImplementedError: ... """ - #TODO: could have a default implementation that simply - # returns the first component of rational_maps() + # TODO: could have a default implementation that simply + # returns the first component of rational_maps() raise NotImplementedError('children must implement') - def scaling_factor(self): r""" Return the Weierstrass scaling factor associated to this @@ -361,9 +353,9 @@ def scaling_factor(self): ... NotImplementedError: ... """ - #TODO: could have a default implementation that simply - # returns .formal()[1], but it seems safer to fail - # visibly to make sure we would notice regressions + # TODO: could have a default implementation that simply + # returns .formal()[1], but it seems safer to fail + # visibly to make sure we would notice regressions raise NotImplementedError('children must implement') def formal(self, prec=20): @@ -413,7 +405,6 @@ def formal(self, prec=20): assert th.valuation() == +1, f"th has valuation {th.valuation()} (should be +1)" return th - def is_normalized(self): r""" Determine whether this morphism is a normalized isogeny. @@ -493,7 +484,6 @@ def is_normalized(self): """ return self.scaling_factor() == 1 - def is_separable(self): r""" Determine whether or not this morphism is separable. @@ -586,7 +576,7 @@ def is_injective(self): True """ if not self.is_separable(): - #TODO: should implement .separable_degree() or similar + # TODO: should implement .separable_degree() or similar raise NotImplementedError return self.degree() == 1 @@ -661,6 +651,36 @@ def __hash__(self): """ return hash((self.domain(), self.codomain(), self.kernel_polynomial())) + def as_morphism(self): + r""" + Return ``self`` as a morphism of projective schemes. + + EXAMPLES:: + + sage: k = GF(11) + sage: E = EllipticCurve(k, [1,1]) + sage: Q = E(6,5) + sage: phi = E.isogeny(Q) + sage: mor = phi.as_morphism() + sage: mor.domain() == E + True + sage: mor.codomain() == phi.codomain() + True + sage: mor(Q) == phi(Q) + True + + TESTS:: + + sage: mor(0*Q) + (0 : 1 : 0) + sage: mor(1*Q) + (0 : 1 : 0) + """ + from sage.schemes.curves.constructor import Curve + X_affine = Curve(self.domain()).affine_patch(2) + Y_affine = Curve(self.codomain()).affine_patch(2) + return X_affine.hom(self.rational_maps(), Y_affine).homogenize(2) + def compare_via_evaluation(left, right): r""" @@ -713,11 +733,10 @@ 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) - elif isinstance(F, number_field_base.NumberField): for _ in range(100): P = E.lift_x(F.random_element(), extend=True) @@ -725,7 +744,5 @@ def compare_via_evaluation(left, right): return left._eval(P) == right._eval(P) else: assert False, "couldn't find a point of infinite order" - 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..b2096eda5b8 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 @@ -32,7 +24,9 @@ sage: EllipticCurveHom_composite(E, P) Composite morphism of degree 11150372599265311570767859136324180752990208 = 2^143: From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2 - To: Elliptic Curve defined by y^2 = x^3 + (18676616716352953484576727486205473216172067*z2+32690199585974925193292786311814241821808308)*x + (3369702436351367403910078877591946300201903*z2+15227558615699041241851978605002704626689722) over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2 + To: Elliptic Curve defined by y^2 = x^3 + (18676616716352953484576727486205473216172067*z2+32690199585974925193292786311814241821808308)*x + + (3369702436351367403910078877591946300201903*z2+15227558615699041241851978605002704626689722) + over Finite Field in z2 of size 33451117797795934712303577408972542258970623^2 Yet, the interface provided by :class:`EllipticCurveHom_composite` is identical to :class:`EllipticCurveIsogeny` and other instantiations @@ -48,10 +42,15 @@ sage: psi(E.lift_x(11)) (352 : 73 : 1) sage: psi.rational_maps() - ((x^35 + 162*x^34 + 186*x^33 + 92*x^32 - ... + 44*x^3 + 190*x^2 + 80*x - 72)/(x^34 + 162*x^33 - 129*x^32 + 41*x^31 + ... + 66*x^3 - 191*x^2 + 119*x + 21), - (x^51*y - 176*x^50*y + 115*x^49*y - 120*x^48*y + ... + 72*x^3*y + 129*x^2*y + 163*x*y + 178*y)/(x^51 - 176*x^50 + 11*x^49 + 26*x^48 - ... - 77*x^3 + 185*x^2 + 169*x - 128)) + ((x^35 + 162*x^34 + 186*x^33 + 92*x^32 - ... + 44*x^3 + 190*x^2 + 80*x - + 72)/(x^34 + 162*x^33 - 129*x^32 + 41*x^31 + ... + 66*x^3 - 191*x^2 + 119*x + + 21), (x^51*y - 176*x^50*y + 115*x^49*y - 120*x^48*y + ... + 72*x^3*y + + 129*x^2*y + 163*x*y + 178*y)/(x^51 - 176*x^50 + 11*x^49 + 26*x^48 - ... - + 77*x^3 + 185*x^2 + 169*x - 128)) sage: psi.kernel_polynomial() - x^17 + 81*x^16 + 7*x^15 + 82*x^14 + 49*x^13 + 68*x^12 + 109*x^11 + 326*x^10 + 117*x^9 + 136*x^8 + 111*x^7 + 292*x^6 + 55*x^5 + 389*x^4 + 175*x^3 + 43*x^2 + 149*x + 373 + x^17 + 81*x^16 + 7*x^15 + 82*x^14 + 49*x^13 + 68*x^12 + 109*x^11 + 326*x^10 + + 117*x^9 + 136*x^8 + 111*x^7 + 292*x^6 + 55*x^5 + 389*x^4 + 175*x^3 + + 43*x^2 + 149*x + 373 sage: psi.dual() Composite morphism of degree 35 = 7*5: From: Elliptic Curve defined by y^2 = x^3 + 101*x + 285 over Finite Field of size 419 @@ -90,10 +89,8 @@ 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) -#TODO: implement sparse strategies? (cf. the SIKE cryptosystem) def _eval_factored_isogeny(phis, P): """ @@ -119,6 +116,7 @@ def _eval_factored_isogeny(phis, P): P = phi(P) return P + def _compute_factored_isogeny_prime_power(P, l, e): """ This method takes a point `P` of order `l^e` and returns @@ -147,6 +145,7 @@ def _compute_factored_isogeny_prime_power(P, l, e): phis.append(phi) return phis + def _compute_factored_isogeny_single_generator(P): """ This method takes a point `P` and returns a sequence of @@ -173,6 +172,7 @@ def _compute_factored_isogeny_single_generator(P): phis += psis return phis + def _compute_factored_isogeny(kernel): """ This method takes a set of points on an elliptic curve @@ -199,6 +199,7 @@ def _compute_factored_isogeny(kernel): phis += psis return phis + class EllipticCurveHom_composite(EllipticCurveHom): _degree = None @@ -479,7 +480,6 @@ def factors(self): """ return self._phis - # EllipticCurveHom methods @staticmethod @@ -517,14 +517,14 @@ def _composition_impl(left, right): To: Elliptic Curve defined by y^2 + (I+1)*x*y = x^3 + I*x^2 + (-4)*x + (-6*I) over Number Field in I with defining polynomial x^2 + 1 with I = 1*I """ if isinstance(left, EllipticCurveHom_composite): - if isinstance(right, WeierstrassIsomorphism) and hasattr(left.factors()[0], '_set_pre_isomorphism'): #XXX bit of a hack + if isinstance(right, WeierstrassIsomorphism) and hasattr(left.factors()[0], '_set_pre_isomorphism'): # XXX bit of a hack return EllipticCurveHom_composite.from_factors((left.factors()[0] * right,) + left.factors()[1:], strict=False) if isinstance(right, EllipticCurveHom_composite): return EllipticCurveHom_composite.from_factors(right.factors() + left.factors()) if isinstance(right, EllipticCurveHom): return EllipticCurveHom_composite.from_factors((right,) + left.factors()) if isinstance(right, EllipticCurveHom_composite): - if isinstance(left, WeierstrassIsomorphism) and hasattr(right.factors()[-1], '_set_post_isomorphism'): #XXX bit of a hack + if isinstance(left, WeierstrassIsomorphism) and hasattr(right.factors()[-1], '_set_post_isomorphism'): # XXX bit of a hack return EllipticCurveHom_composite.from_factors(right.factors()[:-1] + (left * right.factors()[-1],), strict=False) if isinstance(left, EllipticCurveHom): return EllipticCurveHom_composite.from_factors(right.factors() + (left,)) @@ -776,52 +776,19 @@ def is_injective(self): """ return all(phi.is_injective() for phi in self._phis) - @staticmethod def make_default(): r""" - Calling this method will override the composition method - of :class:`EllipticCurveHom` such that it constructs a - :class:`EllipticCurveHom_composite` object by default, - rather than a :class:`sage.categories.map.FormalCompositeMap`. - - .. WARNING:: + This method does nothing and will be removed. - This method exists only temporarily to make testing more - convenient while :class:`EllipticCurveHom_composite` is - experimental. + (It is a leftover from the time when :class:`EllipticCurveHom_composite` + wasn't the default yet.) EXAMPLES:: sage: from sage.schemes.elliptic_curves.hom_composite import EllipticCurveHom_composite - sage: E = EllipticCurve(GF(587), [1,0]) - sage: P = E(3,404) - sage: phi = E.isogeny(7*P) - sage: psi = phi.codomain().isogeny(phi(P)) - sage: psi * phi - Composite map: - From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 587 - To: Elliptic Curve defined by y^2 = x^3 + 296*x + 164 over Finite Field of size 587 - Defn: Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 587 to Elliptic Curve defined by y^2 = x^3 + 126*x + 500 over Finite Field of size 587 - then - Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 126*x + 500 over Finite Field of size 587 to Elliptic Curve defined by y^2 = x^3 + 296*x + 164 over Finite Field of size 587 sage: EllipticCurveHom_composite.make_default() - sage: psi * phi - Composite morphism of degree 49 = 7^2: - From: Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 587 - To: Elliptic Curve defined by y^2 = x^3 + 296*x + 164 over Finite Field of size 587 - sage: (psi * phi).factors() - (Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + x over Finite Field of size 587 to Elliptic Curve defined by y^2 = x^3 + 126*x + 500 over Finite Field of size 587, - Isogeny of degree 7 from Elliptic Curve defined by y^2 = x^3 + 126*x + 500 over Finite Field of size 587 to Elliptic Curve defined by y^2 = x^3 + 296*x + 164 over Finite Field of size 587) + doctest:warning ... """ - def _composition_(self, other, homset): - if not isinstance(self, EllipticCurveHom) or not isinstance(other, EllipticCurveHom): - raise TypeError(f'cannot compose {type(self)} with {type(other)}') - ret = self._composition_impl(self, other) - if ret is not NotImplemented: - return ret - ret = other._composition_impl(self, other) - if ret is not NotImplemented: - return ret - return EllipticCurveHom_composite.from_factors([other, self]) - EllipticCurveHom._composition_ = _composition_ + from sage.misc.superseded import deprecation + deprecation(34410, 'calling EllipticCurveHom_composite.make_default() is no longer necessary') diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index 20688dbb4d0..144b5400970 100644 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -1,23 +1,18 @@ r""" -√élu Algorithm for Elliptic-Curve Isogenies - -The √élu algorithm computes isogenies of elliptic curves in time -`\tilde O(\sqrt\ell)` rather than naïvely `O(\ell)`, where `\ell` -is the degree. - -The core idea is to reindex the points in the kernel subgroup in -a baby-step-giant-step manner, then use fast resultant computations -to evaluate "elliptic polynomials" -(see :class:`FastEllipticPolynomial`) -in essentially square-root time. - -Based on experiments with Sage version 9.7, -the isogeny degree where -:class:`EllipticCurveHom_velusqrt` -begins to outperform +√élu algorithm for elliptic-curve isogenies + +The √élu algorithm computes isogenies of elliptic curves in time `\tilde +O(\sqrt\ell)` rather than naïvely `O(\ell)`, where `\ell` is the degree. + +The core idea is to reindex the points in the kernel subgroup in a +baby-step-giant-step manner, then use fast resultant computations to evaluate +"elliptic polynomials" (see :class:`FastEllipticPolynomial`) in essentially +square-root time. + +Based on experiments with Sage version 9.7, the isogeny degree where +:class:`EllipticCurveHom_velusqrt` begins to outperform :class:`~sage.schemes.elliptic_curves.ell_curve_isogeny.EllipticCurveIsogeny` -can be as low as `\approx 100`, -but is typically closer to `\approx 1000`, +can be as low as `\approx 100`, but is typically closer to `\approx 1000`, depending on the exact situation. REFERENCES: [BDLS2020]_ @@ -106,9 +101,11 @@ .. NOTE:: - Currently :class:`EllipticCurveHom_velusqrt` does not implement - all methods of :class:`EllipticCurveHom`. This will hopefully - change in the future. + Some of the methods inherited from :class:`EllipticCurveHom` compute data + whose size is linear in the degree; this includes kernel polynomial and + rational maps. In consequence, those methods cannot possibly run in the + otherwise advertised square-root complexity, as merely storing the result + already takes linear time. AUTHORS: @@ -128,6 +125,8 @@ from sage.structure.sequence import Sequence from sage.structure.all import coercion_model as cm +from sage.misc.cachefunc import cached_method + from sage.misc.misc_c import prod from sage.structure.richcmp import op_EQ @@ -139,7 +138,7 @@ from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation -#TODO: This is general. It should be elsewhere. +# TODO: This is general. It should be elsewhere. class ProductTree: r""" A simple product tree. @@ -268,7 +267,7 @@ def remainders(self, x): X = [X[i//2] % V[i] for i in range(len(V))] return X -#TODO: This is general. It should be elsewhere. +# TODO: This is general. It should be elsewhere. def prod_with_derivative(pairs): r""" Given a list of pairs `(f, \partial f)` of ring elements, return @@ -332,7 +331,6 @@ def __iter__(self): return tuple(prod(_aux(*tup) for tup in pairs)) - def _choose_IJK(n): r""" Helper function to choose an "index system" for the set @@ -412,6 +410,7 @@ def _points_range(rr, P, Q=None): for _ in range(a+s, b, s): yield (R := R + sP) + class FastEllipticPolynomial: r""" A class to represent and evaluate an *elliptic polynomial*, @@ -527,7 +526,7 @@ def __init__(self, E, n, P, Q=None): IJK = _choose_IJK(2*n+1) # [1,3,5,7,...,2n-1] = [0,1,2,3,...,n-2,n-1] self.base = E.base_ring() - R, Z = self.base['x'].objgen() + R, Z = self.base['Z'].objgen() # Cassels, Lectures on Elliptic Curves, p.132 A,B = E.a_invariants()[-2:] @@ -595,6 +594,7 @@ def __call__(self, alpha, *, derivative=False): R = self._hI_resultant(EJ, EJrems) hK = self.hK(alpha) res = hK * R / self.DeltaIJ + res = base(res) if not derivative: return res @@ -609,6 +609,7 @@ def __call__(self, alpha, *, derivative=False): dR = 0 dhK = self.dhK(alpha) dres = (dhK * R + hK * dR) / self.DeltaIJ + dres = base(dres) return res, dres @@ -629,7 +630,7 @@ def _hI_resultant(self, poly, rems=None): sage: E = EllipticCurve(GF(71), [5,5]) sage: P = E(4, 35) sage: hP = FastEllipticPolynomial(E, P.order(), P) - sage: f = GF(71)['x']([5,4,3,2,1]) + sage: f = GF(71)['Z']([5,4,3,2,1]) sage: hP._hI_resultant(f) 66 sage: prod(f(r) for fi in hP.hItree.layers[0] @@ -640,7 +641,7 @@ def _hI_resultant(self, poly, rems=None): sage: Q = E(0, 17) sage: hPQ = FastEllipticPolynomial(E, P.order(), P, Q) - sage: f = GF(71)['x']([9,8,7,6,5,4,3,2,1]) + sage: f = GF(71)['Z']([9,8,7,6,5,4,3,2,1]) sage: hPQ._hI_resultant(f) 36 sage: prod(f(r) for fi in hPQ.hItree.layers[0] @@ -738,7 +739,7 @@ def _point_outside_subgroup(P): F = E.base_field().extension(d) E = E.base_extend(F) P = E(P) -# assert E.cardinality() > n + # assert E.cardinality() > n for _ in range(1000): Q = E.random_point() if n*Q or not P.weil_pairing(Q,n).is_one(): @@ -746,6 +747,7 @@ def _point_outside_subgroup(P): else: raise NotImplementedError('could not find a point outside the kernel') + class EllipticCurveHom_velusqrt(EllipticCurveHom): r""" This class implements separable odd-degree isogenies of elliptic @@ -918,7 +920,7 @@ def __init__(self, E, P, *, codomain=None, model=None, Q=None): EE = self._Q.curve() self._P = EE(self._P) - self._base_ring = EE.base_ring() + self._internal_base_ring = EE.base_ring() self._h0 = FastEllipticPolynomial(EE, self._degree, self._P) self._h1 = FastEllipticPolynomial(EE, self._degree, self._P, self._Q) @@ -972,6 +974,13 @@ def _raw_eval(self, x, y=None): 50907 sage: phi._raw_eval(123, 456) (3805, 29941) + + TESTS:: + + sage: {t.parent() for t in phi._raw_eval(*Q.xy())} + {Finite Field of size 65537} + sage: {t.parent() for t in phi._raw_eval(123, 456)} + {Finite Field of size 65537} """ if y is None: h0 = self._h0(x) @@ -1041,7 +1050,7 @@ def _compute_codomain(self, model=None): From: Elliptic Curve defined by y^2 + 3*t*x*y + (3*t+2)*y = x^3 + (2*t+4)*x^2 + (t+4)*x + 3*t over Finite Field in t of size 5^2 To: Elliptic Curve defined by y^2 = x^3 + (4*t+3)*x + 2 over Finite Field in t of size 5^2 """ - R, Z = self._base_ring['Z'].objgen() + R, Z = self._internal_base_ring['Z'].objgen() poly = self._raw_domain.two_division_polynomial().monic()(Z) f = 1 @@ -1049,7 +1058,7 @@ def _compute_codomain(self, model=None): if g.degree() == 1: f *= Z - self._raw_eval(-g[0]) else: - K, X0 = self._base_ring.extension(g,'T').objgen() + K, X0 = self._internal_base_ring.extension(g,'T').objgen() imX0 = self._raw_eval(X0) try: imX0 = imX0.polynomial() # K is a FiniteField @@ -1193,6 +1202,169 @@ def _comparison_impl(left, right, op): return NotImplemented return compare_via_evaluation(left, right) + @cached_method + def kernel_polynomial(self): + r""" + Return the kernel polynomial of this √élu isogeny. + + .. NOTE:: + + The data returned by this method has size linear in the degree. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(65537^2,'a'), [5,5]) + sage: K = E.cardinality()//31 * E.gens()[0] + sage: phi = E.isogeny(K, algorithm='velusqrt') + sage: h = phi.kernel_polynomial(); h + x^15 + 21562*x^14 + 8571*x^13 + 20029*x^12 + 1775*x^11 + 60402*x^10 + 17481*x^9 + 46543*x^8 + 46519*x^7 + 18590*x^6 + 36554*x^5 + 36499*x^4 + 48857*x^3 + 3066*x^2 + 23264*x + 53937 + sage: h == E.isogeny(K).kernel_polynomial() + True + sage: h(K.xy()[0]) + 0 + + TESTS:: + + sage: phi.kernel_polynomial().parent() + Univariate Polynomial Ring in x over Finite Field in a of size 65537^2 + """ + R, x = self._domain.base_ring()['x'].objgen() + h0 = self._h0(x) + h = h0(self._pre_iso.x_rational_map()) + return R(h).monic() + + @cached_method + def dual(self): + r""" + Return the dual of this √élu isogeny as an :class:`EllipticCurveHom`. + + .. NOTE:: + + The dual is computed by :class:`EllipticCurveIsogeny`, + hence it does not benefit from the √élu speedup. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1]) + sage: K = E.cardinality() // 11 * E.gens()[0] + sage: phi = E.isogeny(K, algorithm='velusqrt'); phi + Elliptic-curve isogeny (using √élu) of degree 11: + From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2 + To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2 + sage: phi.dual() + Isogeny of degree 11 from Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2 to Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2 + sage: phi.dual() * phi == phi.domain().multiplication_by_m_isogeny(11) + True + sage: phi * phi.dual() == phi.codomain().multiplication_by_m_isogeny(11) + True + """ + # FIXME: This code fails if the degree is divisible by the characteristic. + F = self._raw_domain.base_ring() + from sage.schemes.elliptic_curves.weierstrass_morphism import WeierstrassIsomorphism + isom = ~WeierstrassIsomorphism(self._raw_domain, (~F(self._degree), 0, 0, 0)) + from sage.schemes.elliptic_curves.ell_curve_isogeny import EllipticCurveIsogeny + phi = EllipticCurveIsogeny(self._raw_codomain, None, isom.domain(), self._degree) + return ~self._pre_iso * isom * phi * ~self._post_iso + + @cached_method + def rational_maps(self): + r""" + Return the pair of explicit rational maps of this √élu isogeny + as fractions of bivariate polynomials in `x` and `y`. + + .. NOTE:: + + The data returned by this method has size linear in the degree. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1]) + sage: K = (E.cardinality() // 11) * E.gens()[0] + sage: phi = E.isogeny(K, algorithm='velusqrt'); phi + Elliptic-curve isogeny (using √élu) of degree 11: + From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2 + To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2 + sage: phi.rational_maps() + ((-17*x^11 - 34*x^10 - 36*x^9 + ... - 29*x^2 - 25*x - 25)/(x^10 + 10*x^9 + 19*x^8 - ... + x^2 + 47*x + 24), + (-3*x^16 - 6*x^15*y - 48*x^15 + ... - 49*x - 9*y + 46)/(x^15 + 15*x^14 - 35*x^13 - ... + 3*x^2 - 45*x + 47)) + + TESTS:: + + sage: phi.rational_maps()[0].parent() + Fraction Field of Multivariate Polynomial Ring in x, y over Finite Field in z2 of size 101^2 + sage: phi.rational_maps()[1].parent() + Fraction Field of Multivariate Polynomial Ring in x, y over Finite Field in z2 of size 101^2 + """ + S = self._internal_base_ring['x,y'] + fx, fy = map(S, self._pre_iso.rational_maps()) + fx, fy = self._raw_eval(fx, fy) + gx, gy = self._post_iso.rational_maps() + fx, fy = gx(fx, fy), gy(fx, fy) + R = self._domain.base_ring()['x,y'].fraction_field() + return R(fx), R(fy) + + @cached_method + def x_rational_map(self): + r""" + Return the `x`-coordinate rational map of this √élu isogeny + as a univariate rational function in `x`. + + .. NOTE:: + + The data returned by this method has size linear in the degree. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1]) + sage: K = (E.cardinality() // 11) * E.gens()[0] + sage: phi = E.isogeny(K, algorithm='velusqrt'); phi + Elliptic-curve isogeny (using √élu) of degree 11: + From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2 + To: Elliptic Curve defined by y^2 = x^3 + 39*x + 40 over Finite Field in z2 of size 101^2 + sage: phi.x_rational_map() + (84*x^11 + 67*x^10 + 65*x^9 + ... + 72*x^2 + 76*x + 76)/(x^10 + 10*x^9 + 19*x^8 + ... + x^2 + 47*x + 24) + sage: phi.x_rational_map() == phi.rational_maps()[0] + True + + TESTS:: + + sage: phi.x_rational_map().parent() + Fraction Field of Univariate Polynomial Ring in x over Finite Field in z2 of size 101^2 + """ + S = self._internal_base_ring['x'] + fx = S(self._pre_iso.x_rational_map()) + fx = self._raw_eval(fx) + gx = self._post_iso.x_rational_map() + fx = gx(fx) + R = self._domain.base_ring()['x'].fraction_field() + return R(fx) + + def scaling_factor(self): + r""" + Return the Weierstrass scaling factor associated to this + √élu isogeny. + + The scaling factor is the constant `u` (in the base field) + such that `\varphi^* \omega_2 = u \omega_1`, where + `\varphi: E_1\to E_2` is this isogeny and `\omega_i` are + the standard Weierstrass differentials on `E_i` defined by + `\mathrm dx/(2y+a_1x+a_3)`. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101^2), [1, 1, 1, 1, 1]) + sage: K = (E.cardinality() // 11) * E.gens()[0] + sage: phi = E.isogeny(K, algorithm='velusqrt', model='montgomery'); phi + Elliptic-curve isogeny (using √élu) of degree 11: + From: Elliptic Curve defined by y^2 + x*y + y = x^3 + x^2 + x + 1 over Finite Field in z2 of size 101^2 + To: Elliptic Curve defined by y^2 = x^3 + 61*x^2 + x over Finite Field in z2 of size 101^2 + sage: phi.scaling_factor() + 55 + sage: phi.scaling_factor() == phi.formal()[1] + True + """ + return self._pre_iso.scaling_factor() * self._post_iso.scaling_factor() + def _random_example_for_testing(): r""" @@ -1247,4 +1419,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/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index 8ea04812f3d..d7d45faf22b 100644 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -342,6 +342,22 @@ def ambient_space(self): """ return self.__A + def identity_morphism(self): + """ + Return the identity morphism. + + OUTPUT: the identity morphism of the scheme ``self`` + + EXAMPLES:: + + sage: X = Spec(QQ) + sage: X.identity_morphism() + Scheme endomorphism of Spectrum of Rational Field + Defn: Identity map + """ + from sage.schemes.generic.morphism import SchemeMorphism_polynomial_id + return SchemeMorphism_polynomial_id(self) + def embedding_morphism(self): r""" Return the default embedding morphism of ``self``. diff --git a/src/sage/schemes/generic/ambient_space.py b/src/sage/schemes/generic/ambient_space.py index bcf742c8b25..616f8473ead 100644 --- a/src/sage/schemes/generic/ambient_space.py +++ b/src/sage/schemes/generic/ambient_space.py @@ -279,6 +279,27 @@ def defining_polynomials(self): """ return () + def identity_morphism(self): + """ + Return the identity morphism. + + OUTPUT: the identity morphism of the scheme ``self`` + + EXAMPLES:: + + sage: A = AffineSpace(2, GF(3)) + sage: A.identity_morphism() + Scheme endomorphism of Affine Space of dimension 2 over Finite Field of size 3 + Defn: Identity map + + sage: P = ProjectiveSpace(3, ZZ) + sage: P.identity_morphism() + Scheme endomorphism of Projective Space of dimension 3 over Integer Ring + Defn: Identity map + """ + from sage.schemes.generic.morphism import SchemeMorphism_polynomial_id + return SchemeMorphism_polynomial_id(self) + ###################################################################### # Associated MPolynomial ring generators ###################################################################### diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index 601e80b7f49..49aa3a2d3f8 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -25,16 +25,15 @@ - Ben Hutz (June 2012): added support for projective ring """ - -#***************************************************************************** -# Copyright (C) 2011 Volker Braun -# Copyright (C) 2006 William Stein +# ***************************************************************************** +# Copyright (C) 2011 Volker Braun +# Copyright (C) 2006 William Stein # -# 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/ -#***************************************************************************** +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# ***************************************************************************** from sage.categories.homset import HomsetWithBase from sage.structure.factory import UniqueFactory @@ -70,9 +69,10 @@ def is_SchemeHomset(H): return isinstance(H, SchemeHomset_generic) -#******************************************************************* -# Factory for Hom sets of schemes -#******************************************************************* +# ******************************************************************* +# Factory for Hom sets of schemes +# ******************************************************************* + class SchemeHomsetFactory(UniqueFactory): """ Factory for Hom-sets of schemes. @@ -212,10 +212,10 @@ def create_object(self, version, key, **extra_args): SchemeHomset = SchemeHomsetFactory('sage.schemes.generic.homset.SchemeHomset') +# ******************************************************************* +# Base class +# ******************************************************************* -#******************************************************************* -# Base class -#******************************************************************* class SchemeHomset_generic(HomsetWithBase): r""" The base class for Hom-sets of schemes. @@ -393,9 +393,11 @@ def _element_constructor_(self, x, check=True): raise TypeError("x must be a ring homomorphism, list or tuple") -#******************************************************************* -# Base class for points -#******************************************************************* + +# ******************************************************************* +# Base class for points +# ******************************************************************* + class SchemeHomset_points(SchemeHomset_generic): """ Set of rational points of the scheme. diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 85d2c34db59..d3fe7abd885 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -667,6 +667,7 @@ def glue_along_domains(self, other): from . import glue return glue.GluedScheme(self, other) + class SchemeMorphism_id(SchemeMorphism): """ Return the identity morphism from `X` to itself. @@ -927,11 +928,11 @@ def ring_homomorphism(self): ############################################################################ -# Morphisms between schemes given on points -# The _affine and _projective below refer to the CODOMAIN. -# The domain can be either affine or projective regardless -# of the class +# Morphisms between schemes given on points. The _affine and _projective below +# refer to the CODOMAIN. The domain can be either affine or projective +# regardless of the class ############################################################################ + class SchemeMorphism_polynomial(SchemeMorphism): r""" A morphism of schemes determined by polynomials that define what @@ -1019,6 +1020,26 @@ def __init__(self, parent, polys, check=True): SchemeMorphism.__init__(self, parent) + def __eq__(self, other): + """ + Check equality of ``self`` and ``other``. + + INPUT: + + - ``other`` -- a morphism + + EXAMPLES:: + + sage: A. = AffineSpace(2, QQ) + sage: I = A.identity_morphism() + sage: I.parent().identity() == I + True + """ + if isinstance(other, SchemeMorphism_polynomial): + if self.parent() == other.parent() and self._polys == other._polys: + return True + raise TypeError('cannot determine equality') + def defining_polynomials(self): """ Return the defining polynomials. @@ -1207,7 +1228,6 @@ def _call_with_args(self, x, args, kwds): P = [f(x._coords) for f in self.defining_polynomials()] return self._codomain.point(P,check) - def _repr_defn(self): """ Return a string representation of the definition of ``self``. @@ -1731,6 +1751,36 @@ def _composition_(self, other, homset): return homset([p(*opolys) for p in self._polys]) +class SchemeMorphism_polynomial_id(SchemeMorphism_id, SchemeMorphism_polynomial): + """ + Return the identity morphism from `X` to itself. + + INPUT: + + - ``X`` -- an affine or projective scheme + + EXAMPLES:: + + sage: X = Spec(ZZ) + sage: X.identity_morphism() # indirect doctest + Scheme endomorphism of Spectrum of Integer Ring + Defn: Identity map + """ + def __init__(self, X): + """ + Initialize. + + TESTS:: + + sage: A = AffineSpace(2, GF(3)) + sage: A.identity_morphism().defining_polynomials() + (x0, x1) + """ + super().__init__(X) + variables = X.ambient_space().coordinate_ring().gens() + SchemeMorphism_polynomial.__init__(self, X.Hom(X), variables, check=False) + + ############################################################################ # Rational points on schemes, which we view as morphisms determined # by coordinates. diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py index 31102ff5954..e57f0e5b1e9 100644 --- a/src/sage/schemes/generic/scheme.py +++ b/src/sage/schemes/generic/scheme.py @@ -646,7 +646,7 @@ def _Hom_(self, Y, category=None, check=True): sage: E = EllipticCurve('37a1') sage: Hom(E, E).__class__ - + sage: Hom(Spec(ZZ), Spec(ZZ)).__class__ diff --git a/src/sage/schemes/hyperelliptic_curves/constructor.py b/src/sage/schemes/hyperelliptic_curves/constructor.py index 5aa3ad0abd4..54556e08755 100644 --- a/src/sage/schemes/hyperelliptic_curves/constructor.py +++ b/src/sage/schemes/hyperelliptic_curves/constructor.py @@ -6,15 +6,13 @@ - David Kohel (2006): initial version - Anna Somoza (2019-04): dynamic class creation - """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2006 David Kohel # 2019 Anna Somoza # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.schemes.projective.projective_space import ProjectiveSpace @@ -31,6 +29,7 @@ from sage.structure.dynamic_class import dynamic_class + def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): r""" Returns the hyperelliptic curve `y^2 + h y = f`, for @@ -216,40 +215,39 @@ def HyperellipticCurve(f, h=0, names=None, PP=None, check_squarefree=True): if P(2) == 0: # characteristic 2 if h == 0: - raise ValueError("In characteristic 2, argument h (= %s) must be non-zero."%h) + raise ValueError("In characteristic 2, argument h (= %s) must be non-zero." % h) if h[g+1] == 0 and f[2*g+1]**2 == f[2*g+2]*h[g]**2: - raise ValueError("Not a hyperelliptic curve: " \ - "highly singular at infinity.") + raise ValueError("Not a hyperelliptic curve: " + "highly singular at infinity.") should_be_coprime = [h, f*h.derivative()**2+f.derivative()**2] else: # characteristic not 2 if not F.degree() in [2*g+1, 2*g+2]: - raise ValueError("Not a hyperelliptic curve: " \ - "highly singular at infinity.") + raise ValueError("Not a hyperelliptic curve: " + "highly singular at infinity.") should_be_coprime = [F, F.derivative()] try: - smooth = should_be_coprime[0].gcd(should_be_coprime[1]).degree()==0 + smooth = should_be_coprime[0].gcd(should_be_coprime[1]).degree() == 0 except (AttributeError, NotImplementedError, TypeError): try: - smooth = should_be_coprime[0].resultant(should_be_coprime[1])!=0 + smooth = should_be_coprime[0].resultant(should_be_coprime[1]) != 0 except (AttributeError, NotImplementedError, TypeError): - raise NotImplementedError("Cannot determine whether " \ - "polynomials %s have a common root. Use " \ - "check_squarefree=False to skip this check." % \ + raise NotImplementedError("Cannot determine whether " + "polynomials %s have a common root. Use " + "check_squarefree=False to skip this check." % should_be_coprime) if not smooth: - raise ValueError("Not a hyperelliptic curve: " \ - "singularity in the provided affine patch.") + raise ValueError("Not a hyperelliptic curve: " + "singularity in the provided affine patch.") R = P.base_ring() PP = ProjectiveSpace(2, R) if names is None: - names = ["x","y"] + names = ["x", "y"] superclass = [] cls_name = ["HyperellipticCurve"] - genus_classes = { - 2 : HyperellipticCurve_g2} + genus_classes = {2: HyperellipticCurve_g2} is_pAdicField = lambda x: isinstance(x, sage.rings.abc.pAdicField) diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py index 7167fe2208a..5aa76b5c950 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py @@ -658,7 +658,7 @@ def __bool__(self): """ return self.__polys[0] != 1 - + def __neg__(self): r""" diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py index 05022c45113..117bc1c0daa 100644 --- a/src/sage/schemes/plane_conics/con_field.py +++ b/src/sage/schemes/plane_conics/con_field.py @@ -40,6 +40,7 @@ from sage.categories.fields import Fields _Fields = Fields() + class ProjectiveConic_field(ProjectivePlaneCurve_field): r""" Create a projective plane conic curve over a field. @@ -113,10 +114,10 @@ def base_extend(self, S): if B == S: return self if not S.has_coerce_map_from(B): - raise ValueError("No natural map from the base ring of self " \ + raise ValueError("No natural map from the base ring of self " "(= %s) to S (= %s)" % (self, S)) from .constructor import Conic - con = Conic([S(c) for c in self.coefficients()], \ + con = Conic([S(c) for c in self.coefficients()], self.variable_names()) if self._rational_point is not None: pt = [S(c) for c in Sequence(self._rational_point)] @@ -188,9 +189,7 @@ def derivative_matrix(self): [1 2 1] [1 1 0] - An example in characteristic `2`: - - :: + An example in characteristic `2`:: sage: P. = GF(2)[] sage: c = Conic([t, 1, t^2, 1, 1, 0]); c @@ -203,9 +202,9 @@ def derivative_matrix(self): [t^2 1 0] """ a, b, c, d, e, f = self.coefficients() - return Matrix([[ 2*a , b , c ], - [ b , 2*d , e ], - [ c , e , 2*f ]]) + return Matrix([[2 * a, b, c], + [b, 2 * d, e], + [c, e, 2 * f]]) def determinant(self): r""" @@ -497,8 +496,8 @@ def has_rational_point(self, point=False, # writing) fraction field elements are not converted automatically # from Magma to Sage. try: - return True, self.point( \ - [B(c.Numerator().sage()/c.Denominator().sage()) for c in pt]) + return True, self.point( + [B(c.Numerator().sage() / c.Denominator().sage()) for c in pt]) except (TypeError, NameError): pass @@ -539,8 +538,8 @@ def has_rational_point(self, point=False, if point: return ret return ret[0] - raise NotImplementedError("has_rational_point not implemented for " \ - "conics over base field %s" % B) + raise NotImplementedError("has_rational_point not implemented for " + "conics over base field %s" % B) def has_singular_point(self, point=False): r""" @@ -693,8 +692,8 @@ def hom(self, x, Y=None): if Y is None: Y = im elif not Y == im: - raise ValueError("The matrix x (= %s) does not define a " \ - "map from self (= %s) to Y (= %s)" % \ + raise ValueError("The matrix x (= %s) does not define a " + "map from self (= %s) to Y (= %s)" % (x, self, Y)) x = Sequence(x*vector(self.ambient_space().gens())) return self.Hom(Y)(x, check=False) @@ -1120,12 +1119,12 @@ def rational_point(self, algorithm='default', read_cache=True): ... ValueError: Conic Projective Conic Curve over Real Field with 53 bits of precision defined by x^2 + y^2 + z^2 has no rational points over Real Field with 53 bits of precision! """ - bl,pt = self.has_rational_point(point=True, algorithm=algorithm, - read_cache=read_cache) + bl, pt = self.has_rational_point(point=True, algorithm=algorithm, + read_cache=read_cache) if bl: return pt - raise ValueError("Conic %s has no rational points over %s!" % \ - (self, self.ambient_space().base_ring())) + raise ValueError("Conic %s has no rational points over %s!" % + (self, self.ambient_space().base_ring())) def singular_point(self): r""" @@ -1149,8 +1148,8 @@ def singular_point(self): """ b = self.has_singular_point(point=True) if not b[0]: - raise ValueError("The conic self (= %s) has no rational " \ - "singular point" % self) + raise ValueError("The conic self (= %s) has no rational " + "singular point" % self) return b[1] def symmetric_matrix(self): @@ -1175,13 +1174,13 @@ def symmetric_matrix(self): a, b, c, d, e, f = self.coefficients() if self.base_ring().characteristic() == 2: if b == 0 and c == 0 and e == 0: - return Matrix([[a,0,0],[0,d,0],[0,0,f]]) - raise ValueError("The conic self (= %s) has no symmetric matrix " \ - "because the base field has characteristic 2" % \ - self) - return Matrix([[ a , b/2, c/2 ], - [ b/2, d , e/2 ], - [ c/2, e/2, f ]]) + return Matrix([[a, 0, 0], [0, d, 0], [0, 0, f]]) + raise ValueError("The conic self (= %s) has no symmetric matrix " + "because the base field has characteristic 2" % + self) + return Matrix([[a, b / 2, c / 2], + [b / 2, d, e / 2], + [c / 2, e / 2, f]]) def upper_triangular_matrix(self): r""" diff --git a/src/sage/schemes/plane_conics/con_rational_function_field.py b/src/sage/schemes/plane_conics/con_rational_function_field.py index 66147eba580..0d1d457f085 100644 --- a/src/sage/schemes/plane_conics/con_rational_function_field.py +++ b/src/sage/schemes/plane_conics/con_rational_function_field.py @@ -138,7 +138,7 @@ def has_rational_point(self, point=False, algorithm='default', sage: F. = QuadraticField(-1) sage: R. = F[] sage: C = Conic([1,i*t,-t^2+4]) - sage: C.has_rational_point(point = True) + sage: C.has_rational_point(point=True) (True, (-t - 2*i : -2*i : 1)) It works on non-diagonal conics as well:: diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index b75ec0cde05..8c737f14e0b 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -134,7 +134,7 @@ def enum_product_projective_rational_field(X, B): m = R.num_components() iters = [ R[i].points_of_bounded_height(bound=B) for i in range(m) ] dim = [R[i].dimension_relative() + 1 for i in range(m)] - + dim_prefix = [0, dim[0]] # prefixes dim list for i in range(1, len(dim)): dim_prefix.append(dim_prefix[i] + dim[i]) @@ -540,5 +540,5 @@ def lift_all_points(): m.append(temp) rat_points = lift_all_points() - + return sorted(rat_points) diff --git a/src/sage/schemes/projective/proj_bdd_height.py b/src/sage/schemes/projective/proj_bdd_height.py new file mode 100644 index 00000000000..33d5ec1d3bc --- /dev/null +++ b/src/sage/schemes/projective/proj_bdd_height.py @@ -0,0 +1,349 @@ +r""" +Points of bounded height in projective spaces + +This module defines functions to compute points of bounded height of a given +number field with height less than a specified bound in projective spaces. + +Sage functions to list all elements of a given number field with height less +than a specified bound. + +AUTHORS: + +- Jing Guo (2022): initial version based on David Krumm's code + +REFERENCES: + +- [Krumm2016] + +""" + +import itertools + +from math import floor + +from sage.schemes.projective.projective_space import ProjectiveSpace +from sage.rings.rational_field import QQ +from sage.rings.all import RealField +from sage.rings.number_field.unit_group import UnitGroup +from sage.arith.all import gcd +from sage.matrix.constructor import matrix, column_matrix +from sage.libs.pari.all import pari +from sage.modules.free_module_element import vector +from sage.rings.integer import Integer +from sage.geometry.polyhedron.constructor import Polyhedron + + +def QQ_points_of_bounded_height(dim, bound): + r""" + Return an iterator of the points in ``self`` of absolute multiplicative + height of at most ``bound`` in the rational field. + + INPUT: + + - ``dim`` -- a positive integer + + - ``bound`` -- a real number + + OUTPUT: + + - an iterator of points of bounded height + + EXAMPLES: + + sage: from sage.schemes.projective.proj_bdd_height import QQ_points_of_bounded_height + sage: sorted(list(QQ_points_of_bounded_height(1, 1))) + [(-1 : 1), (0 : 1), (1 : 0), (1 : 1)] + sage: len(list(QQ_points_of_bounded_height(1, 5))) + 40 + + There are no points of negative height:: + + sage: from sage.schemes.projective.proj_bdd_height import QQ_points_of_bounded_height + sage: list(QQ_points_of_bounded_height(1, -3)) + [] + """ + if bound < 1: + return iter(set([])) + + PN = ProjectiveSpace(QQ, dim) + unit_tuples = list(itertools.product([-1, 1], repeat=dim)) + points_of_bounded_height = set([]) + increasing_tuples = itertools.combinations_with_replacement(range(floor(bound + 1)), dim + 1) + for t in increasing_tuples: + if gcd(t) == 1: + for p in itertools.permutations(t): + for u in unit_tuples: + point = PN([a*b for a, b in zip(u, p)] + [p[dim]]) + if point not in points_of_bounded_height: + points_of_bounded_height.add(point) + yield point + + +def IQ_points_of_bounded_height(PN, K, dim, bound): + r""" + Return an iterator of the points in ``self`` of absolute multiplicative + height of at most ``bound`` in the imaginary quadratic field ``K``. + + INPUT: + + - ``PN`` -- a projective space + + - ``K`` -- a number field + + - ``dim`` -- a positive interger + + - ``bound`` -- a real number + + OUTPUT: + + - an iterator of points of bounded height + + EXAMPLES: + + sage: from sage.schemes.projective.proj_bdd_height import IQ_points_of_bounded_height + sage: CF. = CyclotomicField(3) + sage: P. = ProjectiveSpace(CF, 2) + sage: len(list(IQ_points_of_bounded_height(P, CF, 2, -1))) + 0 + sage: len(list(IQ_points_of_bounded_height(P, CF, 2, 1))) + 57 + """ + if bound < 1: + return iter([]) + + unit_tuples = list(itertools.product(K.roots_of_unity(), repeat=dim)) + + class_group_ideals = [c.ideal() for c in K.class_group()] + class_group_ideal_norms = [i.norm() for i in class_group_ideals] + class_number = len(class_group_ideals) + + possible_norm_set = set([]) + for i in range(class_number): + for k in range(1, floor(bound + 1)): + possible_norm_set.add(k*class_group_ideal_norms[i]) + + coordinate_space = dict() + coordinate_space[0] = [K(0)] + for m in possible_norm_set: + coordinate_space[m] = K.elements_of_norm(m) + + for i in range(class_number): + a = class_group_ideals[i] + a_norm = class_group_ideal_norms[i] + a_norm_bound = bound * a_norm + a_coordinates = [] + + for m in coordinate_space: + if m <= a_norm_bound: + for x in coordinate_space[m]: + if x in a: + a_coordinates.append(x) + + points_in_class_a = set([]) + t = len(a_coordinates) - 1 + increasing_tuples = itertools.combinations_with_replacement(range(t + 1), dim + 1) + for index_tuple in increasing_tuples: + point_coordinates = [a_coordinates[i] for i in index_tuple] + if a == K.ideal(point_coordinates): + for p in itertools.permutations(point_coordinates): + for u in unit_tuples: + point = PN([i*j for i, j in zip(u, p)] + [p[dim]]) + if point not in points_in_class_a: + points_in_class_a.add(point) + yield point + + +def points_of_bounded_height(PN, K, dim, bound, prec=53): + r""" + Return an iterator of the points in ``K`` with dimension ``dim`` of + absolute multiplicative height of at most ``bound``. + + ALGORITHM: + + This is an implementation of Algorithm 6 in [Krumm2016]_. + + INPUT: + + - ``PN`` -- a projective space + + - ``K`` -- a number field + + - ``dim`` -- a positive interger + + - ``bound`` -- a real number + + - ``prec`` -- (default: 53) a positive integer + + OUTPUT: + + - an iterator of points of bounded height + + EXAMPLES: + + sage: from sage.schemes.projective.proj_bdd_height import points_of_bounded_height + sage: K. = NumberField(x^3 - 7) + sage: P. = ProjectiveSpace(K, 2) + sage: len(list(points_of_bounded_height(P, K, 2, 1))) + 13 + """ + if bound < 1: + return iter([]) + + r1, r2 = K.signature() + r = r1 + r2 - 1 + + if K.is_relative(): + K_degree = K.relative_degree() + else: + K_degree = K.degree() + + roots_of_unity = K.roots_of_unity() + unit_tuples = list(itertools.product(roots_of_unity, repeat=dim)) + + log_embed = K.logarithmic_embedding() + + Reals = RealField(prec) + logB = Reals(bound).log() + + class_group_ideals = [c.ideal() for c in K.class_group()] + class_number = len(class_group_ideals) + + if K.is_relative(): + class_group_ideal_norms = [i.absolute_norm() for i in class_group_ideals] + else: + class_group_ideal_norms = [i.norm() for i in class_group_ideals] + + norm_bound = bound * max(class_group_ideal_norms) + fundamental_units = UnitGroup(K).fundamental_units() + fund_unit_logs = list(map(log_embed, fundamental_units)) + mat = column_matrix(fund_unit_logs) + + test_matrix = mat + try: + test_matrix.change_ring(QQ) + except ValueError: + raise ValueError('prec too low.') + + cut_fund_unit_logs = mat.delete_rows([r]) + lll_fund_units = [] + for c in pari(cut_fund_unit_logs).qflll().python(): + new_unit = 1 + for i in range(r): + new_unit *= fundamental_units[i]**c[i] + lll_fund_units.append(new_unit) + fundamental_units = lll_fund_units + fund_unit_logs = list(map(log_embed, fundamental_units)) + + possible_norm_set = set([]) + for i in range(class_number): + for k in range(1, floor(bound + 1)): + possible_norm_set.add(k*class_group_ideal_norms[i]) + + principal_ideal_gens = dict() + negative_norm_units = K.elements_of_norm(-1) + if len(negative_norm_units) == 0: + for m in possible_norm_set: + principal_ideal_gens[m] = K.elements_of_norm(m) + K.elements_of_norm(-m) + else: + for m in possible_norm_set: + principal_ideal_gens[m] = K.elements_of_norm(m) + + pr_ideal_gen_logs = dict() + for key in principal_ideal_gens: + for y in principal_ideal_gens[key]: + pr_ideal_gen_logs[y] = log_embed(y) + + fund_parallelotope_vertices = [] + for coefficient_tuple in itertools.product([-1/2, 1/2], repeat=r): + vertex = sum([coefficient_tuple[i]*fund_unit_logs[i] for i in range(r)]) + fund_parallelotope_vertices.append(vertex) + + D_numbers = [] + for v in range(r + 1): + D_numbers.append(max([vertex[v] for vertex in fund_parallelotope_vertices])) + + A_numbers = [] + for v in range(r + 1): + A_numbers.append(min([pr_ideal_gen_logs[y][v] for y in pr_ideal_gen_logs])) + + aux_constant = (1/K_degree) * Reals(norm_bound).log() + + L_numbers = [] + for v in range(r1): + L_numbers.append(aux_constant + D_numbers[v] - A_numbers[v]) + for v in range(r1, r + 1): + L_numbers.append(2*aux_constant + D_numbers[v] - A_numbers[v]) + L_numbers = vector(L_numbers).change_ring(QQ) + + T = column_matrix(fund_unit_logs).delete_rows([r]).change_ring(QQ) + + # insert_row only takes integers, see https://trac.sagemath.org/ticket/11328 + M = ((-1)*matrix.identity(r)).insert_row(r, [Integer(1) for i in range(r)]) + M = M.transpose().insert_row(0, [Integer(0) for i in range(r + 1)]).transpose() + M = M.change_ring(QQ) + M.set_column(0, L_numbers) + vertices = map(vector, Polyhedron(ieqs=list(M)).vertices()) + + T_it = T.inverse().transpose() + unit_polytope = Polyhedron([v*T_it for v in vertices]) + + coordinate_space = dict() + coordinate_space[0] = [[K(0), log_embed(0)]] + int_points = unit_polytope.integral_points() + + units_with_logs = dict() + for n in int_points: + new_unit = 1 + for j in range(r): + new_unit *= fundamental_units[j]**n[j] + new_unit_log = sum([n[j]*fund_unit_logs[j] for j in range(r)]) + units_with_logs[n] = [new_unit, new_unit_log] + + for norm in principal_ideal_gens: + coordinate_list = [] + for y in principal_ideal_gens[norm]: + for n in int_points: + unit, unit_log = units_with_logs[n] + y_log = pr_ideal_gen_logs[y] + g_log = unit_log + y_log + bool1 = all(g_log[i] <= aux_constant + D_numbers[i] for i in range(r1)) + bool2 = all(g_log[j] <= 2 * aux_constant + D_numbers[j] for j in range(r1, r + 1)) + if bool1 and bool2: + g = unit * y + coordinate_list.append([g, g_log]) + if len(coordinate_list) > 0: + coordinate_space[norm] = coordinate_list + + for m in range(class_number): + a = class_group_ideals[m] + a_norm = class_group_ideal_norms[m] + log_a_norm = Reals(a_norm).log() + a_const = (logB + log_a_norm)/K_degree + a_coordinates = [] + + for k in range(floor(bound + 1)): + norm = k * a_norm + if norm in coordinate_space: + for pair in coordinate_space[norm]: + g, g_log = pair + if g in a: + bool1 = all(g_log[i] <= a_const + D_numbers[i] for i in range(r1)) + bool2 = all(g_log[j] <= 2 * a_const + D_numbers[j] for j in range(r1, r + 1)) + if bool1 and bool2: + a_coordinates.append(pair) + + t = len(a_coordinates) - 1 + points_in_class_a = set([]) + increasing_tuples = itertools.combinations_with_replacement(range(t + 1), dim + 1) + log_arch_height_bound = logB + log_a_norm + for index_tuple in increasing_tuples: + point_coordinates = [a_coordinates[i][0] for i in index_tuple] + point_coordinate_logs = [a_coordinates[i][1] for i in index_tuple] + log_arch_height = sum([max([x[i] for x in point_coordinate_logs]) for i in range(r + 1)]) + if log_arch_height <= log_arch_height_bound and a == K.ideal(point_coordinates): + for p in itertools.permutations(point_coordinates): + for u in unit_tuples: + point = PN([i*j for i, j in zip(u, p)] + [p[dim]]) + if point not in points_in_class_a: + points_in_class_a.add(point) + yield point diff --git a/src/sage/schemes/projective/projective_homset.py b/src/sage/schemes/projective/projective_homset.py index 0f7b6abce52..3ffd4a6b6e4 100644 --- a/src/sage/schemes/projective/projective_homset.py +++ b/src/sage/schemes/projective/projective_homset.py @@ -27,21 +27,20 @@ - Ben Hutz (2018): add numerical point support """ - -#***************************************************************************** -# Copyright (C) 2011 Volker Braun -# Copyright (C) 2006 William Stein +# ***************************************************************************** +# Copyright (C) 2011 Volker Braun +# Copyright (C) 2006 William Stein # -# 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/ -#***************************************************************************** +# Distributed under the terms of the GNU General Public License (GPL) +# as published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# http://www.gnu.org/licenses/ +# ***************************************************************************** from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR from sage.rings.cc import CC -from sage.schemes.generic.homset import SchemeHomset_points +from sage.schemes.generic.homset import SchemeHomset_points, SchemeHomset_generic from sage.misc.verbose import verbose @@ -53,9 +52,11 @@ from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme from copy import copy -#******************************************************************* -# Projective varieties -#******************************************************************* + +# ******************************************************************* +# Projective varieties +# ******************************************************************* + class SchemeHomset_points_projective_field(SchemeHomset_points): """ Set of rational points of a projective variety over a field. @@ -124,7 +125,7 @@ def points(self, **kwds): sage: K. = NumberField(u^2 + 3) sage: P. = ProjectiveSpace(K,2) sage: len(P(K).points(bound=1.8)) - 381 + 309 :: @@ -459,6 +460,7 @@ def numerical_points(self, F=None, **kwds): return rat_points raise NotImplementedError('numerical approximation of points only for dimension 0 subschemes') + class SchemeHomset_points_projective_ring(SchemeHomset_points): """ Set of rational points of a projective variety over a commutative ring. @@ -527,9 +529,43 @@ def points(self, B=0): raise TypeError("unable to enumerate points over %s"%R) -#******************************************************************* -# Abelian varieties -#******************************************************************* +class SchemeHomset_polynomial_projective_space(SchemeHomset_generic): + """ + Set of morphisms of a projective space. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(2, QQ) + sage: Hom(P, P) + Set of morphisms + From: Projective Space of dimension 2 over Rational Field + To: Projective Space of dimension 2 over Rational Field + """ + def identity(self): + """ + Return the identity morphism of this hom-set. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(2, QQ) + sage: Hom(P, P) + Set of morphisms + From: Projective Space of dimension 2 over Rational Field + To: Projective Space of dimension 2 over Rational Field + sage: _.identity() + Scheme endomorphism of Projective Space of dimension 2 over Rational Field + Defn: Identity map + """ + if self.is_endomorphism_set(): + from sage.schemes.generic.morphism import SchemeMorphism_polynomial_id + return SchemeMorphism_polynomial_id(self.domain()) + raise TypeError("identity map is only defined for endomorphisms") + + +# ******************************************************************* +# Abelian varieties +# ******************************************************************* + class SchemeHomset_points_abelian_variety_field(SchemeHomset_points_projective_field): r""" Set of rational points of an Abelian variety. diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py index 834074be573..3f70e439f2d 100644 --- a/src/sage/schemes/projective/projective_morphism.py +++ b/src/sage/schemes/projective/projective_morphism.py @@ -86,6 +86,7 @@ from sage.rings.quotient_ring import QuotientRing_generic from sage.rings.rational_field import QQ from sage.modules.free_module_element import vector +from sage.matrix.constructor import matrix from sage.schemes.generic.morphism import SchemeMorphism_polynomial from sage.categories.finite_fields import FiniteFields from sage.categories.number_fields import NumberFields @@ -2283,6 +2284,41 @@ def __call__(self, x): pass raise ValueError('the morphism is not defined at this point') + def __eq__(self, other): + """ + EXAMPLES:: + + sage: R. = QQ[] + sage: C = Curve(7*x^2 + 2*y*z + z^2) # conic + sage: f, g = C.parametrization() + sage: f*g == C.identity_morphism() + True + + sage: C = Curve(x^2 + y^2 - z^2) + sage: P. = ProjectiveSpace(QQ, 1) + sage: f = C.hom([x + z, y], P) + sage: g = C.hom([y, z - x], P) + sage: f == g + True + sage: h = C.hom([z, x - y], P) + sage: f == h + False + """ + Y = self.codomain() + + if not isinstance(other, SchemeMorphism_polynomial): + return False + if self.domain() != other.domain() or Y != other.codomain(): + return False + + if not Y.is_projective(): # codomain is affine + e = Y.projective_embedding(0) + return (e * self) == (e * other) + + R = self.domain().coordinate_ring() + mat = matrix([self.defining_polynomials(), other.defining_polynomials()]) + return all(R(minor).is_zero() for minor in mat.minors(2)) + @cached_method def representatives(self): """ diff --git a/src/sage/schemes/projective/projective_rational_point.py b/src/sage/schemes/projective/projective_rational_point.py index 93789be8d65..cb12e30c873 100644 --- a/src/sage/schemes/projective/projective_rational_point.py +++ b/src/sage/schemes/projective/projective_rational_point.py @@ -191,8 +191,7 @@ def enum_projective_number_field(X, **kwds): sage: P. = ProjectiveSpace(K, 2) sage: X = P.subscheme([x - y]) sage: enum_projective_number_field(X(K), bound=RR(5^(1/3)), prec=2^10) - [(0 : 0 : 1), (-1 : -1 : 1), (1 : 1 : 1), (-1/5*v^2 : -1/5*v^2 : 1), (-v : -v : 1), - (1/5*v^2 : 1/5*v^2 : 1), (v : v : 1), (1 : 1 : 0)] + [(0 : 0 : 1), (1 : 1 : 0), (-1 : -1 : 1), (1 : 1 : 1)] :: diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index ed44ebcd6aa..eeb5dc589ca 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -80,7 +80,6 @@ # **************************************************************************** from sage.arith.misc import gcd, binomial -from sage.arith.srange import srange from sage.rings.finite_rings.finite_field_constructor import is_FiniteField from sage.rings.integer import Integer @@ -112,7 +111,8 @@ from sage.modules.free_module_element import prepare from sage.schemes.generic.ambient_space import AmbientSpace from sage.schemes.projective.projective_homset import (SchemeHomset_points_projective_ring, - SchemeHomset_points_projective_field) + SchemeHomset_points_projective_field, + SchemeHomset_polynomial_projective_space) from sage.schemes.projective.projective_point import (SchemeMorphism_point_projective_ring, SchemeMorphism_point_projective_field, SchemeMorphism_point_projective_finite_field) @@ -459,7 +459,7 @@ def _validate(self, polynomials): sage: P._validate([x*y - z^2, x]) [x*y - z^2, x] - :: + :: sage: P. = ProjectiveSpace(2, ZZ) sage: P._validate((x*y - z, x)) @@ -467,7 +467,7 @@ def _validate(self, polynomials): ... TypeError: x*y - z is not a homogeneous polynomial - :: + :: sage: P. = ProjectiveSpace(2, ZZ) sage: P._validate(x*y - z) @@ -741,6 +741,20 @@ def _morphism(self, *args, **kwds): """ return SchemeMorphism_polynomial_projective_space(*args, **kwds) + def _homset(self, *args, **kwds): + """ ii + Construct the Hom-set + + EXAMPLES:: + + sage: P. = ProjectiveSpace(2, QQ) + sage: Hom(P, P) + Set of morphisms + From: Projective Space of dimension 2 over Rational Field + To: Projective Space of dimension 2 over Rational Field + """ + return SchemeHomset_polynomial_projective_space(*args, **kwds) + def _point_homset(self, *args, **kwds): """ Construct a point Hom-set. @@ -1547,8 +1561,8 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: plane1 = P.subscheme(x) sage: plane2 = P.subscheme(y) sage: m = P.hyperplane_transformation_matrix(plane1, plane2); m - [-1 -1] - [ 1 0] + [0 1] + [1 0] sage: plane2(m*P((0,1))) (1 : 0) @@ -1558,10 +1572,10 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: plane1 = P.subscheme(x + 2*y + z) sage: plane2 = P.subscheme(2*x + y + z) sage: P.hyperplane_transformation_matrix(plane1, plane2) - [ -3 0 0 0] - [ 9 6 0 0] - [-3/2 -3 3/2 0] - [-1/2 -1 -1/2 1] + [1 0 0 0] + [0 4 0 0] + [0 0 2 0] + [0 0 0 1] :: @@ -1569,8 +1583,8 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: plane1 = P.subscheme(x + y) sage: plane2 = P.subscheme(y) sage: P.hyperplane_transformation_matrix(plane1, plane2) - [ 1 0] - [-1 -1] + [-1 0] + [ 1 1] :: @@ -1580,9 +1594,9 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: plane2 = P.subscheme(x + v*y + v*z) sage: m = P.hyperplane_transformation_matrix(plane1, plane2) sage: m - [ -6/7*v - 2/7 0 0] - [ 2/7*v + 10/7 -4/7*v + 8/7 0] - [ -4/7*v + 1/7 -10/7*v - 8/7 1] + [ v 0 0] + [ 0 -2*v 0] + [ 0 0 1] :: @@ -1592,10 +1606,10 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: plane1 = P.subscheme(k*x + 2*k*y + z) sage: plane2 = P.subscheme(7*k*x + y + 9*z) sage: m = P.hyperplane_transformation_matrix(plane1, plane2); m - [ 297/410*k + 279/410 0 0 0] - [-3609/410*k + 4437/410 -1656/205*k + 2358/205 0 0] - [ 511/410*k - 24/205 511/205*k - 48/205 -107/205*k + 327/410 0] - [ 83/410*k - 107/205 83/205*k - 214/205 107/205*k + 83/410 1] + [ 1 0 0 0] + [ 0 14*k 0 0] + [ 0 0 7/9 0] + [ 0 0 0 1] :: @@ -1627,9 +1641,9 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): sage: plane1 = P.subscheme(x + 9*t*y + z) sage: plane2 = P.subscheme(x + z) sage: P.hyperplane_transformation_matrix(plane1, plane2) - [ -1/9*t -t^2 0] - [ -t^2 + 1/9*t 0 0] - [ 1/81 1/9*t -1/9*t + 1/81] + [ 1 9*t 0] + [ 1 0 0] + [ 0 0 1] TESTS:: @@ -1698,7 +1712,7 @@ def hyperplane_transformation_matrix(self, plane_1, plane_2): source_points.append(self(point)) base_list = [list(s) for s in source_points] elif len(source_points) == N + 1: - Ms = matrix(base_list + [point]) + Ms = matrix(base_list + [point.change_ring(self.base_ring())]) if not any([m == 0 for m in Ms.minors(N + 1)]): source_points.append(self(point)) break @@ -1804,6 +1818,7 @@ def is_linearly_independent(self, points, n=None): break return linearly_independent + class ProjectiveSpace_field(ProjectiveSpace_ring): def _point_homset(self, *args, **kwds): """ @@ -1852,18 +1867,12 @@ def _morphism(self, *args, **kwds): def points_of_bounded_height(self, **kwds): r""" - Returns an iterator of the points in self of absolute height of at most the given bound. + Return an iterator of the points in ``self`` of absolute multiplicative + height of at most the given bound. - Bound check is strict for the rational field. Requires self to be projective space - over a number field. Uses the - Doyle-Krumm algorithm 4 (algorithm 5 for imaginary quadratic) for - computing algebraic numbers up to a given height [DK2013]_. + ALGORITHM: - The algorithm requires floating point arithmetic, so the user is - allowed to specify the precision for such calculations. - Additionally, due to floating point issues, points - slightly larger than the bound may be returned. This can be controlled - by lowering the tolerance. + This is an implementation of Algorithm 6 in [Krumm2016]_. INPUT: @@ -1871,74 +1880,113 @@ def points_of_bounded_height(self, **kwds): - ``bound`` - a real number - - ``tolerance`` - a rational number in (0,1] used in doyle-krumm algorithm-4 - - - ``precision`` - the precision to use for computing the elements of bounded height of number fields. + - ``precision`` - (default: 53) a positive integer OUTPUT: - - an iterator of points in this space + - an iterator of points of bounded height EXAMPLES:: sage: P. = ProjectiveSpace(QQ, 1) - sage: sorted(list(P.points_of_bounded_height(bound=5))) - [(0 : 1), (1 : -5), (1 : -4), (1 : -3), (1 : -2), (1 : -1), (1 : 0), - (1 : 1), (1 : 2), (1 : 3), (1 : 4), (1 : 5), (2 : -5), (2 : -3), - (2 : -1), (2 : 1), (2 : 3), (2 : 5), (3 : -5), (3 : -4), (3 : -2), - (3 : -1), (3 : 1), (3 : 2), (3 : 4), (3 : 5), (4 : -5), (4 : -3), - (4 : -1), (4 : 1), (4 : 3), (4 : 5), (5 : -4), (5 : -3), (5 : -2), - (5 : -1), (5 : 1), (5 : 2), (5 : 3), (5 : 4)] + sage: sorted(list(P.points_of_bounded_height(bound=2))) + [(-2 : 1), (-1 : 1), (-1/2 : 1), (0 : 1), + (1/2 : 1), (1 : 0), (1 : 1), (2 : 1)] :: sage: u = QQ['u'].0 sage: P. = ProjectiveSpace(NumberField(u^2 - 2, 'v'), 2) - sage: len(list(P.points_of_bounded_height(bound=1.5, tolerance=0.1))) + sage: len(list(P.points_of_bounded_height(bound=2))) + 265 + + :: + + sage: CF. = CyclotomicField(3) + sage: R. = CF[] + sage: L. = CF.extension(x^3 + 2) + sage: Q. = ProjectiveSpace(L, 1) + sage: sorted(list(Q.points_of_bounded_height(bound=1))) + [(0 : 1), (1 : 0), (a + 1 : 1), (a : 1), + (-1 : 1), (-a - 1 : 1), (-a : 1), (1 : 1)] + + :: + + sage: R. = QQ[] + sage: F. = NumberField(x^4 - 8*x^2 + 3) + sage: P. = ProjectiveSpace(F, 2) + sage: all([exp(p.global_height()) <= 1 for p in P.points_of_bounded_height(bound=1)]) + True + + :: + + sage: K. = CyclotomicField(3) + sage: P. = ProjectiveSpace(K, 2) + sage: len(list(P.points_of_bounded_height(bound=1))) 57 + + :: + + sage: u = QQ['u'].0 + sage: K. = NumberField(u^2 - 2) + sage: P. = ProjectiveSpace(K, 1) + sage: len(list(P.points_of_bounded_height(bound=2))) + 24 + + :: + + sage: R. = QQ[] + sage: K. = NumberField(x^4 - 8*x^2 + 3) + sage: P. = ProjectiveSpace(K, 1) + sage: len(list(P.points_of_bounded_height(bound=2))) + 108 + + :: + + sage: R. = QQ[] + sage: K. = NumberField(x^5 + x^3 + 1) + sage: P. = ProjectiveSpace(K, 2) + sage: L = P.points_of_bounded_height(bound=1.2) + sage: len(list(L)) + 109 """ - if is_RationalField(self.base_ring()): - ftype = False # stores whether the field is a number field or the rational field - elif self.base_ring() in NumberFields(): # true for rational field as well, so check is_RationalField first - ftype = True + from sage.schemes.projective.proj_bdd_height import QQ_points_of_bounded_height, IQ_points_of_bounded_height, points_of_bounded_height + + R = self.base_ring() + + # whether the field is a number field or the rational field + if is_RationalField(R): + field_type = False + elif R in NumberFields(): + # true for rational field as well, so check is_RationalField first + field_type = True else: raise NotImplementedError("self must be projective space over a number field") bound = kwds.pop('bound') - B = bound**(self.base_ring().absolute_degree()) # convert to relative height + prec = kwds.pop('precision', 53) - n = self.dimension_relative() - R = self.base_ring() - if ftype: - zero = R.zero() - i = n - while not i < 0: - P = [zero for _ in range(i)] + [R.one()] - P += [zero for _ in range(n - i)] - yield self(P) - tol = kwds.pop('tolerance', 1e-2) - prec = kwds.pop('precision', 53) - iters = [R.elements_of_bounded_height(bound=B, tolerance=tol, precision=prec) for _ in range(i)] - for x in iters: - next(x) # put at zero - j = 0 - while j < i: - try: - P[j] = next(iters[j]) - yield self(P) - j = 0 - except StopIteration: - iters[j] = R.elements_of_bounded_height(bound=B, tolerance=tol, precision=prec) # reset - next(iters[j]) # put at zero - P[j] = zero - j += 1 - i -= 1 - else: # base ring QQ - zero = (0,) * (n + 1) - for c in cartesian_product_iterator([srange(-B, B + 1) - for _ in range(n + 1)]): - if gcd(c) == 1 and c > zero: - yield self.point(c, check=False) + # Convert between absolute and relative height for calling Krumm's algorithm + bound = bound**R.absolute_degree() + + dim = self.dimension_relative() + + if field_type: + # for imaginary quadratic field + r1, r2 = R.signature() + r = r1 + r2 - 1 + + if R.is_relative(): + deg = R.relative_degree() + else: + deg = R.degree() + + if deg == 2 and r == 0: + return IQ_points_of_bounded_height(self, R, dim, bound) + + return points_of_bounded_height(self, R, dim, bound, prec) + else: + return QQ_points_of_bounded_height(dim, bound) def subscheme_from_Chow_form(self, Ch, dim): r""" @@ -2100,6 +2148,7 @@ def line_through(self, p, q): m = matrix(3, list(self.gens()) + list(p) + list(q)) return Curve([f for f in m.minors(3) if f]) + class ProjectiveSpace_finite_field(ProjectiveSpace_field): def _point(self, *args, **kwds): """ diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py index f85a7295dbc..facd90d0425 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`. @@ -3082,7 +3082,7 @@ def initialise(z, i): # converge happens silently, thus allowing the user to get *an* # answer out of the integration, but numerical imprecision is to be # expected. As such, we set the maximum number of steps in the sequence - # of DE integrations to be lower in the latter case. + # of DE integrations to be lower in the latter case. if raise_errors: n_steps = self._prec - 1 else: @@ -3240,9 +3240,9 @@ def fv(hj, previous_estimate): Nh *= 2 # Note that throughout this loop there is a return statement, intended # to be activated when the sequence of integral approximations is - # deemed to have converged by the heuristic error. If this has no + # deemed to have converged by the heuristic error. If this has no # happened by the time we have gone through the process n_steps times, - # we have one final error handle. Again, this will throw an error if + # we have one final error handle. Again, this will throw an error if # the raise_errors flag is true, but will just return the answer otherwise. if raise_errors: raise ConvergenceError("Newton iteration fails to converge") diff --git a/src/sage/schemes/toric/homset.py b/src/sage/schemes/toric/homset.py index b5c97e10f83..a057ecdf1ab 100644 --- a/src/sage/schemes/toric/homset.py +++ b/src/sage/schemes/toric/homset.py @@ -84,7 +84,7 @@ From: Projective Space of dimension 2 over Rational Field To: 2-d CPR-Fano toric variety covered by 3 affine patches sage: type(native_to_toric) - + sage: native_to_toric([u^2, v^2, w^2]) Scheme morphism: From: Projective Space of dimension 2 over Rational Field diff --git a/src/sage/sets/disjoint_set.pyx b/src/sage/sets/disjoint_set.pyx index 02cde67d017..aaa12438f15 100644 --- a/src/sage/sets/disjoint_set.pyx +++ b/src/sage/sets/disjoint_set.pyx @@ -887,7 +887,6 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): {{0}, {1, 2, 3, 4}} sage: d.to_digraph().edges(sort=True) [(0, 0, None), (1, 1, None), (2, 1, None), (3, 1, None), (4, 1, None)] - """ d = {} for i from 0 <= i < self.cardinality(): @@ -896,4 +895,3 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): d[e] = [p] from sage.graphs.graph import DiGraph return DiGraph(d) - diff --git a/src/sage/sets/disjoint_union_enumerated_sets.py b/src/sage/sets/disjoint_union_enumerated_sets.py index 1820a79256f..c1276dc9edf 100644 --- a/src/sage/sets/disjoint_union_enumerated_sets.py +++ b/src/sage/sets/disjoint_union_enumerated_sets.py @@ -542,11 +542,11 @@ def _element_constructor_facade(self, el): sage: p = X._element_constructor_((0, [])) # indirect doctest sage: p[1].parent() Partitions of the integer 0 - + Test that facade parents can create and properly access elements that are tuples (fixed by :trac:`22382`):: - sage: f = lambda mu: cartesian_product([mu.standard_tableaux(), + sage: f = lambda mu: cartesian_product([mu.standard_tableaux(), ....: mu.standard_tableaux()]) sage: tabs = DisjointUnionEnumeratedSets(Family(Partitions(4), f)) sage: s = StandardTableau([[1,3],[2,4]]) @@ -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_enumerated_set.py b/src/sage/sets/finite_enumerated_set.py index d8745d13844..a2f5dc759ec 100644 --- a/src/sage/sets/finite_enumerated_set.py +++ b/src/sage/sets/finite_enumerated_set.py @@ -109,7 +109,7 @@ def __init__(self, elements): self._elements = elements Parent.__init__(self, facade=True, category=FiniteEnumeratedSets()) - def __bool__(self): + def __bool__(self) -> bool: r""" Conversion to boolean. @@ -122,8 +122,6 @@ def __bool__(self): """ return bool(self._elements) - - def _repr_(self): """ TESTS:: 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/formal_sum.py b/src/sage/structure/formal_sum.py index 0e14ab6dd1e..73eeb69854e 100644 --- a/src/sage/structure/formal_sum.py +++ b/src/sage/structure/formal_sum.py @@ -265,7 +265,7 @@ def _rmul_(self, s): """ return self.__class__([(s*c, x) for (c, x) in self], check=False, parent=self.parent()) - def __bool__(self): + def __bool__(self) -> bool: """ EXAMPLES:: @@ -278,8 +278,6 @@ def __bool__(self): """ return not all(c.is_zero() for c, _ in self._data) - - def reduce(self): """ EXAMPLES:: diff --git a/src/sage/structure/global_options.py b/src/sage/structure/global_options.py index a529d39cd5e..8a3411bdc8f 100644 --- a/src/sage/structure/global_options.py +++ b/src/sage/structure/global_options.py @@ -613,7 +613,7 @@ def __rmul__(self, other): """ return other * self._options[self._name] - def __bool__(self): + def __bool__(self) -> bool: r""" Return the value of this option interpreted as a boolean. @@ -630,9 +630,6 @@ def __bool__(self): """ return bool(self._options[self._name]) - # for the less sensibly named python 2 family - - def __call__(self, *args, **kwds): r""" Get or set value of the option ``self``. 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/mutability.pyx b/src/sage/structure/mutability.pyx index b35d26a3ccb..4aa466513c8 100644 --- a/src/sage/structure/mutability.pyx +++ b/src/sage/structure/mutability.pyx @@ -69,9 +69,9 @@ cdef class Mutability: cpdef _require_mutable(self): r""" Whenever mutability is required, this method can be called. - + EXAMPLES:: - + sage: class A(SageObject, Mutability): ....: def __init__(self, val): ....: self._val = val @@ -87,7 +87,7 @@ cdef class Mutability: Traceback (most recent call last): ... ValueError: object is immutable; please change a copy instead - + """ if self._is_immutable: raise ValueError("object is immutable; please change a copy instead") @@ -95,9 +95,9 @@ cdef class Mutability: cpdef _require_immutable(self): r""" Whenever immutability is required, this method can be called. - + EXAMPLES:: - + sage: class A(SageObject, Mutability): ....: def __init__(self, val): ....: self._val = val @@ -112,7 +112,7 @@ cdef class Mutability: Traceback (most recent call last): ... ValueError: object is mutable; please make it immutable first - + """ if not self._is_immutable: raise ValueError("object is mutable; please make it immutable first") @@ -160,11 +160,11 @@ cdef class Mutability: """ Return ``True`` if this object is mutable (can be changed) and ``False`` if it is not. - + To make this object immutable use ``self.set_immutable()``. - + EXAMPLES:: - + sage: v = Sequence([1,2,3,4/5]) sage: v[0] = 5 sage: v @@ -180,9 +180,9 @@ cdef class Mutability: def __getstate__(self): r""" Get the current state of ``self`` including the mutability status. - + TESTS:: - + sage: class A(SageObject, Mutability): ....: def __init__(self, val): ....: self._val = val @@ -203,7 +203,7 @@ cdef class Mutability: , ), {'_is_immutable': False, '_val': 4}) - + """ state = getattr(self, '__dict__', {}) state['_is_immutable'] = self._is_immutable diff --git a/src/sage/structure/parent_base.pyx b/src/sage/structure/parent_base.pyx index 91c62424dae..907f84ec89f 100644 --- a/src/sage/structure/parent_base.pyx +++ b/src/sage/structure/parent_base.pyx @@ -41,4 +41,3 @@ cdef class ParentWithBase(Parent_old): check_old_coerce(self) raise CoercionException("BUG: the base_extend method must be defined for '%s' (class '%s')" % (self, type(self))) - diff --git a/src/sage/structure/parent_gens.pyx b/src/sage/structure/parent_gens.pyx index 45e82720f43..c4155736e99 100644 --- a/src/sage/structure/parent_gens.pyx +++ b/src/sage/structure/parent_gens.pyx @@ -373,5 +373,3 @@ cdef class localvars: def __exit__(self, type, value, traceback): self._obj.__temporarily_change_names(self._orig[0], self._orig[1]) - - 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/assumptions.py b/src/sage/symbolic/assumptions.py index 706de96005d..4616fd2880b 100644 --- a/src/sage/symbolic/assumptions.py +++ b/src/sage/symbolic/assumptions.py @@ -883,7 +883,6 @@ class assuming: [x == -2, x == 2] sage: with assuming(x > 0): ....: solve(x^2 == 4,x) - ....: [x == 2] sage: assumptions() [] diff --git a/src/sage/symbolic/callable.py b/src/sage/symbolic/callable.py index 4a123ec0e33..e570b06bc98 100644 --- a/src/sage/symbolic/callable.py +++ b/src/sage/symbolic/callable.py @@ -358,7 +358,7 @@ def _repr_(self): sage: R._repr_() 'Callable function ring with arguments (x, y, theta)' - We verify that :trac:`12298` has been fixed:: + We verify that :trac:`12298` has been fixed:: sage: S = CallableSymbolicExpressionRing([var('z')]) sage: S._repr_() diff --git a/src/sage/symbolic/complexity_measures.py b/src/sage/symbolic/complexity_measures.py index 1b5823e38bf..528d1bf6906 100644 --- a/src/sage/symbolic/complexity_measures.py +++ b/src/sage/symbolic/complexity_measures.py @@ -6,6 +6,7 @@ return a number. """ + def string_length(expr): """ Returns the length of ``expr`` after converting it to a string. @@ -22,11 +23,11 @@ def string_length(expr): If the expression is longer on-screen, then a human would probably consider it more complex. - + EXAMPLES: This expression has three characters, ``x``, ``^``, and ``2``:: - + sage: from sage.symbolic.complexity_measures import string_length sage: f = x^2 sage: string_length(f) diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 7ee103f8555..903a8541460 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -11901,7 +11901,7 @@ cdef class Expression(Expression_abc): Check that :trac:`33640` is fixed:: - sage: ((x + 1)^2 - 2*x - 1).factor() + sage: ((x + 1)^2 - 2*x - 1).factor() x^2 """ from sage.calculus.calculus import symbolic_expression_from_maxima_string diff --git a/src/sage/symbolic/function.pyx b/src/sage/symbolic/function.pyx index 06e626c7748..0baedce69c0 100644 --- a/src/sage/symbolic/function.pyx +++ b/src/sage/symbolic/function.pyx @@ -502,7 +502,7 @@ cdef class Function(SageObject): sage: (out, parent(out)) (0, Integer Ring) - Check that `real_part` and `imag_part` still works after :trac:`21216`:: + Check that ``real_part`` and ``imag_part`` still works after :trac:`21216`:: sage: import numpy sage: a = numpy.array([1+2*I, -2-3*I], dtype=complex) 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/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index f9914e438a1..34d96b1c731 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -194,6 +194,16 @@ def __init__(self): sage: from sage.symbolic.integration.integral import definite_integral sage: definite_integral(sin(x),x,0,pi) 2 + + TESTS: + + Check for :trac:`32354`:: + + sage: ex = 1/max_symbolic(x, 1)**2 + sage: integral(ex, x, 0, 2, algorithm='giac') + 3/2 + sage: integral(1/max_symbolic(x, 1)**2, x, 0, oo, algorithm='giac') + 2 """ # The automatic evaluation routine will try these integrators # in the given order. This is an attribute of the class instead of diff --git a/src/sage/symbolic/relation.py b/src/sage/symbolic/relation.py index 6bd6469dd22..e9dbc0fea30 100644 --- a/src/sage/symbolic/relation.py +++ b/src/sage/symbolic/relation.py @@ -1197,12 +1197,16 @@ def _solve_expression(f, x, explicit_solutions, multiplicities, Catch error message from Maxima:: sage: solve(acot(x),x) - [] + Traceback (most recent call last): + ... + TypeError: ECL says: cot: argument 0 isn't in the domain of cot. :: sage: solve(acot(x),x,to_poly_solve=True) - [] + Traceback (most recent call last): + ... + TypeError: ECL says: cot: argument 0 isn't in the domain of cot. :trac:`7491` fixed:: 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 9dc4f6e430a..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 @@ -121,8 +121,7 @@ Sage example in ./combinat.tex, line 661:: - sage: C = L() - sage: C._name = 'C' + sage: C = L.undefined(valuation=1) sage: C.define( z + C * C ) Sage example in ./combinat.tex, line 666:: @@ -889,7 +888,7 @@ Sage example in ./combinat.tex, line 2697:: - sage: BT = CombinatorialSpecies() + sage: BT = CombinatorialSpecies(min=1) sage: Leaf = SingletonSpecies() sage: BT.define( Leaf + (BT*BT) ) @@ -906,7 +905,7 @@ Sage example in ./combinat.tex, line 2727:: sage: g = BT.isotype_generating_series(); g - x + x^2 + 2*x^3 + 5*x^4 + 14*x^5 + O(x^6) + z + z^2 + 2*z^3 + 5*z^4 + 14*z^5 + 42*z^6 + 132*z^7 + O(z^8) Sage example in ./combinat.tex, line 2733:: @@ -922,7 +921,7 @@ Sage example in ./combinat.tex, line 2752:: - sage: L = FW.isotype_generating_series().coefficients(15); L + sage: L = FW.isotype_generating_series()[:15]; L [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987] Sage example in ./combinat.tex, line 2769:: @@ -1053,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 951bfb2b5c6..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 @@ -363,28 +363,27 @@ Sage example in ./polynomes.tex, line 2028:: sage: L. = LazyPowerSeriesRing(QQ) - sage: lazy_exp = x.exponential(); lazy_exp - O(1) + sage: lazy_exp = x.exp(); lazy_exp + 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + 1/720*x^6 + O(x^7) Sage example in ./polynomes.tex, line 2039:: sage: lazy_exp[5] 1/120 sage: lazy_exp - 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + O(x^6) + 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + 1/720*x^6 + O(x^7) Sage example in ./polynomes.tex, line 2062:: sage: f = L(1) # the constant lazy series 1 sage: for i in range(5): - ....: f = (x*f).exponential() - ....: f.compute_coefficients(5) # forces the computation + ....: f = (x*f).exp() ....: print(f) # of the first coefficients - 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + O(x^6) - 1 + x + 3/2*x^2 + 5/3*x^3 + 41/24*x^4 + 49/30*x^5 + O(x^6) - 1 + x + 3/2*x^2 + 8/3*x^3 + 101/24*x^4 + 63/10*x^5 + O(x^6) - 1 + x + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + 49/5*x^5 + O(x^6) - 1 + x + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + 54/5*x^5 + O(x^6) + 1 + x + 1/2*x^2 + 1/6*x^3 + 1/24*x^4 + 1/120*x^5 + 1/720*x^6 + O(x^7) + 1 + x + 3/2*x^2 + 5/3*x^3 + 41/24*x^4 + 49/30*x^5 + 1057/720*x^6 + O(x^7) + 1 + x + 3/2*x^2 + 8/3*x^3 + 101/24*x^4 + 63/10*x^5 + 6607/720*x^6 + O(x^7) + 1 + x + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + 49/5*x^5 + 12847/720*x^6 + O(x^7) + 1 + x + 3/2*x^2 + 8/3*x^3 + 125/24*x^4 + 54/5*x^5 + 16087/720*x^6 + O(x^7) Sage example in ./polynomes.tex, line 2091:: @@ -393,10 +392,9 @@ Sage example in ./polynomes.tex, line 2105:: - sage: from sage.combinat.species.series import LazyPowerSeries - sage: f = LazyPowerSeries(L, name='f') - sage: f.define((x*f).exponential()) - sage: f.coefficients(8) + sage: f = L.undefined(valuation=0) + sage: f.define((x*f).exp()) + sage: f[:8] [1, 1, 3/2, 8/3, 125/24, 54/5, 16807/720, 16384/315] Sage example in ./polynomes.tex, line 2158:: @@ -406,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/topology/delta_complex.py b/src/sage/topology/delta_complex.py index 8cbdcf5d293..420fd2fad5a 100644 --- a/src/sage/topology/delta_complex.py +++ b/src/sage/topology/delta_complex.py @@ -235,7 +235,7 @@ class DeltaComplex(GenericCellComplex): sage: delta_complexes.RealProjectivePlane() Delta complex with 2 vertices and 8 simplices - Type ``delta_complexes.`` and then hit the TAB key to get the + Type ``delta_complexes.`` and then hit the :kbd:`Tab` key to get the full list. """ def __init__(self, data=None, check_validity=True): diff --git a/src/sage/topology/simplicial_complex_catalog.py b/src/sage/topology/simplicial_complex_catalog.py index 07a0de43b4a..6e86db14cb5 100644 --- a/src/sage/topology/simplicial_complex_catalog.py +++ b/src/sage/topology/simplicial_complex_catalog.py @@ -49,7 +49,7 @@ - :meth:`~sage.topology.examples.ZieglerBall` You can also get a list by typing ``simplicial_complexes.`` and hitting the -TAB key. +:kbd:`Tab` key. EXAMPLES:: diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index a21391beab3..65914f47830 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -49,7 +49,7 @@ - :func:`ZieglerBall` You can also get a list by typing ``simplicial_complexes.`` and hitting the -TAB key. +:kbd:`Tab` key. EXAMPLES:: diff --git a/src/sage/topology/simplicial_set.py b/src/sage/topology/simplicial_set.py index 0fa0e6495d9..836a13da05d 100644 --- a/src/sage/topology/simplicial_set.py +++ b/src/sage/topology/simplicial_set.py @@ -62,7 +62,7 @@ sage: simplicial_sets.ClassifyingSpace(Sigma4) Classifying space of Symmetric group of order 4! as a permutation group -Type ``simplicial_sets.`` and hit the ``TAB`` key to get a full list +Type ``simplicial_sets.`` and hit the :kbd:`Tab` key to get a full list of the predefined simplicial sets. You can construct new simplicial sets from old by taking quotients, 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..a82d4578e10 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.beta3' +date = '2022-10-30' +banner = 'SageMath version 9.8.beta3, Release Date: 2022-10-30' diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index 245fce04aeb..4c880cdca63 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -196,6 +196,7 @@ def sphinx_plot(graphics, **kwds): # Cross-links to other project's online documentation. python_version = sys.version_info.major + def set_intersphinx_mappings(app, config): """ Add precompiled inventory (the objects.inv) @@ -207,7 +208,7 @@ def set_intersphinx_mappings(app, config): app.config.intersphinx_mapping = {} return - app.config.intersphinx_mapping = { + app.config.intersphinx_mapping = { 'python': ('https://docs.python.org/', os.path.join(SAGE_DOC_SRC, "common", "python{}.inv".format(python_version))), @@ -232,6 +233,7 @@ def set_intersphinx_mappings(app, config): intersphinx.normalize_intersphinx_mapping(app, config) + # By default document are not master. multidocs_is_master = True @@ -819,6 +821,7 @@ def nitpick_patch_config(app): '__builtin__', ] + def check_nested_class_picklability(app, what, name, obj, skip, options): """ Print a warning if pickling is broken for nested classes. @@ -878,6 +881,7 @@ class will be properly documented inside its surrounding class. return skip + # This replaces the setup() in sage.misc.sagedoc_conf def setup(app): app.connect('autodoc-process-docstring', process_docstring_cython) @@ -904,4 +908,3 @@ def setup(app): app.connect('missing-reference', find_sage_dangling_links) app.connect('builder-inited', nitpick_patch_config) app.connect('html-page-context', add_page_context) - diff --git a/src/sage_docbuild/ext/multidocs.py b/src/sage_docbuild/ext/multidocs.py index 39121ef90ac..70096178b9f 100644 --- a/src/sage_docbuild/ext/multidocs.py +++ b/src/sage_docbuild/ext/multidocs.py @@ -1,24 +1,24 @@ # -*- coding: utf-8 -*- """ - multi documentation in Sphinx - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - The goal of this extension is to manage a multi documentation in Sphinx. - To be able to compile Sage's huge documentation in parallel, the - documentation is cut into a bunch of independent documentations called - "subdocs", which are compiled separately. There is a master document which - points to all the subdocs. The intersphinx extension ensures that the - cross-link between the subdocs are correctly resolved. However some work - is needed to build a global index. This is the goal of multidocs. - - More precisely this extension ensures the correct merging of - - the todo list if this extension is activated; - - the python indexes; - - the list of python modules; - - the javascript index; - - the citations. -""" +Sage multidocs extension + +The goal of this extension is to manage a multi-documentation in Sphinx. To be +able to compile Sage's huge documentation in parallel, the documentation is cut +into a bunch of independent documentations called "sub-docs", which are +compiled separately. There is a master document which points to all the +sub-docs. The intersphinx extension ensures that the cross-link between the +sub-docs are correctly resolved. However some work is needed to build a global +index. This is the goal of the ``multidocs`` extension. + +More precisely this extension ensures the correct merging of + +- the todo list if this extension is activated +- the python indexes +- the list of python modules +- the javascript index +- the citations +""" import os import pickle import shutil @@ -35,15 +35,15 @@ def merge_environment(app, env): """ - Merges the following attributes of the sub-docs environment into the main + Merge the following attributes of the sub-docs environment into the main environment: - - titles # Titles - - todo_all_todos # ToDo's - - indexentries # global python index - - all_docs # needed by the js index - - citations # citations - - domaindata['py']['modules'] # list of python modules + - ``titles`` -- Titles + - ``todo_all_todos`` -- todo's + - ``indexentries`` -- global python index + - ``all_docs`` -- needed by the js index + - ``citations`` -- citations + - ``domaindata['py']['modules']`` -- list of python modules """ logger.info(bold('Merging environment/index files...')) for curdoc in app.env.config.multidocs_subdoc_list: @@ -81,7 +81,7 @@ def merge_environment(app, env): env.all_docs.update(newalldoc) # needed by env.check_consistency (sphinx.environment, line 1734) for ind in newalldoc: - # treat subdocument source as orphaned file and don't complain + # treat sub-document source as orphaned file and don't complain md = env.metadata.get(ind, dict()) md['orphan'] = 1 env.metadata[ind] = md @@ -146,6 +146,10 @@ def merge_js_index(app): titles = app.builder.indexer._titles for (res, title) in index._titles.items(): titles[fixpath(res)] = title + # merge the alltitles + alltitles = app.builder.indexer._all_titles + for (res, alltitle) in index._all_titles.items(): + alltitles[fixpath(res)] = alltitle # merge the filenames filenames = app.builder.indexer._filenames for (res, filename) in index._filenames.items(): @@ -192,14 +196,14 @@ def get_js_index(app, curdoc): def fix_path_html(app, pagename, templatename, ctx, event_arg): """ - Fixes the context so that the files - - search.html - - genindex.html - - py-modindex.html - point to the right place, that is in - reference/ - instead of - reference/subdocument + Fix the context so that the files + + - :file:`search.html` + - :file:`genindex.html` + - :file:`py-modindex.html` + + point to the right place, that is in :file:`reference/` instead of + :file:`reference/subdocument`. """ # sphinx/builder/html.py line 702 # def pathto(otheruri, resource=False, @@ -265,7 +269,7 @@ def fetch_citation(app: Sphinx, env): def init_subdoc(app): """ - Init the merger depending on if we are compiling a subdoc or the master + Init the merger depending on if we are compiling a sub-doc or the master doc itself. """ if app.config.multidocs_is_master: diff --git a/src/sage_docbuild/ext/sage_autodoc.py b/src/sage_docbuild/ext/sage_autodoc.py index 5b97b272718..0d15eec91a2 100644 --- a/src/sage_docbuild/ext/sage_autodoc.py +++ b/src/sage_docbuild/ext/sage_autodoc.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- """ -Sage autodoc extension based on sphinx.ext.autodoc from Sphinx +Sage autodoc extension -From sphinx.ext.autodoc: +This is based on :mod:`sphinx.ext.autodoc` from Sphinx. + +From :mod:`sphinx.ext.autodoc`: Automatically insert docstrings for functions, classes or whole modules into the doctree, thus avoiding duplication between docstrings and documentation @@ -23,7 +25,7 @@ - Simon King (2011-04): use sageinspect; include public cython attributes only in the documentation if they have a docstring -- Kwankyu Lee (2018-12-26): rebase on the latest sphinx.ext.autodoc +- Kwankyu Lee (2018-12-26): rebased on the latest sphinx.ext.autodoc """ @@ -64,7 +66,7 @@ MethodDescriptorType = type(type.__subclasses__) -#: extended signature RE: with explicit module name separated by :: +# extended signature RE: with explicit module name separated by ``::`` py_ext_sig_re = re.compile( r'''^ ([\w.]+::)? # explicit module name ([\w.]+\.)? # module and/or class name(s) @@ -192,7 +194,8 @@ def cut_lines(pre, post=0, what=None): from sphinx.ext.autodoc import cut_lines app.connect('autodoc-process-docstring', cut_lines(4, what=['module'])) - This can (and should) be used in place of :confval:`automodule_skip_lines`. + This can (and should) be used in place of ``automodule_skip_lines`` (config + value defined in Sphinx autodoc). """ def process(app, what_, name, obj, options, lines): # type: (Sphinx, unicode, unicode, Any, Any, List[unicode]) -> None diff --git a/src/sage_setup/clean.py b/src/sage_setup/clean.py index 4ed286cdac6..3cf0d08a353 100644 --- a/src/sage_setup/clean.py +++ b/src/sage_setup/clean.py @@ -2,7 +2,10 @@ Clean the Install Dir """ #***************************************************************************** -# Copyright (C) 2014 Volker Braun +# Copyright (C) 2014 Volker Braun +# 2015 Jeroen Demeyer +# 2017 Erik M. Bray +# 2020-2022 Matthias Koeppe # # 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 @@ -15,8 +18,8 @@ import os import importlib.util -from sage_setup.find import installed_files_by_module, get_extensions, read_distribution - +from sage.misc.package_dir import SourceDistributionFilter +from sage_setup.find import installed_files_by_module, get_extensions def _remove(file_set, module_base, to_remove): @@ -83,8 +86,14 @@ def _find_stale_files(site_packages, python_packages, python_modules, ext_module sage: from sage_setup.find import find_python_sources, find_extra_files sage: python_packages, python_modules, cython_modules = find_python_sources( ....: SAGE_SRC, ['sage', 'sage_setup']) - sage: extra_files = list(find_extra_files(SAGE_SRC, - ....: ['sage', 'sage_setup'], cythonized_dir, []).items()) + sage: extra_files = find_extra_files(SAGE_SRC, + ....: ['sage', 'sage_setup'], cythonized_dir, []) + sage: from importlib.metadata import files + sage: for f in files('sagemath-standard'): + ....: dir = os.path.dirname(str(f)) + ....: extra_files[dir] = extra_files.get(dir, []) + ....: extra_files[dir].append(str(f)) + sage: extra_files = list(extra_files.items()) sage: from sage_setup.clean import _find_stale_files TODO: Also check extension modules:: @@ -141,7 +150,7 @@ def _find_stale_files(site_packages, python_packages, python_modules, ext_module def clean_install_dir(site_packages, python_packages, python_modules, ext_modules, data_files, nobase_data_files, *, - distributions=None): + distributions=None, exclude_distributions=None): """ Delete all modules that are **not** being installed @@ -178,10 +187,11 @@ def clean_install_dir(site_packages, python_packages, python_modules, ext_module ``distribution`` (from a ``# sage_setup: distribution = PACKAGE`` directive in the file) is an element of ``distributions``. """ + distribution_filter = SourceDistributionFilter(distributions, exclude_distributions) stale_file_iter = _find_stale_files( site_packages, python_packages, python_modules, ext_modules, data_files, nobase_data_files) for f in stale_file_iter: f = os.path.join(site_packages, f) - if distributions is None or read_distribution(f) in distributions: + if f in distribution_filter: print('Cleaning up stale file: {0}'.format(f)) os.unlink(f) diff --git a/src/sage_setup/find.py b/src/sage_setup/find.py index 5cec2c4ee44..61d91abc2eb 100644 --- a/src/sage_setup/find.py +++ b/src/sage_setup/find.py @@ -2,7 +2,12 @@ Recursive Directory Contents """ # **************************************************************************** -# Copyright (C) 2014 Volker Braun +# Copyright (C) 2014 Volker Braun +# 2014 R. Andrew Ohana +# 2015-2018 Jeroen Demeyer +# 2017 Erik M. Bray +# 2021 Tobias Diez +# 2020-2022 Matthias Koeppe # # 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 @@ -19,49 +24,13 @@ from collections import defaultdict from sage.misc.package_dir import is_package_or_sage_namespace_package_dir as is_package_or_namespace_package_dir +from sage.misc.package_dir import read_distribution, SourceDistributionFilter +assert read_distribution # unused in this file, re-export for compatibility -def read_distribution(src_file): - """ - Parse ``src_file`` for a ``# sage_setup: distribution = PKG`` directive. - - INPUT: - - - ``src_file`` -- file name of a Python or Cython source file - - OUTPUT: - - - a string, the name of the distribution package (``PKG``); or the empty - string if no directive was found. - - EXAMPLES:: - sage: from sage.env import SAGE_SRC - sage: from sage_setup.find import read_distribution - sage: read_distribution(os.path.join(SAGE_SRC, 'sage', 'graphs', 'graph_decompositions', 'tdlib.pyx')) - 'sagemath-tdlib' - sage: read_distribution(os.path.join(SAGE_SRC, 'sage', 'graphs', 'graph_decompositions', 'modular_decomposition.py')) - '' - """ - from Cython.Utils import open_source_file - with open_source_file(src_file, error_handling='ignore') as fh: - for line in fh: - # Adapted from Cython's Build/Dependencies.py - line = line.lstrip() - if not line: - continue - if line[0] != '#': - break - line = line[1:].lstrip() - kind = "sage_setup:" - if line.startswith(kind): - key, _, value = [s.strip() for s in line[len(kind):].partition('=')] - if key == "distribution": - return value - return '' - - -def find_python_sources(src_dir, modules=['sage'], distributions=None): +def find_python_sources(src_dir, modules=['sage'], distributions=None, + exclude_distributions=None): """ Find all Python packages and Python/Cython modules in the sources. @@ -78,6 +47,11 @@ def find_python_sources(src_dir, modules=['sage'], distributions=None): directive in the module source file) is an element of ``distributions``. + - ``exclude_distributions`` -- (default: ``None``) if not ``None``, + should be a sequence or set of strings: exclude modules whose + ``distribution`` (from a ``# sage_setup: distribution = PACKAGE`` + directive in the module source file) is in ``exclude_distributions``. + OUTPUT: Triple consisting of - the list of package names (corresponding to ordinary packages @@ -164,6 +138,8 @@ def find_python_sources(src_dir, modules=['sage'], distributions=None): python_modules = [] cython_modules = [] + distribution_filter = SourceDistributionFilter(distributions, exclude_distributions) + cwd = os.getcwd() try: os.chdir(src_dir) @@ -171,24 +147,21 @@ def find_python_sources(src_dir, modules=['sage'], distributions=None): for dirpath, dirnames, filenames in os.walk(module): package = dirpath.replace(os.path.sep, '.') if not is_package_or_namespace_package_dir(dirpath): + # Skip any subdirectories + dirnames[:] = [] continue # Ordinary package or namespace package. if distributions is None or '' in distributions: python_packages.append(package) - def is_in_distributions(filename): - if distributions is None: - return True - distribution = read_distribution(os.path.join(dirpath, filename)) - return distribution in distributions - for filename in filenames: base, ext = os.path.splitext(filename) + filepath = os.path.join(dirpath, filename) if ext == PYMOD_EXT and base != '__init__': - if is_in_distributions(filename): + if filepath in distribution_filter: python_modules.append(package + '.' + base) if ext == '.pyx': - if is_in_distributions(filename): + if filepath in distribution_filter: cython_modules.append(Extension(package + '.' + base, sources=[os.path.join(dirpath, filename)])) @@ -196,7 +169,7 @@ def is_in_distributions(filename): os.chdir(cwd) return python_packages, python_modules, cython_modules -def filter_cython_sources(src_dir, distributions): +def filter_cython_sources(src_dir, distributions, exclude_distributions=None): """ Find all Cython modules in the given source directory that belong to the given distributions. @@ -235,12 +208,12 @@ def filter_cython_sources(src_dir, distributions): 1 loops, best of 1: 850 ms per loop """ files: list[str] = [] - + distribution_filter = SourceDistributionFilter(distributions, exclude_distributions) for dirpath, dirnames, filenames in os.walk(src_dir): for filename in filenames: filepath = os.path.join(dirpath, filename) base, ext = os.path.splitext(filename) - if ext == '.pyx' and read_distribution(filepath) in distributions: + if ext == '.pyx' and filepath in distribution_filter: files.append(filepath) return files diff --git a/src/setup.cfg.m4 b/src/setup.cfg.m4 index a69b69924c5..ae2a5bfe9a9 100644 --- a/src/setup.cfg.m4 +++ b/src/setup.cfg.m4 @@ -68,7 +68,6 @@ dnl From Makefile.in: DOC_DEPENDENCIES | sed "2,\$s/^/ /;"')dnl' dnl Other Python packages that are standard spkg, used in doctests esyscmd(`sage-get-system-packages install-requires \ - rpy2 \ fpylll \ | sed "2,\$s/^/ /;"')dnl' dnl pycryptosat # Sage distribution installs it as part of cryptominisat. According to its README on https://pypi.org/project/pycryptosat/: "The pycryptosat python package compiles while compiling CryptoMiniSat. It cannot be compiled on its own, it must be compiled at the same time as CryptoMiniSat." @@ -160,3 +159,8 @@ sage = ext_data/magma/sage/* ext_data/valgrind/* ext_data/threejs/* + +[options.extras_require] +R = esyscmd(`sage-get-system-packages install-requires \ + rpy2 \ + | sed "2,\$s/^/ /;"')dnl' diff --git a/src/tox.ini b/src/tox.ini index b54938f74e3..06ab0b18a0d 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -106,10 +106,11 @@ description = # E713 test for membership should be 'not in' # E721: do not compare types, use isinstance() # E722: do not use bare except, specify exception instead + # W391: blank line at end of file # W605: invalid escape sequence ‘x’ # See https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes deps = pycodestyle -commands = pycodestyle --select E111,E306,E401,E701,E702,E703,W605,E711,E712,E713,E721,E722 {posargs:{toxinidir}/sage/} +commands = pycodestyle --select E111,E306,E401,E701,E702,E703,W391,W605,E711,E712,E713,E721,E722 {posargs:{toxinidir}/sage/} pycodestyle --select E111,E401,E703,E712,E713,E721,E722 --filename *.pyx {posargs:{toxinidir}/sage/} [pycodestyle] @@ -196,6 +197,7 @@ rst-roles = data, exc, func, + kbd, meth, mod, obj, diff --git a/tox.ini b/tox.ini index 0106e693891..89541088306 100644 --- a/tox.ini +++ b/tox.ini @@ -509,6 +509,8 @@ setenv = python3.11: PYTHON_MINOR=11 CONFIG_CONFIGURE_ARGS_1=--with-system-python3=yes python3_spkg: CONFIG_CONFIGURE_ARGS_1=--without-system-python3 + python3.8,python3.9,python3.10,python3.11: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=python{env:PYTHON_MAJOR}.{env:PYTHON_MINOR} + python3.8,python3.9,python3.10,python3.11: EXTRA_SAGE_PACKAGES=_python{env:PYTHON_MAJOR}.{env:PYTHON_MINOR} _bootstrap liblzma bzip2 libffi libpng macos-python3_xcode: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/usr/bin/python3 macos-{python3_xcode,nohomebrew}-{python3.8}: CONFIG_CONFIGURE_ARGS_1=--with-system-python3=force --with-python=/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/{env:PYTHON_MAJOR}.{env:PYTHON_MINOR}/bin/python3 # Homebrew keg installs