diff --git a/.ci/write-dockerfile.sh b/.ci/write-dockerfile.sh index cfd4fb20810..7a3512dafd9 100755 --- a/.ci/write-dockerfile.sh +++ b/.ci/write-dockerfile.sh @@ -275,11 +275,11 @@ cat <- ${{ github.event_name == 'pull_request' - && fromJson('["ubuntu-latest"]') + && fromJson('["ubuntu-latest", "macos-latest"]') || fromJson('["ubuntu-latest", "macos-latest", "macos-13"]') }} - python: >- - ${{ github.event_name == 'pull_request' - && fromJson('["3.9"]') - || fromJson('["3.9", "3.10", "3.11"]') }} + python: ['3.11', '3.12'] # Optional environment is disabled for now as its not yet working # environment: [environment, environment-optional] conda-env: [environment] - # On pull requests, only test two jobs: - # Ubuntu with Python 3.9, macOS (arm64) with Python 3.11. - # Build & Test currently uses Python 3.10 (on ubuntu-jammy). - # Together, they cover the supported minor Python versions. - include: >- - ${{ github.event_name == 'pull_request' - && fromJson('[{"os": "macos-latest", "python": "3.11", "conda-env": "environment"}]') - || fromJson('[]') }} steps: - uses: actions/checkout@v4 @@ -69,7 +58,7 @@ jobs: use-mamba: true channels: conda-forge channel-priority: true - activate-environment: sage + activate-environment: sage-dev environment-file: ${{ matrix.conda-env }}-${{ matrix.python }}-${{ startsWith(matrix.os, 'macos') && (startsWith(runner.arch, 'ARM') && 'macos' || 'macos-x86_64') || 'linux' }}.yml - name: Print Conda environment diff --git a/.github/workflows/ci-meson.yml b/.github/workflows/ci-meson.yml index d2ceb1a1b9b..ab073aae87c 100644 --- a/.github/workflows/ci-meson.yml +++ b/.github/workflows/ci-meson.yml @@ -23,7 +23,7 @@ jobs: fail-fast: false matrix: os: [ubuntu] - python: ['3.9', '3.10', '3.11'] + python: ['3.11', '3.12'] steps: - uses: actions/checkout@v4 @@ -47,14 +47,14 @@ jobs: key: ${{ runner.os }}-meson-${{ matrix.python }} - name: Setup Conda environment - uses: conda-incubator/setup-miniconda@v2 + uses: conda-incubator/setup-miniconda@v3 with: python-version: ${{ matrix.python }} miniforge-version: latest use-mamba: true channels: conda-forge channel-priority: true - activate-environment: sage + activate-environment: sage-dev environment-file: environment-${{ matrix.python }}-${{ startsWith(matrix.os, 'macos') && (startsWith(runner.arch, 'ARM') && 'macos' || 'macos-x86_64') || 'linux' }}.yml - name: Print Conda environment @@ -69,7 +69,12 @@ jobs: export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" export CC="ccache $CC" export CXX="ccache $CXX" - pip install --no-build-isolation --config-settings=builddir=builddir . -v + # Use --no-deps and pip check below to verify that all necessary dependencies are installed via conda + pip install --no-build-isolation --no-deps --config-settings=builddir=builddir . -v + + - name: Verify dependencies + shell: bash -l {0} + run: pip check - name: Test shell: bash -l {0} @@ -77,3 +82,10 @@ jobs: # We don't install sage_setup, so don't try to test it rm -R ./src/sage_setup/ ./sage -t --all -p4 + + - name: Upload log + uses: actions/upload-artifact@v4.5.0 + if: failure() + with: + name: ${{ runner.os }}-meson-${{ matrix.python }}-log + path: builddir/meson-logs/ diff --git a/.github/workflows/conda-lock-update.py b/.github/workflows/conda-lock-update.py deleted file mode 100755 index ca71b631db3..00000000000 --- a/.github/workflows/conda-lock-update.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 - -from pathlib import Path -import subprocess - -script_dir = Path(__file__).resolve().parent -root_dir = script_dir / ".." / ".." - -subprocess.run([str(root_dir / "bootstrap-conda")]) - -platforms = { - "linux-64": "linux", - "linux-aarch64": "linux-aarch64", - "osx-64": "macos-x86_64", - "osx-arm64": "macos", - # "win-64": "win", -} -pythons = ["3.9", "3.10", "3.11"] -tags = ["", "-dev"] - -for platform_key, platform_value in platforms.items(): - for python in pythons: - for tag in tags: - env_file = root_dir / f"environment{tag}-{python}.yml" - lock_file = root_dir / f"environment{tag}-{python}-{platform_value}" - lock_file_gen = root_dir / f"environment{tag}-{python}-{platform_value}.yml" - - if not env_file.exists(): - continue - - print(f"Updating lock file for {env_file} at {lock_file_gen}", flush=True) - subprocess.run( - [ - "conda-lock", - "--mamba", - "--channel", - "conda-forge", - "--kind", - "env", - "--platform", - platform_key, - "--file", - str(env_file), - "--lockfile", - str(lock_file), - "--filename-template", - str(lock_file), - ], - check=True, - ) - - # Add conda env name to lock file at beginning - with open(lock_file_gen, "r+") as f: - content = f.read() - f.seek(0, 0) - f.write(f"name: sage{tag}\n{content}") diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml index 538b44d1431..b8800c8854b 100644 --- a/.github/workflows/dist.yml +++ b/.github/workflows/dist.yml @@ -119,10 +119,38 @@ jobs: with: name: dist path: dist - - uses: softprops/action-gh-release@v2 + - name: Create release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + latest_release_tag=$(curl -s https://api.github.com/repos/${{ github.repository }}/releases \ + | jq -r 'sort_by(.created_at) | last(.[]).tag_name') + release_notes=$(curl -s \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/${{ github.repository }}/releases/generate-notes \ + -d "{ + \"tag_name\": \"${{ github.ref_name }}\", + \"previous_tag_name\": \"$latest_release_tag\" + }" | jq -r '.body') + # escape special characters for json + release_notes=$(jq -R -s '.' <<< "$release_notes") + curl -L \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/${{ github.repository }}/releases \ + -d "{ + \"tag_name\": \"${{ github.ref_name }}\", + \"prerelease\": ${{ contains(github.ref, 'beta') || contains(github.ref, 'rc') }}, + \"body\": $release_notes + }" + - name: Create release assets + uses: softprops/action-gh-release@v2 with: - generate_release_notes: true - prerelease: ${{ contains(github.ref, 'beta') || contains(github.ref, 'rc') }} files: | dist/* upstream/* diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index 5eb5e932da9..f46317ecda7 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -154,6 +154,7 @@ jobs: git config --global user.email "ci-sage@example.com" git config --global user.name "Build documentation workflow" unzip doc.zip + rm doc.zip PR_NUMBER="" if [[ "$GITHUB_REF" =~ refs/pull/([0-9]+)/merge ]]; then PR_NUMBER="${BASH_REMATCH[1]}" @@ -202,6 +203,10 @@ jobs: if: steps.docbuild.outcome == 'success' run: | set -ex + # Remove any existing html directory before copying a new one + if [ -d "doc/html" ]; then + rm -rf doc/html + fi # Simpler "docker cp --follow-link ... doc" does not work mkdir -p doc mkdir -p temp @@ -217,7 +222,7 @@ jobs: fi # If so, then create CHANGES.html if [[ -n "$PR_NUMBER" ]]; then - (cd doc && git commit -a -m 'new') + (cd doc && git add -A && git commit --quiet -m 'new') # Wipe out chronic diffs of new doc against old doc before creating CHANGES.html (cd doc && \ find . -name "*.html" | xargs sed -i -e '/This is documentation/ s/ built with GitHub PR .* for development/ for development/' \ @@ -229,7 +234,7 @@ jobs: # Since HEAD is at commit 'wipe-out', HEAD~1 is commit 'new' (new doc), HEAD~2 is commit 'old' (old doc) (cd doc && git diff $(git rev-parse HEAD~2) -- "*.html") > diff.txt # Restore the new doc dropping changes by "wipe out" - (cd doc && git checkout -q -f HEAD~1) + (cd doc && git checkout --quiet -f HEAD~1) .ci/create-changes-html.sh diff.txt doc # Sometimes rm -rf .git errors out because of some diehard hidden files # So we simply move it out of the doc directory diff --git a/.gitignore b/.gitignore index 0df6ef10d98..b8bfc364a26 100644 --- a/.gitignore +++ b/.gitignore @@ -18,7 +18,6 @@ /config.log /config.status /configure -/conftest* /confdefs.h /m4/sage_spkg_configures.m4 @@ -27,13 +26,11 @@ # no longer generated, but may still be in user worktrees /src/lib/pkgconfig -# Environment files generated by bootstrap-conda. -# The files without Python version and in src are no longer generated -# but may still be in users' directories. +# Conda environment files (auto-generated) +/environment-3.[0-9].yml +/environment-3.[0-9][0-9].yml +# The following files are no longer generated but may still be in users' directories /environment.yml -/environment-3.9.yml -/environment-3.10.yml -/environment-3.11.yml /environment-dev-3.9.yml /environment-dev-3.10.yml /environment-dev-3.11.yml @@ -56,10 +53,6 @@ /src/setup.cfg /src/requirements.txt -/src/Pipfile -/src/Pipfile.lock -/Pipfile -/Pipfile.lock # Various editors *~ diff --git a/.gitpod.yml b/.gitpod.yml index 6ebcf7f67a4..554a5c41f4b 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -7,7 +7,7 @@ tasks: - name: Setup # Create conda environment, then configure and build sage init: >- - && mamba env create --file environment-dev-3.11-linux.yml --prefix venv + && mamba env create --file environment-3.11-linux.yml --prefix venv && conda config --append envs_dirs $(pwd) && conda activate $(pwd)/venv && ./bootstrap diff --git a/.upstream.d/20-github.com-sagemath-sage-releases b/.upstream.d/20-github.com-sagemath-sage-releases index 399ee84dbd6..ed442b3039e 100644 --- a/.upstream.d/20-github.com-sagemath-sage-releases +++ b/.upstream.d/20-github.com-sagemath-sage-releases @@ -1,5 +1,5 @@ # Upstream packages as uploaded as GitHub release assets. # This file is automatically updated by the sage-update-version script. +https://github.com/sagemath/sage/releases/download/10.6/ https://github.com/sagemath/sage/releases/download/10.5/ https://github.com/sagemath/sage/releases/download/10.4/ -https://github.com/sagemath/sage/releases/download/10.3/ diff --git a/.vscode/settings.json b/.vscode/settings.json index bf6ab3e7c3a..8998f229f9f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,17 +18,101 @@ }, "python.testing.pytestEnabled": true, "python.testing.pytestArgs": [ - "--rootdir=src/sage", - "-c=src/tox.ini", - "--doctest-modules" + "--doctest" ], "python.testing.unittestEnabled": false, "cSpell.words": [ - "furo", + "adic", + "arccos", + "arccosh", + "arcsin", + "arcsinh", + "arctan", + "arctanh", + "Bejger", + "bigcup", + "cachefunc", + "charpoly", + "classmethod", + "clopen", + "codim", + "codomain", + "coframe", + "coframes", "Conda", + "cputime", + "cysignals", + "Cython", + "d'Alembertian", + "dalembertian", + "disp", + "doctest", + "doctests", + "emptyset", + "figsize", + "Florentin", + "fontsize", + "forall", + "furo", + "Gourgoulhon", + "grayskull", + "groebner", + "homeomorphic", + "homset", + "homsets", + "hypersurfaces", + "infty", + "Jaffredo", + "Katsura", + "Koeppe", + "longmapsto", + "longrightarrow", + "mapsto", + "mathbb", + "mathrm", + "Michal", + "micjung", + "Minkowski", + "Möbius", + "mpfr", + "nabla", + "Nullspace", + "padics", + "pari", + "prandom", + "Pynac", + "rightarrow", "sagemath", - "Cython" + "scalarfield", + "SEEALSO", + "setminus", + "smithform", + "subchart", + "subcharts", + "subframe", + "subframes", + "subobjects", + "subring", + "superchart", + "supercharts", + "supersets", + "sympy", + "tensorfield", + "trigsimp", + "varphi", + "vbundle", + "vecmat", + "vectorfield", + "walltime", + "zmax", + "zmin" ], "editor.formatOnType": true, - "esbonio.sphinx.confDir": "" + "esbonio.sphinx.confDir": "", + // Don't update the settings.json file with values inferred from Meson (we provide them manually) + "mesonbuild.modifySettings": false, + // Use the Meson build system for C/C++ files + "C_Cpp.default.configurationProvider": "mesonbuild.mesonbuild", + // Use the compile_commands.json file generated by Meson for IntelliSense + "C_Cpp.default.compileCommands": "${workspaceFolder}/builddir/compile_commands.json" } diff --git a/CITATION.cff b/CITATION.cff index c0dbf3d6a37..1a4f50ce0c0 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -4,8 +4,8 @@ title: SageMath abstract: SageMath is a free open-source mathematics software system. authors: - name: "The SageMath Developers" -version: 10.5.rc2 +version: 10.6.beta4 doi: 10.5281/zenodo.8042260 -date-released: 2024-11-30 +date-released: 2025-01-18 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/Makefile b/Makefile index 96d1ba62e94..6bc60acdca3 100644 --- a/Makefile +++ b/Makefile @@ -173,9 +173,8 @@ distclean: build-clean bootstrap-clean: rm -rf config/install-sh config/compile config/config.guess config/config.sub config/missing configure build/make/Makefile-auto.in rm -f src/doc/en/installation/*.txt - find src/doc/en/reference/spkg -name index.rst -prune -o -maxdepth 1 -name "*.rst" -exec rm -f {} \+ - for a in environment environment-optional src/environment src/environment-dev src/environment-optional; do rm -f $$a.yml $$a-3.[89].yml $$a-3.1[0-9].yml; done - rm -f src/Pipfile + find src/doc/en/reference/spkg -maxdepth 1 -name index.rst -prune -o -name "*.rst" -exec rm -f {} \+ + for a in environment environment-optional src/environment src/environment-optional; do rm -f $$a.yml $$a-3.[89].yml $$a-3.1[0-9].yml; done rm -f src/requirements.txt rm -f src/setup.cfg rm -f build/pkgs/cypari/version_requirements.txt diff --git a/Pipfile.m4 b/Pipfile.m4 deleted file mode 100644 index e7dd86744a0..00000000000 --- a/Pipfile.m4 +++ /dev/null @@ -1,40 +0,0 @@ -## Pipfile with all packages in the Sage distribution and version information locked -## FIXME: Many packages still missing. -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -pkgconfig = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../pkgconfig/package-version.txt)')" -cython = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../cython/package-version.txt)')" -pycodestyle = "*" -ipykernel = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../ipykernel/package-version.txt)')" -tox = "*" -jinja2 = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../jinja2/package-version.txt)')" -pytest = "*" -ipywidgets = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../ipywidgets/package-version.txt)')" -sphinx = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../sphinx/package-version.txt)')" -rope = "*" -six = "*" -jupyter-core = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../jupyter_core/package-version.txt)')" - -[packages] -numpy = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../numpy/package-version.txt)')" -cysignals = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../cysignals/package-version.txt)')" -cypari2 = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../cypari/package-version.txt)')" -gmpy2 = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../gmpy2/package-version.txt)')" -pexpect = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../pexpect/package-version.txt)')" -ipython = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../ipython/package-version.txt)')" -sympy = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../sympy/package-version.txt)')" -scipy = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../scipy/package-version.txt)')" -pplpy = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../pplpy/package-version.txt)')" -matplotlib = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../matplotlib/package-version.txt)')" -cvxopt = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../cvxopt/package-version.txt)')" -rpy2 = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../rpy2/package-version.txt)')" -networkx = "==esyscmd(`printf $(sed "s/[.]p.*//;" ../networkx/package-version.txt)')" - -sagemath-standard = { path = "src" } - -[requires] -python_version = "3.9" diff --git a/README.md b/README.md index af91374fe19..f54d7ad34b6 100644 --- a/README.md +++ b/README.md @@ -679,7 +679,7 @@ information, patches, and build scripts are in the accompanying part of the Sage git repository.

- Copyright (C) 2005-2024 The Sage Development Team + Copyright (C) 2005-2025 The Sage Development Team

https://www.sagemath.org diff --git a/VERSION.txt b/VERSION.txt index 219cada0e3f..c6b18bd1ad9 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.5.rc2, Release Date: 2024-11-30 +SageMath version 10.6.beta4, Release Date: 2025-01-18 diff --git a/bootstrap b/bootstrap index 9d19e756a38..00c2a1f7d54 100755 --- a/bootstrap +++ b/bootstrap @@ -139,7 +139,6 @@ EOF # ONLY stderr, and to re-output the results back to stderr leaving # stdout alone. Basically we swap the two descriptors using a # third, filter, and then swap them back. - ./bootstrap-conda && \ aclocal -I m4 && \ automake --add-missing --copy build/make/Makefile-auto 3>&1 1>&2 2>&3 \ | sed "${QUIET_SED_FILTER}" 3>&1 1>&2 2>&3 && \ @@ -225,9 +224,8 @@ save () { config/install-sh config/compile config/config.guess config/config.sub config/missing \ build/make/Makefile-auto.in \ src/doc/en/installation/*.txt \ - $(find src/doc/en/reference/spkg -name index.rst -prune -o -maxdepth 1 -name "*.rst" -print) \ - environment-3.[89].yml environment-3.1[0-9].yml \ - src/Pipfile \ + $(find src/doc/en/reference/spkg -maxdepth 1 -name index.rst -prune -o -name "*.rst" -print) \ + environment-3.1[0-9]-*.yml \ src/pyproject.toml \ src/requirements.txt \ src/setup.cfg \ @@ -237,6 +235,7 @@ save () { build/pkgs/gmpy2/version_requirements.txt \ build/pkgs/jupyter_core/version_requirements.txt \ build/pkgs/memory_allocator/version_requirements.txt \ + build/pkgs/meson/version_requirements.txt \ build/pkgs/numpy/version_requirements.txt \ build/pkgs/pkgconfig/version_requirements.txt \ build/pkgs/pplpy/version_requirements.txt \ diff --git a/bootstrap-conda b/bootstrap-conda deleted file mode 100755 index 157700ee809..00000000000 --- a/bootstrap-conda +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env bash - -######################################################################## -# Generate auto-generated conda environment files -######################################################################### - -export PATH="$(pwd)/build/bin:$PATH" - -STRIP_COMMENTS="sed s/#.*//;" - -shopt -s extglob - -DEVELOP_SPKG_PATTERN="@(_develop$(for a in $(head -n 1 build/pkgs/_develop/dependencies); do echo -n "|"$a; done))" -BOOTSTRAP_PACKAGES=_bootstrap -PACKAGES= -OPTIONAL_PACKAGES= -SAGELIB_PACKAGES= -SAGELIB_OPTIONAL_PACKAGES= -DEVELOP_PACKAGES= - -eval $(sage-package properties --format=shell :all:) - -for PKG_BASE in $(sage-package list --has-file distros/conda.txt --exclude _sagemath); do - eval PKG_SCRIPTS=\$path_$PKG_BASE PKG_TYPE=\$type_$PKG_BASE - SYSTEM_PACKAGES_FILE=$PKG_SCRIPTS/distros/conda.txt - PKG_SYSTEM_PACKAGES=$(echo $(${STRIP_COMMENTS} $SYSTEM_PACKAGES_FILE)) - if [ -n "$PKG_SYSTEM_PACKAGES" ]; then - if [ -f $PKG_SCRIPTS/spkg-configure.m4 ]; then - if grep -q SAGE_PYTHON_PACKAGE_CHECK $PKG_SCRIPTS/spkg-configure.m4; then - # Python package that would need --enable-system-site-packages to be used - # with the Sage distribution, but we do not recommend that for conda. - PKG_SAGELIB_ONLY=yes - else - PKG_SAGELIB_ONLY=no - fi - else - # No spkg-configure, so the Sage distribution is not able to make use of this package. - PKG_SAGELIB_ONLY=yes - fi - [ -n "$BOOTSTRAP_VERBOSE" ] && echo "$PKG_BASE:$PKG_TYPE:$PKG_SAGELIB_ONLY" - if [ $PKG_SAGELIB_ONLY = no ]; then - case "$PKG_BASE:$PKG_TYPE" in - *:standard) - PACKAGES+=" $PKG_BASE" - ;; - $DEVELOP_SPKG_PATTERN:*) - DEVELOP_PACKAGES+=" $PKG_BASE" - ;; - *) - OPTIONAL_PACKAGES+=" $PKG_BASE" - ;; - esac - else - case "$PKG_BASE:$PKG_TYPE" in - *:standard) - SAGELIB_PACKAGES+=" $PKG_BASE" - ;; - $DEVELOP_SPKG_PATTERN:*) - DEVELOP_PACKAGES+=" $PKG_BASE" - ;; - *) - SAGELIB_OPTIONAL_PACKAGES+=" $PKG_BASE" - ;; - esac - fi - fi -done -unset PKG_SYSTEM_PACKAGES - -[ -n "$BOOTSTRAP_VERBOSE" ] && echo "## Collected:" && set | grep PACKAGES= - -# Translate to system packages -export ENABLE_SYSTEM_SITE_PACKAGES=yes # Disable filtering in sage-get-system-packages -SYSTEM_PACKAGES=$(sage-get-system-packages conda $PACKAGES) -BOOTSTRAP_SYSTEM_PACKAGES=$(sage-get-system-packages conda $BOOTSTRAP_PACKAGES) -OPTIONAL_SYSTEM_PACKAGES=$(sage-get-system-packages conda $OPTIONAL_PACKAGES) -SAGELIB_SYSTEM_PACKAGES=$(sage-get-system-packages conda $SAGELIB_PACKAGES) -SAGELIB_OPTIONAL_SYSTEM_PACKAGES=$(sage-get-system-packages conda $SAGELIB_OPTIONAL_PACKAGES) -DEVELOP_SYSTEM_PACKAGES=$(sage-get-system-packages conda $DEVELOP_PACKAGES) -unset ENABLE_SYSTEM_SITE_PACKAGES - -[ -n "$BOOTSTRAP_VERBOSE" ] && echo "## Translated to system:" && set | grep SYSTEM_PACKAGES= - -echo >&2 $0:$LINENO: generate conda environment files - - ( - echo "name: sage" - echo "channels:" - echo " - conda-forge" - echo " - nodefaults" - echo "dependencies:" - for pkg in $SYSTEM_PACKAGES; do - echo " - $pkg" - done - echo " # Packages needed for ./bootstrap" - for pkg in $BOOTSTRAP_SYSTEM_PACKAGES; do - echo " - $pkg" - done - ) > environment-template.yml - ( - sed 's/name: sage-build/name: sage/' environment-template.yml - echo " - meson" - echo " - meson-python" - echo " - pytest" - echo " # Additional packages providing all dependencies for the Sage library" - for pkg in $SAGELIB_SYSTEM_PACKAGES; do - echo " - $pkg" - done - ) > environment-template.yml - - ( - sed 's/name: sage/name: sage-dev/' environment-template.yml - echo " # Additional dev tools" - echo " - conda-lock" - for pkg in $DEVELOP_SYSTEM_PACKAGES; do - echo " - $pkg" - done - ) > environment-dev-template.yml - -for f in environment environment-dev; do - for python_version in 3.9 3.10 3.11; do - sed -E 's/^( *- *)python *$/\1python='$python_version'/' $f-template.yml > $f-$python_version.yml - done - rm -f $f-template.yml -done diff --git a/build/bin/sage-dist-helpers b/build/bin/sage-dist-helpers index 520b6ceec5a..f8d07741612 100644 --- a/build/bin/sage-dist-helpers +++ b/build/bin/sage-dist-helpers @@ -71,10 +71,9 @@ # # - sdh_cmake [...] # -# Runs `cmake` in the current directory with the given arguments, as well as -# additional arguments passed to cmake (assuming packages are using the -# GNUInstallDirs module) so that `CMAKE_INSTALL_PREFIX` and -# `CMAKE_INSTALL_LIBDIR` are set correctly. +# Runs `cmake` with the given arguments, as well as additional arguments +# (assuming packages are using the GNUInstallDirs module) so that +# `CMAKE_INSTALL_PREFIX` and `CMAKE_INSTALL_LIBDIR` are set correctly. # # - sdh_install [-T] SRC [SRC...] DEST # @@ -416,9 +415,9 @@ sdh_pip_uninstall() { sdh_cmake() { echo "Configuring $PKG_NAME with cmake" - cmake . -DCMAKE_INSTALL_PREFIX="${SAGE_INST_LOCAL}" \ - -DCMAKE_INSTALL_LIBDIR=lib \ - "$@" + cmake -DCMAKE_INSTALL_PREFIX="${SAGE_INST_LOCAL}" \ + -DCMAKE_INSTALL_LIBDIR=lib \ + "$@" if [ $? -ne 0 ]; then if [ -f "$(pwd)/CMakeFiles/CMakeOutput.log" ]; then sdh_die <<_EOF_ diff --git a/build/pkgs/bliss/spkg-install.in b/build/pkgs/bliss/spkg-install.in index b988d6262ce..b203f30dcab 100644 --- a/build/pkgs/bliss/spkg-install.in +++ b/build/pkgs/bliss/spkg-install.in @@ -3,6 +3,6 @@ if [ "$UNAME" = "Darwin" ]; then export LDFLAGS fi cd src -sdh_cmake -DUSE_GMP=OFF -DCMAKE_VERBOSE_MAKEFILE=ON +sdh_cmake -DUSE_GMP=OFF -DCMAKE_VERBOSE_MAKEFILE=ON . sdh_make sdh_make_install diff --git a/build/pkgs/ccache/checksums.ini b/build/pkgs/ccache/checksums.ini index 2b4b1895243..23eadcfc9b7 100644 --- a/build/pkgs/ccache/checksums.ini +++ b/build/pkgs/ccache/checksums.ini @@ -1,3 +1,4 @@ -tarball=ccache-VERSION.tar.bz2 -sha1=3653e0765f01697c449f7026c479fbd9526323a7 -sha256=fa9d7f38367431bc86b19ad107d709ca7ecf1574fdacca01698bdf0a47cd8567 +tarball=ccache-VERSION.tar.xz +sha1=cff97f7592f5042eb43cb54a6d12a1ce7e49da62 +sha256=c0b85ddfc1a3e77b105ec9ada2d24aad617fa0b447c6a94d55890972810f0f5a +upstream_url=https://github.com/ccache/ccache/releases/download/vVERSION/ccache-VERSION.tar.xz diff --git a/build/pkgs/ccache/dependencies b/build/pkgs/ccache/dependencies index a1eb8a80d3d..e1c0b124beb 100644 --- a/build/pkgs/ccache/dependencies +++ b/build/pkgs/ccache/dependencies @@ -1,4 +1,4 @@ -zlib +cmake xz ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/ccache/distros/arch.txt b/build/pkgs/ccache/distros/arch.txt new file mode 100644 index 00000000000..812b9efc0c5 --- /dev/null +++ b/build/pkgs/ccache/distros/arch.txt @@ -0,0 +1 @@ +ccache diff --git a/build/pkgs/ccache/package-version.txt b/build/pkgs/ccache/package-version.txt index a0891f563f3..0216ba38478 100644 --- a/build/pkgs/ccache/package-version.txt +++ b/build/pkgs/ccache/package-version.txt @@ -1 +1 @@ -3.3.4 +4.10.2 diff --git a/build/pkgs/ccache/patches/01-apple-gcc-id.patch b/build/pkgs/ccache/patches/01-apple-gcc-id.patch deleted file mode 100644 index fec64b61d85..00000000000 --- a/build/pkgs/ccache/patches/01-apple-gcc-id.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/test.sh b/test.sh -index b4c95b1..e51b4bc 100755 ---- a/test.sh -+++ b/test.sh -@@ -3354,6 +3354,10 @@ case $compiler_version in - *clang*) - COMPILER_TYPE_CLANG=true - ;; -+ *Xcode.app*) -+# /usr/bin/gcc on OS X which is a front end to clang doesn't have gcc or clang in the first line. -+ COMPILER_TYPE_CLANG=true -+ ;; - *) - echo "WARNING: Compiler $COMPILER not supported (version: $compiler_version) -- not running tests" >&2 - exit 0 diff --git a/build/pkgs/ccache/spkg-install.in b/build/pkgs/ccache/spkg-install.in index 3ed82ae521c..6e7bcf1fc55 100644 --- a/build/pkgs/ccache/spkg-install.in +++ b/build/pkgs/ccache/spkg-install.in @@ -1,14 +1,14 @@ cd src -# Use newer version of config.guess and config.sub (see Issue #23710) -cp "$SAGE_ROOT"/config/config.* . - -export CPPFLAGS="-I$SAGE_LOCAL/include $CPPFLAGS" -sdh_configure +mkdir build +cd build +sdh_cmake -DCMAKE_BUILD_TYPE=Release \ + -DENABLE_TESTING=OFF \ + -DREDIS_STORAGE_BACKEND=OFF \ + .. sdh_make sdh_make_install - set -e mkdir -p "$SAGE_LOCAL/libexec/ccache" @@ -21,4 +21,4 @@ ln -sf ../../bin/ccache "$SAGE_LOCAL/libexec/ccache/clang++" # Copy a reasonable default configuration for Sage # (cache size of 4G and compression enabled) -cp -p ../ccache.conf "$SAGE_LOCAL/etc" +cp -p ../../ccache.conf "$SAGE_LOCAL/etc" diff --git a/build/pkgs/cmake/checksums.ini b/build/pkgs/cmake/checksums.ini index 477a967711a..812e28398b0 100644 --- a/build/pkgs/cmake/checksums.ini +++ b/build/pkgs/cmake/checksums.ini @@ -1,4 +1,4 @@ tarball=cmake-VERSION.tar.gz -sha1=05de9ac807fefeb2a36ed5e8fcea376a00dd3d57 -sha256=fece24563f697870fbb982ea8bf17482c9d5f855d8c9bf0b82463d76c9e8d0cc +sha1=b87bd9de209a60d7bc81b8fed594ea26adb4f716 +sha256=42abb3f48f37dbd739cdfeb19d3712db0c5935ed5c2aef6c340f9ae9114238a2 upstream_url=https://github.com/Kitware/CMake/releases/download/vVERSION/cmake-VERSION.tar.gz diff --git a/build/pkgs/cmake/package-version.txt b/build/pkgs/cmake/package-version.txt index f641ba7ef04..4464a71f413 100644 --- a/build/pkgs/cmake/package-version.txt +++ b/build/pkgs/cmake/package-version.txt @@ -1 +1 @@ -3.27.8 +3.31.2 diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 7d0a957c854..8adc17b1426 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,3 +1,3 @@ tarball=configure-VERSION.tar.gz -sha1=4d6de7b4a5aff43a508a1e64078fe409554869fe -sha256=18cc6fa95c0bd6ae0bf1f9b447ae2dd9da7d596d17bec5e961b980b9687e1a7e +sha1=f9c1bea6113a6a09430ee1f1aca16c75ed427d48 +sha256=c1e0826fb54dd60e78f19e6fcad0b0ef90b33e1771fbbc2165a54c9297a89557 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 8c7663a9fa1..0597496b77d 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -68f446ad3f1abcea6e1a9b679a04242597f439f6 +5eb37241946a9ef9130ce36eff7e4f135d980eaf diff --git a/build/pkgs/dsdp/spkg-install.in b/build/pkgs/dsdp/spkg-install.in index 5d0ecadf030..238cc83b279 100644 --- a/build/pkgs/dsdp/spkg-install.in +++ b/build/pkgs/dsdp/spkg-install.in @@ -5,6 +5,7 @@ sdh_cmake -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=ON \ -DBLA_VENDOR=OpenBLAS \ -DBLAS_LIBRARIES="$(pkg-config --libs blas)" \ - -DLAPACK_LIBRARIES="$(pkg-config --libs lapack)" + -DLAPACK_LIBRARIES="$(pkg-config --libs lapack)" \ + . sdh_make sdh_make_install diff --git a/build/pkgs/execnet/distros/arch.txt b/build/pkgs/execnet/distros/arch.txt new file mode 100644 index 00000000000..3462eb00113 --- /dev/null +++ b/build/pkgs/execnet/distros/arch.txt @@ -0,0 +1 @@ +python-execnet diff --git a/build/pkgs/execnet/distros/debian.txt b/build/pkgs/execnet/distros/debian.txt new file mode 100644 index 00000000000..242410655f3 --- /dev/null +++ b/build/pkgs/execnet/distros/debian.txt @@ -0,0 +1 @@ +python3-execnet diff --git a/build/pkgs/execnet/distros/fedora.txt b/build/pkgs/execnet/distros/fedora.txt new file mode 100644 index 00000000000..242410655f3 --- /dev/null +++ b/build/pkgs/execnet/distros/fedora.txt @@ -0,0 +1 @@ +python3-execnet diff --git a/build/pkgs/execnet/distros/gentoo.txt b/build/pkgs/execnet/distros/gentoo.txt new file mode 100644 index 00000000000..ce0a8471ea6 --- /dev/null +++ b/build/pkgs/execnet/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/execnet diff --git a/build/pkgs/execnet/distros/void.txt b/build/pkgs/execnet/distros/void.txt new file mode 100644 index 00000000000..242410655f3 --- /dev/null +++ b/build/pkgs/execnet/distros/void.txt @@ -0,0 +1 @@ +python3-execnet diff --git a/build/pkgs/execnet/spkg-configure.m4 b/build/pkgs/execnet/spkg-configure.m4 new file mode 100644 index 00000000000..82f8824ba87 --- /dev/null +++ b/build/pkgs/execnet/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([execnet], [SAGE_PYTHON_PACKAGE_CHECK([execnet])]) diff --git a/build/pkgs/iniconfig/distros/arch.txt b/build/pkgs/iniconfig/distros/arch.txt new file mode 100644 index 00000000000..3b2e261329f --- /dev/null +++ b/build/pkgs/iniconfig/distros/arch.txt @@ -0,0 +1 @@ +python-iniconfig diff --git a/build/pkgs/iniconfig/distros/debian.txt b/build/pkgs/iniconfig/distros/debian.txt new file mode 100644 index 00000000000..db703500b14 --- /dev/null +++ b/build/pkgs/iniconfig/distros/debian.txt @@ -0,0 +1 @@ +python3-iniconfig diff --git a/build/pkgs/iniconfig/distros/fedora.txt b/build/pkgs/iniconfig/distros/fedora.txt new file mode 100644 index 00000000000..db703500b14 --- /dev/null +++ b/build/pkgs/iniconfig/distros/fedora.txt @@ -0,0 +1 @@ +python3-iniconfig diff --git a/build/pkgs/iniconfig/distros/gentoo.txt b/build/pkgs/iniconfig/distros/gentoo.txt new file mode 100644 index 00000000000..962de2510d3 --- /dev/null +++ b/build/pkgs/iniconfig/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/iniconfig diff --git a/build/pkgs/iniconfig/distros/void.txt b/build/pkgs/iniconfig/distros/void.txt new file mode 100644 index 00000000000..db703500b14 --- /dev/null +++ b/build/pkgs/iniconfig/distros/void.txt @@ -0,0 +1 @@ +python3-iniconfig diff --git a/build/pkgs/iniconfig/spkg-configure.m4 b/build/pkgs/iniconfig/spkg-configure.m4 new file mode 100644 index 00000000000..8c94fdf4986 --- /dev/null +++ b/build/pkgs/iniconfig/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([iniconfig], [SAGE_PYTHON_PACKAGE_CHECK([iniconfig])]) diff --git a/build/pkgs/libbraiding/checksums.ini b/build/pkgs/libbraiding/checksums.ini index 5a956e027bf..0795b89fdf6 100644 --- a/build/pkgs/libbraiding/checksums.ini +++ b/build/pkgs/libbraiding/checksums.ini @@ -1,4 +1,4 @@ tarball=libbraiding-VERSION-actually-VERSION.tar.gz -sha1=b7e13778784fe1e36e7c0cbd7a4c234a090cd1b2 -sha256=73087d1145ace719eafeda1db1c28b5fe1c981b7e784dc59f2b1d6fc4ff75f80 +sha1=8c22d5d396e2c4d2dd032172589042933b651108 +sha256=d1738c3ad64a90ca0ad968d2e3c9069b0de08abcf37fb44a151a229d88203950 upstream_url=https://github.com/miguelmarco/libbraiding/releases/download/VERSION/libbraiding-VERSION.tar.gz diff --git a/build/pkgs/libbraiding/package-version.txt b/build/pkgs/libbraiding/package-version.txt index 5625e59da88..3a3cd8cc8b0 100644 --- a/build/pkgs/libbraiding/package-version.txt +++ b/build/pkgs/libbraiding/package-version.txt @@ -1 +1 @@ -1.2 +1.3.1 diff --git a/build/pkgs/libbraiding/spkg-configure.m4 b/build/pkgs/libbraiding/spkg-configure.m4 index 8fd86aa20ea..67d80d77a64 100644 --- a/build/pkgs/libbraiding/spkg-configure.m4 +++ b/build/pkgs/libbraiding/spkg-configure.m4 @@ -1,50 +1,9 @@ SAGE_SPKG_CONFIGURE([libbraiding], [ - # Since libbraiding is a C++ library with no pkg-config file, - # the best we can do here is compile and run a test program - # linked against it. - AC_LANG_PUSH(C++) - SAVED_LIBS=$LIBS - LIBS="$LIBS -lbraiding" - AC_MSG_CHECKING([if we can link against libbraiding]) - AC_RUN_IFELSE([ - AC_LANG_PROGRAM([ - #include - #include - using namespace Braiding; - ],[ - // Mimic BraidGroup(2)([1,1]).thurston_type() in SageMath. - // thurstontype == 1 corresponds to "periodic" - if (thurstontype(2, {1,1}) == 1) { return 0; } else { return 1; } - ]) - ], - [ - AC_MSG_RESULT([yes]) + PKG_CHECK_MODULES([libbraiding], [libbraiding >= 1.3.1], [ + AC_MSG_RESULT([found libbraiding >= 1.3.1, will use installed version]) sage_spkg_install_libbraiding=no - ], - [ - AC_MSG_RESULT([no]) - sage_spkg_install_libbraiding=yes ],[ - AC_LINK_IFELSE([ - AC_LANG_PROGRAM([ - #include - #include - using namespace Braiding; - ],[ - // Mimic BraidGroup(2)([1,1]).thurston_type() in SageMath. - // thurstontype == 1 corresponds to "periodic" - if (thurstontype(2, {1,1}) == 1) { return 0; } else { return 1; } - ]) - ], - [ - AC_MSG_RESULT([yes]) - sage_spkg_install_libbraiding=no - ], - [ - AC_MSG_RESULT([no]) - sage_spkg_install_libbraiding=yes - ]) + AC_MSG_RESULT([couldn't find libbraiding >= 1.3.1. It will be installed]) + sage_spkg_install_libbraiding=yes ]) - LIBS=$SAVED_LIBS - AC_LANG_POP ]) diff --git a/build/pkgs/libtheora/SPKG.rst b/build/pkgs/libtheora/SPKG.rst deleted file mode 100644 index 0c2c9e1c642..00000000000 --- a/build/pkgs/libtheora/SPKG.rst +++ /dev/null @@ -1,54 +0,0 @@ -libtheora: Library for the Theora video codec -============================================= - -Description ------------ - -libtheora is the official reference library for the Theora video codec. -Theora is a free and open video compression format from the Xiph.org -Foundation. - -Website: http://www.xiph.org/theora - -License -------- - -Copyright (c) 2002, Xiph.org Foundation - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -- Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -- Neither the name of the Xiph.org Foundation nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Upstream Contact ----------------- - -The Xiph.org mailing lists - see http://lists.xiph.org/mailman/listinfo - -Special Update/Build Instructions ---------------------------------- - -- No changes went into src. diff --git a/build/pkgs/libtheora/checksums.ini b/build/pkgs/libtheora/checksums.ini deleted file mode 100644 index b940bb462c1..00000000000 --- a/build/pkgs/libtheora/checksums.ini +++ /dev/null @@ -1,3 +0,0 @@ -tarball=libtheora-VERSION.tar.bz2 -sha1=8dcaa8e61cd86eb1244467c0b64b9ddac04ae262 -sha256=b6ae1ee2fa3d42ac489287d3ec34c5885730b1296f0801ae577a35193d3affbc diff --git a/build/pkgs/libtheora/dependencies b/build/pkgs/libtheora/dependencies deleted file mode 100644 index e62d879d3a4..00000000000 --- a/build/pkgs/libtheora/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -libogg libpng - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/libtheora/distros/conda.txt b/build/pkgs/libtheora/distros/conda.txt deleted file mode 100644 index 944587f5d50..00000000000 --- a/build/pkgs/libtheora/distros/conda.txt +++ /dev/null @@ -1 +0,0 @@ -libtheora diff --git a/build/pkgs/libtheora/distros/fedora.txt b/build/pkgs/libtheora/distros/fedora.txt deleted file mode 100644 index 8043f5eea67..00000000000 --- a/build/pkgs/libtheora/distros/fedora.txt +++ /dev/null @@ -1,2 +0,0 @@ -libtheora -libtheora-devel diff --git a/build/pkgs/libtheora/distros/homebrew.txt b/build/pkgs/libtheora/distros/homebrew.txt deleted file mode 100644 index bddb694122d..00000000000 --- a/build/pkgs/libtheora/distros/homebrew.txt +++ /dev/null @@ -1 +0,0 @@ -theora diff --git a/build/pkgs/libtheora/distros/macports.txt b/build/pkgs/libtheora/distros/macports.txt deleted file mode 100644 index 944587f5d50..00000000000 --- a/build/pkgs/libtheora/distros/macports.txt +++ /dev/null @@ -1 +0,0 @@ -libtheora diff --git a/build/pkgs/libtheora/distros/opensuse.txt b/build/pkgs/libtheora/distros/opensuse.txt deleted file mode 100644 index 156db81fdea..00000000000 --- a/build/pkgs/libtheora/distros/opensuse.txt +++ /dev/null @@ -1 +0,0 @@ -pkgconfig(theora) diff --git a/build/pkgs/libtheora/distros/repology.txt b/build/pkgs/libtheora/distros/repology.txt deleted file mode 100644 index 944587f5d50..00000000000 --- a/build/pkgs/libtheora/distros/repology.txt +++ /dev/null @@ -1 +0,0 @@ -libtheora diff --git a/build/pkgs/libtheora/distros/void.txt b/build/pkgs/libtheora/distros/void.txt deleted file mode 100644 index cc4b4b3d8be..00000000000 --- a/build/pkgs/libtheora/distros/void.txt +++ /dev/null @@ -1 +0,0 @@ -libtheora-devel diff --git a/build/pkgs/libtheora/package-version.txt b/build/pkgs/libtheora/package-version.txt deleted file mode 100644 index 524cb55242b..00000000000 --- a/build/pkgs/libtheora/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -1.1.1 diff --git a/build/pkgs/libtheora/spkg-install.in b/build/pkgs/libtheora/spkg-install.in deleted file mode 100644 index b1f58b44681..00000000000 --- a/build/pkgs/libtheora/spkg-install.in +++ /dev/null @@ -1,24 +0,0 @@ -cd src - -./configure \ - --prefix="$SAGE_LOCAL" \ - --libdir="$SAGE_LOCAL/lib" \ - --with-ogg="$SAGE_LOCAL" -if [ $? -ne 0 ]; then - echo "Error configuring libtheora" - exit 1 -fi - -$MAKE -if [ $? -ne 0 ]; then - echo "Error building libtheora" - exit 1 -fi - -$MAKE -j1 install -if [ $? -ne 0 ]; then - echo "Error installing libtheora" - exit 1 -fi - -cp examples/.libs/png2theora $SAGE_LOCAL/bin diff --git a/build/pkgs/libtheora/type b/build/pkgs/libtheora/type deleted file mode 100644 index 9839eb20815..00000000000 --- a/build/pkgs/libtheora/type +++ /dev/null @@ -1 +0,0 @@ -experimental diff --git a/build/pkgs/ore_algebra/requirements.txt b/build/pkgs/ore_algebra/requirements.txt index 3b6d6cc56ff..2df654052a2 100644 --- a/build/pkgs/ore_algebra/requirements.txt +++ b/build/pkgs/ore_algebra/requirements.txt @@ -1 +1 @@ -git+https://github.com/mkauers/ore_algebra@01c357f590685ff362c008229681ee08269457da#egg=ore_algebra +ore_algebra @ git+https://github.com/mkauers/ore_algebra diff --git a/build/pkgs/planarity/spkg-configure.m4 b/build/pkgs/planarity/spkg-configure.m4 index 9ec8ddc64f6..355332a72e7 100644 --- a/build/pkgs/planarity/spkg-configure.m4 +++ b/build/pkgs/planarity/spkg-configure.m4 @@ -1,6 +1,6 @@ SAGE_SPKG_CONFIGURE([planarity], [ AC_LANG_PUSH([C]) - AC_CHECK_HEADER([planarity/planarity.h], [ + AC_CHECK_HEADER([planarity/graph.h], [ AC_CHECK_LIB([planarity], [gp_InitGraph], [ AC_MSG_CHECKING([for planarity version 3.0 or later]) AC_COMPILE_IFELSE( diff --git a/build/pkgs/primecount/spkg-install.in b/build/pkgs/primecount/spkg-install.in index 7589fad8cb9..19b88753127 100644 --- a/build/pkgs/primecount/spkg-install.in +++ b/build/pkgs/primecount/spkg-install.in @@ -36,6 +36,7 @@ sdh_cmake -DCMAKE_VERBOSE_MAKEFILE=ON \ -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \ -DCMAKE_INSTALL_PREFIX=$SAGE_LOCAL \ -DWITH_POPCNT=OFF \ + . \ && sdh_make_install } diff --git a/build/pkgs/primesieve/spkg-install.in b/build/pkgs/primesieve/spkg-install.in index c7669a664e9..52968c86587 100644 --- a/build/pkgs/primesieve/spkg-install.in +++ b/build/pkgs/primesieve/spkg-install.in @@ -9,6 +9,7 @@ sdh_cmake -DCMAKE_VERBOSE_MAKEFILE=ON \ -DBUILD_STATIC_LIBS=OFF \ -DBUILD_SHARED_LIBS=ON \ -DBUILD_TESTS=ON \ - ${EXTRA_OPTS} + ${EXTRA_OPTS} \ + . sdh_make_install diff --git a/build/pkgs/pyproject_api/distros/arch.txt b/build/pkgs/pyproject_api/distros/arch.txt new file mode 100644 index 00000000000..7d778992044 --- /dev/null +++ b/build/pkgs/pyproject_api/distros/arch.txt @@ -0,0 +1 @@ +python-pyproject-api diff --git a/build/pkgs/pyproject_api/distros/debian.txt b/build/pkgs/pyproject_api/distros/debian.txt new file mode 100644 index 00000000000..0d2d5b563c5 --- /dev/null +++ b/build/pkgs/pyproject_api/distros/debian.txt @@ -0,0 +1 @@ +python3-pyproject-api diff --git a/build/pkgs/pyproject_api/distros/fedora.txt b/build/pkgs/pyproject_api/distros/fedora.txt new file mode 100644 index 00000000000..0d2d5b563c5 --- /dev/null +++ b/build/pkgs/pyproject_api/distros/fedora.txt @@ -0,0 +1 @@ +python3-pyproject-api diff --git a/build/pkgs/pyproject_api/distros/gentoo.txt b/build/pkgs/pyproject_api/distros/gentoo.txt new file mode 100644 index 00000000000..69d2b03e990 --- /dev/null +++ b/build/pkgs/pyproject_api/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pyproject-api diff --git a/build/pkgs/pyproject_api/distros/void.txt b/build/pkgs/pyproject_api/distros/void.txt new file mode 100644 index 00000000000..0d2d5b563c5 --- /dev/null +++ b/build/pkgs/pyproject_api/distros/void.txt @@ -0,0 +1 @@ +python3-pyproject-api diff --git a/build/pkgs/pyproject_hooks/distros/arch.txt b/build/pkgs/pyproject_hooks/distros/arch.txt new file mode 100644 index 00000000000..71c493f0851 --- /dev/null +++ b/build/pkgs/pyproject_hooks/distros/arch.txt @@ -0,0 +1 @@ +python-pyproject-hooks diff --git a/build/pkgs/pyproject_hooks/distros/debian.txt b/build/pkgs/pyproject_hooks/distros/debian.txt new file mode 100644 index 00000000000..010de587955 --- /dev/null +++ b/build/pkgs/pyproject_hooks/distros/debian.txt @@ -0,0 +1 @@ +python3-pyproject-hooks diff --git a/build/pkgs/pyproject_hooks/distros/fedora.txt b/build/pkgs/pyproject_hooks/distros/fedora.txt new file mode 100644 index 00000000000..010de587955 --- /dev/null +++ b/build/pkgs/pyproject_hooks/distros/fedora.txt @@ -0,0 +1 @@ +python3-pyproject-hooks diff --git a/build/pkgs/pyproject_hooks/distros/gentoo.txt b/build/pkgs/pyproject_hooks/distros/gentoo.txt new file mode 100644 index 00000000000..4034186504e --- /dev/null +++ b/build/pkgs/pyproject_hooks/distros/gentoo.txt @@ -0,0 +1 @@ +dev-python/pyproject-hooks diff --git a/build/pkgs/pyproject_hooks/distros/void.txt b/build/pkgs/pyproject_hooks/distros/void.txt new file mode 100644 index 00000000000..010de587955 --- /dev/null +++ b/build/pkgs/pyproject_hooks/distros/void.txt @@ -0,0 +1 @@ +python3-pyproject-hooks diff --git a/build/pkgs/pyproject_hooks/spkg-configure.m4 b/build/pkgs/pyproject_hooks/spkg-configure.m4 new file mode 100644 index 00000000000..acec0fc4902 --- /dev/null +++ b/build/pkgs/pyproject_hooks/spkg-configure.m4 @@ -0,0 +1 @@ +SAGE_SPKG_CONFIGURE([pyproject_hooks], [SAGE_PYTHON_PACKAGE_CHECK([pyproject_hooks])]) diff --git a/build/pkgs/pyproject_metadata/distros/arch.txt b/build/pkgs/pyproject_metadata/distros/arch.txt new file mode 100644 index 00000000000..31f99621fe0 --- /dev/null +++ b/build/pkgs/pyproject_metadata/distros/arch.txt @@ -0,0 +1 @@ +python-pyproject-metadata diff --git a/build/pkgs/pyproject_metadata/distros/debian.txt b/build/pkgs/pyproject_metadata/distros/debian.txt new file mode 100644 index 00000000000..5180a07a0cc --- /dev/null +++ b/build/pkgs/pyproject_metadata/distros/debian.txt @@ -0,0 +1 @@ +python3-pyproject-metadata diff --git a/build/pkgs/pyproject_metadata/distros/void.txt b/build/pkgs/pyproject_metadata/distros/void.txt new file mode 100644 index 00000000000..5180a07a0cc --- /dev/null +++ b/build/pkgs/pyproject_metadata/distros/void.txt @@ -0,0 +1 @@ +python3-pyproject-metadata diff --git a/build/pkgs/qhull/spkg-install.in b/build/pkgs/qhull/spkg-install.in index c3df534ad86..e649712ac43 100644 --- a/build/pkgs/qhull/spkg-install.in +++ b/build/pkgs/qhull/spkg-install.in @@ -1,7 +1,8 @@ cd src/ sdh_cmake -DCMAKE_VERBOSE_MAKEFILE=ON \ - -DLIB_INSTALL_DIR="${SAGE_LOCAL}"/lib + -DLIB_INSTALL_DIR="${SAGE_LOCAL}"/lib \ + . sdh_make diff --git a/build/pkgs/sage_conf/version_requirements.txt b/build/pkgs/sage_conf/version_requirements.txt index 11ae1c5d2a5..0a47bcf1281 100644 --- a/build/pkgs/sage_conf/version_requirements.txt +++ b/build/pkgs/sage_conf/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-conf ~= 10.5rc2 +sage-conf ~= 10.6b4 diff --git a/build/pkgs/sage_docbuild/version_requirements.txt b/build/pkgs/sage_docbuild/version_requirements.txt index b2dd3fbec85..2986652773e 100644 --- a/build/pkgs/sage_docbuild/version_requirements.txt +++ b/build/pkgs/sage_docbuild/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-docbuild ~= 10.5rc2 +sage-docbuild ~= 10.6b4 diff --git a/build/pkgs/sage_setup/version_requirements.txt b/build/pkgs/sage_setup/version_requirements.txt index c9bffddf1dc..3d739f2c183 100644 --- a/build/pkgs/sage_setup/version_requirements.txt +++ b/build/pkgs/sage_setup/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-setup ~= 10.5rc2 +sage-setup ~= 10.6b4 diff --git a/build/pkgs/sage_sws2rst/version_requirements.txt b/build/pkgs/sage_sws2rst/version_requirements.txt index 44d72b63d93..a1c57461d38 100644 --- a/build/pkgs/sage_sws2rst/version_requirements.txt +++ b/build/pkgs/sage_sws2rst/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sage-sws2rst ~= 10.5rc2 +sage-sws2rst ~= 10.6b4 diff --git a/build/pkgs/sagelib/version_requirements.txt b/build/pkgs/sagelib/version_requirements.txt index 49cf1f431c8..09e6e070dbf 100644 --- a/build/pkgs/sagelib/version_requirements.txt +++ b/build/pkgs/sagelib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-standard ~= 10.5rc2 +sagemath-standard ~= 10.6b4 diff --git a/build/pkgs/sagemath_bliss/version_requirements.txt b/build/pkgs/sagemath_bliss/version_requirements.txt index 97488091046..370e9dc8d11 100644 --- a/build/pkgs/sagemath_bliss/version_requirements.txt +++ b/build/pkgs/sagemath_bliss/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-bliss ~= 10.5rc2 +sagemath-bliss ~= 10.6b4 diff --git a/build/pkgs/sagemath_categories/version_requirements.txt b/build/pkgs/sagemath_categories/version_requirements.txt index 38d0f576482..6e0f464e560 100644 --- a/build/pkgs/sagemath_categories/version_requirements.txt +++ b/build/pkgs/sagemath_categories/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-categories ~= 10.5rc2 +sagemath-categories ~= 10.6b4 diff --git a/build/pkgs/sagemath_coxeter3/version_requirements.txt b/build/pkgs/sagemath_coxeter3/version_requirements.txt index 74fcc5180f1..825ad688d44 100644 --- a/build/pkgs/sagemath_coxeter3/version_requirements.txt +++ b/build/pkgs/sagemath_coxeter3/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-coxeter3 ~= 10.5rc2 +sagemath-coxeter3 ~= 10.6b4 diff --git a/build/pkgs/sagemath_doc_html/dependencies b/build/pkgs/sagemath_doc_html/dependencies index 40717629a77..ef59cbb539b 100644 --- a/build/pkgs/sagemath_doc_html/dependencies +++ b/build/pkgs/sagemath_doc_html/dependencies @@ -1,4 +1,4 @@ -sagelib sphinx sphinx_copybutton sphinx_inline_tabs pplpy_doc | $(SAGERUNTIME) maxima networkx scipy sympy matplotlib pillow mathjax mpmath ipykernel jupyter_client conway_polynomials tachyon ipywidgets sage_docbuild elliptic_curves furo fpylll graphs +sagelib sphinx sphinx_copybutton sphinx_inline_tabs pplpy_doc | $(SAGERUNTIME) maxima networkx scipy sympy matplotlib pillow mathjax mpmath ipykernel jupyter_client conway_polynomials tachyon ipywidgets sage_docbuild elliptic_curves furo fpylll graphs typing_extensions # Building the documentation has many dependencies, because all # documented modules are imported and because we use matplotlib to diff --git a/build/pkgs/sagemath_environment/version_requirements.txt b/build/pkgs/sagemath_environment/version_requirements.txt index 17b0f996c23..27e9c97c883 100644 --- a/build/pkgs/sagemath_environment/version_requirements.txt +++ b/build/pkgs/sagemath_environment/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-environment ~= 10.5rc2 +sagemath-environment ~= 10.6b4 diff --git a/build/pkgs/sagemath_mcqd/version_requirements.txt b/build/pkgs/sagemath_mcqd/version_requirements.txt index e25bbd7cbf5..32529957f70 100644 --- a/build/pkgs/sagemath_mcqd/version_requirements.txt +++ b/build/pkgs/sagemath_mcqd/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-mcqd ~= 10.5rc2 +sagemath-mcqd ~= 10.6b4 diff --git a/build/pkgs/sagemath_meataxe/version_requirements.txt b/build/pkgs/sagemath_meataxe/version_requirements.txt index 839d6691290..f579dd099c5 100644 --- a/build/pkgs/sagemath_meataxe/version_requirements.txt +++ b/build/pkgs/sagemath_meataxe/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-meataxe ~= 10.5rc2 +sagemath-meataxe ~= 10.6b4 diff --git a/build/pkgs/sagemath_objects/version_requirements.txt b/build/pkgs/sagemath_objects/version_requirements.txt index 2087671be40..92754c524f1 100644 --- a/build/pkgs/sagemath_objects/version_requirements.txt +++ b/build/pkgs/sagemath_objects/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-objects ~= 10.5rc2 +sagemath-objects ~= 10.6b4 diff --git a/build/pkgs/sagemath_repl/version_requirements.txt b/build/pkgs/sagemath_repl/version_requirements.txt index cf19972eb63..ca8348f0f76 100644 --- a/build/pkgs/sagemath_repl/version_requirements.txt +++ b/build/pkgs/sagemath_repl/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-repl ~= 10.5rc2 +sagemath-repl ~= 10.6b4 diff --git a/build/pkgs/sagemath_sirocco/version_requirements.txt b/build/pkgs/sagemath_sirocco/version_requirements.txt index eb2af632ca7..881707ea9d5 100644 --- a/build/pkgs/sagemath_sirocco/version_requirements.txt +++ b/build/pkgs/sagemath_sirocco/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-sirocco ~= 10.5rc2 +sagemath-sirocco ~= 10.6b4 diff --git a/build/pkgs/sagemath_tdlib/version_requirements.txt b/build/pkgs/sagemath_tdlib/version_requirements.txt index ebd9f2961a9..8110525f3b7 100644 --- a/build/pkgs/sagemath_tdlib/version_requirements.txt +++ b/build/pkgs/sagemath_tdlib/version_requirements.txt @@ -1,2 +1,2 @@ # This file is updated on every release by the sage-update-version script -sagemath-tdlib ~= 10.5rc2 +sagemath-tdlib ~= 10.6b4 diff --git a/build/pkgs/scip/spkg-install.in b/build/pkgs/scip/spkg-install.in index 69bbdfae266..2ec391fc2bc 100644 --- a/build/pkgs/scip/spkg-install.in +++ b/build/pkgs/scip/spkg-install.in @@ -2,16 +2,16 @@ cd src mkdir build cd build sdh_cmake -DCMAKE_INSTALL_LIBDIR=lib \ - -DCMAKE_VERBOSE_MAKEFILE=ON \ - -DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=ON \ - -DGMP_DIR="${SAGE_GMP_PREFIX}" \ - -DReadline_ROOT_DIR=$(pkg-config --variable=prefix readline) \ - -DHistory_ROOT_DIR=$(pkg-config --variable=prefix readline) \ - -DIPOPT=off \ - -DPAPILO=on -DPAPILO_DIR="${SAGE_LOCAL}" \ - -DZIMPL=off \ - -DAMPL=off \ - -DSYM=bliss \ - .. + -DCMAKE_VERBOSE_MAKEFILE=ON \ + -DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=ON \ + -DGMP_DIR="${SAGE_GMP_PREFIX}" \ + -DReadline_ROOT_DIR=$(pkg-config --variable=prefix readline) \ + -DHistory_ROOT_DIR=$(pkg-config --variable=prefix readline) \ + -DIPOPT=off \ + -DPAPILO=on -DPAPILO_DIR="${SAGE_LOCAL}" \ + -DZIMPL=off \ + -DAMPL=off \ + -DSYM=bliss \ + .. sdh_make sdh_make_install diff --git a/build/pkgs/scip_sdp/spkg-install.in b/build/pkgs/scip_sdp/spkg-install.in index 3a65a004219..bc202b1262b 100644 --- a/build/pkgs/scip_sdp/spkg-install.in +++ b/build/pkgs/scip_sdp/spkg-install.in @@ -2,14 +2,14 @@ cd src mkdir build cd build sdh_cmake -DCMAKE_INSTALL_LIBDIR=lib \ - -DCMAKE_VERBOSE_MAKEFILE=ON \ - -DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=ON \ - -DBLA_VENDOR=OpenBLAS \ - -DBLAS_LIBRARIES="$(pkg-config --libs blas)" \ - -DLAPACK_LIBRARIES="$(pkg-config --libs lapack)" \ - -DSCIP_DIR="${SAGE_LOCAL}" \ - -DSYM=bliss \ - -DSDPS=dsdp \ - .. + -DCMAKE_VERBOSE_MAKEFILE=ON \ + -DCMAKE_BUILD_WITH_INSTALL_NAME_DIR=ON \ + -DBLA_VENDOR=OpenBLAS \ + -DBLAS_LIBRARIES="$(pkg-config --libs blas)" \ + -DLAPACK_LIBRARIES="$(pkg-config --libs lapack)" \ + -DSCIP_DIR="${SAGE_LOCAL}" \ + -DSYM=bliss \ + -DSDPS=dsdp \ + .. sdh_make sdh_make_install diff --git a/build/pkgs/suitesparse/spkg-install.in b/build/pkgs/suitesparse/spkg-install.in index f7ef16bb48b..cfc8b176d71 100644 --- a/build/pkgs/suitesparse/spkg-install.in +++ b/build/pkgs/suitesparse/spkg-install.in @@ -5,7 +5,7 @@ echo "Configuring suitesparse" # Hopefully these sill be normalised in the future. # * SUITESPARSE_INCLUDEDIR_POSTFIX sets the subfolder in which to install headers. # It default to "suitesparse" if not defined, which currently breaks dependencies. -# * SUITESPARSE_USE_FORTRAN make sure the fortran interface is off. There is trouble when +# * SUITESPARSE_USE_FORTRAN make sure the fortran interface is off. There is trouble when # gcc and gfortran version are not matching. # * SUITESPARSE_ENABLE_PROJECTS semi column separated list of the desired packages. Default is # all the packages in the suitesparse tarball. @@ -16,6 +16,7 @@ sdh_cmake -DCMAKE_VERBOSE_MAKEFILE=ON \ -DNSTATIC=ON \ -DSUITESPARSE_USE_FORTRAN=OFF \ -DSUITESPARSE_INCLUDEDIR_POSTFIX="" \ - -DSUITESPARSE_ENABLE_PROJECTS="suitesparse_config;amd;camd;ccolamd;colamd;cholmod;umfpack" + -DSUITESPARSE_ENABLE_PROJECTS="suitesparse_config;amd;camd;ccolamd;colamd;cholmod;umfpack" \ + . sdh_make_install diff --git a/build/pkgs/symengine/spkg-install.in b/build/pkgs/symengine/spkg-install.in index 8eaaf6fbcbe..3e9c4b05fcf 100644 --- a/build/pkgs/symengine/spkg-install.in +++ b/build/pkgs/symengine/spkg-install.in @@ -2,18 +2,18 @@ cd src mkdir build cd build sdh_cmake -DCMAKE_PREFIX_PATH="$SAGE_LOCAL" \ - -DWITH_SYMENGINE_THREAD_SAFE=yes \ - -DWITH_ECM=yes \ - -DWITH_FLINT=yes \ - -DWITH_ARB=yes \ - -DWITH_MPFR=yes \ - -DWITH_MPC=yes \ - -DWITH_LLVM=no \ - -DINTEGER_CLASS="flint" \ - -DBUILD_BENCHMARKS=no \ - -DBUILD_SHARED_LIBS=yes \ - -DBUILD_TESTS=yes \ - .. + -DWITH_SYMENGINE_THREAD_SAFE=yes \ + -DWITH_ECM=yes \ + -DWITH_FLINT=yes \ + -DWITH_ARB=yes \ + -DWITH_MPFR=yes \ + -DWITH_MPC=yes \ + -DWITH_LLVM=no \ + -DINTEGER_CLASS="flint" \ + -DBUILD_BENCHMARKS=no \ + -DBUILD_SHARED_LIBS=yes \ + -DBUILD_TESTS=yes \ + .. sdh_make sdh_make install diff --git a/configure.ac b/configure.ac index 1bf79ed7333..29812af6e97 100644 --- a/configure.ac +++ b/configure.ac @@ -222,7 +222,7 @@ dnl Exit autoconf with exit code 16 in this case. This will be dnl caught by the bootstrap script. m4_exit(16)]) -PKG_PROG_PKG_CONFIG([0.29], [PKG_CONFIG=false]) +PKG_PROG_PKG_CONFIG([0.29], [PKG_CONFIG=]) AC_CHECK_PROG(found_ranlib, ranlib, yes, no) if test x$found_ranlib != xyes @@ -431,7 +431,7 @@ AS_IF([test "x$enable_download_from_upstream_url" = "xyes"], [ ]) AC_SUBST([SAGE_SPKG_OPTIONS]) -AC_ARG_ENABLE([sagelib], +AC_ARG_ENABLE([sage_conf], AS_HELP_STRING([--disable-sage_conf], [disable build of the sage_conf package]), [ for pkg in sage_conf; do diff --git a/conftest.py b/conftest.py new file mode 100644 index 00000000000..5307d7f6233 --- /dev/null +++ b/conftest.py @@ -0,0 +1,347 @@ +# pyright: strict +"""Configuration and fixtures for pytest. + +This file configures pytest and provides some global fixtures. +See https://docs.pytest.org/en/latest/index.html for more details. +""" + +from __future__ import annotations + +import doctest +import inspect +import sys +import warnings +from pathlib import Path +from typing import Any, Iterable, Optional + +import pytest +from _pytest.doctest import ( + DoctestItem, + DoctestModule, + _get_continue_on_failure, + _get_runner, + _is_mocked, + _patch_unwrap_mock_aware, + get_optionflags, +) +from _pytest.pathlib import ImportMode, import_path + +from sage.doctest.forker import ( + init_sage, + showwarning_with_traceback, +) +from sage.doctest.parsing import SageDocTestParser, SageOutputChecker + + +class SageDoctestModule(DoctestModule): + """ + This is essentially a copy of `DoctestModule` from + https://github.com/pytest-dev/pytest/blob/main/src/_pytest/doctest.py. + The only change is that we use `SageDocTestParser` to extract the doctests + and `SageOutputChecker` to verify the output. + """ + + def collect(self) -> Iterable[DoctestItem]: + import doctest + + class MockAwareDocTestFinder(doctest.DocTestFinder): + """A hackish doctest finder that overrides stdlib internals to fix a stdlib bug. + https://github.com/pytest-dev/pytest/issues/3456 + https://bugs.python.org/issue25532 + """ + + def __init__(self) -> None: + super().__init__(parser=SageDocTestParser(set(["sage"]))) + + def _find_lineno(self, obj, source_lines): + """Doctest code does not take into account `@property`, this + is a hackish way to fix it. https://bugs.python.org/issue17446 + Wrapped Doctests will need to be unwrapped so the correct + line number is returned. This will be reported upstream. #8796 + """ + if isinstance(obj, property): + obj = getattr(obj, "fget", obj) + + if hasattr(obj, "__wrapped__"): + # Get the main obj in case of it being wrapped + obj = inspect.unwrap(obj) + + # Type ignored because this is a private function. + return super()._find_lineno( # type:ignore[misc] + obj, + source_lines, + ) + + def _find( + self, tests, obj, name, module, source_lines, globs, seen + ) -> None: + if _is_mocked(obj): + return + with _patch_unwrap_mock_aware(): + # Type ignored because this is a private function. + super()._find( # type:ignore[misc] + tests, obj, name, module, source_lines, globs, seen + ) + + if self.path.name == "conftest.py": + module = self.config.pluginmanager._importconftest( + self.path, + self.config.getoption("importmode"), + rootpath=self.config.rootpath, + consider_namespace_packages=True, + ) + else: + try: + module = import_path( + self.path, + mode=ImportMode.importlib, + root=self.config.rootpath, + consider_namespace_packages=True, + ) + except ImportError as exception: + if self.config.getvalue("doctest_ignore_import_errors"): + pytest.skip("unable to import module %r" % self.path) + else: + if isinstance(exception, ModuleNotFoundError): + # Ignore some missing features/modules for now + # TODO: Remove this once all optional things are using Features + if exception.name in ( + "valgrind", + "rpy2", + "sage.libs.coxeter3.coxeter", + ): + pytest.skip( + f"unable to import module { self.path } due to missing feature { exception.name }" + ) + raise + # Uses internal doctest module parsing mechanism. + finder = MockAwareDocTestFinder() + optionflags = get_optionflags(self.config) + from sage.features import FeatureNotPresentError + + runner = _get_runner( + verbose=False, + optionflags=optionflags, + checker=SageOutputChecker(), + continue_on_failure=_get_continue_on_failure(self.config), + ) + try: + for test in finder.find(module, module.__name__): + if test.examples: # skip empty doctests + yield DoctestItem.from_parent( + self, name=test.name, runner=runner, dtest=test + ) + except FeatureNotPresentError as exception: + pytest.skip( + f"unable to import module { self.path } due to missing feature { exception.feature.name }" + ) + except ModuleNotFoundError as exception: + # TODO: Remove this once all optional things are using Features + pytest.skip( + f"unable to import module { self.path } due to missing module { exception.name }" + ) + + +class IgnoreCollector(pytest.Collector): + """ + Ignore a file. + """ + + def __init__(self, parent: pytest.Collector) -> None: + super().__init__("ignore", parent) + + def collect(self) -> Iterable[pytest.Item | pytest.Collector]: + return [] + + +def pytest_collect_file( + file_path: Path, parent: pytest.Collector +) -> pytest.Collector | None: + """ + This hook is called when collecting test files, and can be used to + modify the file or test selection logic by returning a list of + ``pytest.Item`` objects which the ``pytest`` command will directly + add to the list of test items. + + See `pytest documentation `_. + """ + if ( + file_path.parent.name == "combinat" + or file_path.parent.parent.name == "combinat" + ): + # Crashes CI for some reason + return IgnoreCollector.from_parent(parent) + if file_path.suffix == ".pyx": + # We don't allow pytests to be defined in Cython files. + # Normally, Cython files are filtered out already by pytest and we only + # hit this here if someone explicitly runs `pytest some_file.pyx`. + return IgnoreCollector.from_parent(parent) + elif file_path.suffix == ".py": + if parent.config.option.doctest: + if file_path.name == "__main__.py" or file_path.name == "setup.py": + # We don't allow tests to be defined in __main__.py/setup.py files (because their import will fail). + return IgnoreCollector.from_parent(parent) + if ( + ( + file_path.name == "postprocess.py" + and file_path.parent.name == "nbconvert" + ) + or ( + file_path.name == "giacpy-mkkeywords.py" + and file_path.parent.name == "autogen" + ) + or ( + file_path.name == "flint_autogen.py" + and file_path.parent.name == "autogen" + ) + ): + # This is an executable file. + return IgnoreCollector.from_parent(parent) + + if file_path.name == "conftest_inputtest.py": + # This is an input file for testing the doctest machinery (and contains broken doctests). + return IgnoreCollector.from_parent(parent) + + if ( + ( + file_path.name == "finite_dimensional_lie_algebras_with_basis.py" + and file_path.parent.name == "categories" + ) + or ( + file_path.name == "__init__.py" + and file_path.parent.name == "crypto" + ) + or (file_path.name == "__init__.py" and file_path.parent.name == "mq") + ): + # TODO: Fix these (import fails with "RuntimeError: dictionary changed size during iteration") + return IgnoreCollector.from_parent(parent) + + if ( + file_path.name in ("forker.py", "reporting.py") + ) and file_path.parent.name == "doctest": + # Fails with many errors due to different testing framework + return IgnoreCollector.from_parent(parent) + + if ( + ( + file_path.name == "arithgroup_generic.py" + and file_path.parent.name == "arithgroup" + ) + or ( + file_path.name == "pari.py" + and file_path.parent.name == "lfunctions" + ) + or ( + file_path.name == "permgroup_named.py" + and file_path.parent.name == "perm_gps" + ) + or ( + file_path.name == "finitely_generated.py" + and file_path.parent.name == "matrix_gps" + ) + or ( + file_path.name == "libgap_mixin.py" + and file_path.parent.name == "groups" + ) + or ( + file_path.name == "finitely_presented.py" + and file_path.parent.name == "groups" + ) + or ( + file_path.name == "classical_geometries.py" + and file_path.parent.name == "generators" + ) + ): + # Fails with "Fatal Python error" + return IgnoreCollector.from_parent(parent) + + return SageDoctestModule.from_parent(parent, path=file_path) + + +def pytest_addoption(parser): + # Add a command line option to run doctests + # (we don't use the built-in --doctest-modules option because then doctests are collected twice) + group = parser.getgroup("collect") + group.addoption( + "--doctest", + action="store_true", + default=False, + help="Run doctests in all .py modules", + dest="doctest", + ) + + +# Monkey patch exception printing to replace the full qualified name of the exception by its short name +# TODO: Remove this hack once migration to pytest is complete +import traceback + +old_format_exception_only = traceback.format_exception_only + + +def format_exception_only(etype: type, value: BaseException) -> list[str]: + formatted_exception = old_format_exception_only(etype, value) + exception_name = etype.__name__ + if etype.__module__: + exception_full_name = etype.__module__ + "." + etype.__qualname__ + else: + exception_full_name = etype.__qualname__ + + for i, line in enumerate(formatted_exception): + if line.startswith(exception_full_name): + formatted_exception[i] = line.replace( + exception_full_name, exception_name, 1 + ) + return formatted_exception + + +# Initialize Sage-specific doctest stuff +init_sage() + +# Monkey patch doctest to use our custom printer etc +old_run = doctest.DocTestRunner.run + + +def doctest_run( + self: doctest.DocTestRunner, + test: doctest.DocTest, + compileflags: Optional[int] = None, + out: Any = None, + clear_globs: bool = True, +) -> doctest.TestResults: + from sage.repl.rich_output import get_display_manager + from sage.repl.user_globals import set_globals + + traceback.format_exception_only = format_exception_only + + # Display warnings in doctests + warnings.showwarning = showwarning_with_traceback + setattr(sys, "__displayhook__", get_display_manager().displayhook) + + # Ensure that injecting globals works as expected in doctests + set_globals(test.globs) + return old_run(self, test, compileflags, out, clear_globs) + + +doctest.DocTestRunner.run = doctest_run + + +@pytest.fixture(autouse=True, scope="session") +def add_imports(doctest_namespace: dict[str, Any]): + """ + Add global imports for doctests. + + See `pytest documentation `. + """ + # Inject sage.all into each doctest + import sage.repl.ipython_kernel.all_jupyter + + dict_all = sage.repl.ipython_kernel.all_jupyter.__dict__ + + # Remove '__package__' item from the globals since it is not + # always in the globals in an actual Sage session. + dict_all.pop("__package__", None) + + sage_namespace = dict(dict_all) + sage_namespace["__name__"] = "__main__" + + doctest_namespace.update(**sage_namespace) diff --git a/docker/.gitpod.Dockerfile b/docker/.gitpod.Dockerfile index 3ff75298c77..2e4da8ed858 100644 --- a/docker/.gitpod.Dockerfile +++ b/docker/.gitpod.Dockerfile @@ -6,7 +6,7 @@ RUN apt update && apt-get install -yq --no-install-recommends sudo gpg curl lsb- # Make Docker available, like the default gitpod image does # from https://github.com/gitpod-io/workspace-images/blob/main/chunks/tool-docker/Dockerfile @ 3f0988f2d06768d22d0aa1454ef0e963b0db65f3 -# - removed unneccessary "sudo" +# - removed unnecessary "sudo" # - replaced use of "install-packages" (https://github.com/gitpod-io/workspace-images/blob/main/base/install-packages) # https://docs.docker.com/engine/install/ubuntu/ RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \ diff --git a/environment-3.10-linux-aarch64.yml b/environment-3.10-linux-aarch64.yml deleted file mode 100644 index 1ec845735bf..00000000000 --- a/environment-3.10-linux-aarch64.yml +++ /dev/null @@ -1,436 +0,0 @@ -name: sage -# Generated by conda-lock. -# platform: linux-aarch64 -# input_hash: 50ecbf09a118347f6c002960a184cf81c369d83e8e8555c2db3282013254eca1 - -channels: - - conda-forge -dependencies: - - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - _sysroot_linux-aarch64_curr_repodata_hack=4=h57d6b7b_14 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.11=h31becfc_1 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py310hb299538_4 - - arpack=3.9.1=nompi_hd363cd0_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321h2148fe1_1 - - automake=1.16.5=pl5321h8af1aa0_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=hf897c2e_0 - - bdw-gc=8.0.6=hd62202e_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=hf1166c9_7 - - binutils_impl_linux-aarch64=2.40=hf54a868_7 - - binutils_linux-aarch64=2.40=h1f91aba_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linuxaarch64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=ha990451_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h31becfc_1 - - brotli-bin=1.1.0=h31becfc_1 - - brotli-python=1.1.0=py310hbb3657e_1 - - bwidget=1.9.14=h8af1aa0_1 - - bzip2=1.0.8=h31becfc_5 - - c-ares=1.28.1=h31becfc_0 - - c-compiler=1.7.0=h31becfc_1 - - ca-certificates=2024.6.2=hcefe29a_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=h5c54ea9_2 - - cddlib=1!0.94m=h719063d_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py310hce94938_0 - - chardet=5.2.0=py310hbbe02a8_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - cliquer=1.22=h31becfc_1 - - cmake=3.29.6=h7042e5d_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py310h4c7bcd0_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=h8af1aa0_1 - - contourpy=1.2.1=py310h586407a_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=h7daf2e0_0 - - cvxopt=1.3.2=py310he29a27f_2 - - cxx-compiler=1.7.0=h2a328a1_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py310h4cbba44_0 - - cysignals=1.11.2=py310h485802a_3 - - cython=3.0.10=py310hbb3657e_0 - - debugpy=1.8.1=py310hbb3657e_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hb12102e_1203 - - ecl=23.9.9=h6475f26_0 - - eclib=20231212=he26bab5_0 - - ecm=7.0.5=ha2d0fc4_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h2f0025b_0 - - fflas-ffpack=2.5.0=h503e619_0 - - fftw=3.3.10=nompi_h020dacd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=ha9a116f_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py310hb52b2da_0 - - fortran-compiler=1.7.0=h7048d53_1 - - fplll=5.4.5=hb3a790e_0 - - fpylll=0.6.1=py310hfdbf2a6_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=hf0a5ef3_2 - - fribidi=1.0.10=hb9de7d4_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=h597289e_3 - - gap-defaults=4.12.2=h8af1aa0_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=hdb0cc85_13 - - gcc_impl_linux-aarch64=12.3.0=h3d98823_13 - - gcc_linux-aarch64=12.3.0=ha52a6ea_9 - - gengetopt=2.23=h01db608_0 - - gf2x=1.3.0=h1b3b3a3_2 - - gfan=0.6.2=h5f589ec_1003 - - gfortran=12.3.0=hdb0cc85_13 - - gfortran_impl_linux-aarch64=12.3.0=h97ebfd2_13 - - gfortran_linux-aarch64=12.3.0=ha7b8e4b_9 - - giac=1.9.0.21=h04922a4_1 - - giflib=5.2.2=h31becfc_0 - - givaro=4.2.0=h364d21b_0 - - glpk=5.0=h66325d0_0 - - gmp=6.3.0=h0a1ffab_2 - - gmpy2=2.1.5=py310h05bcf56_1 - - graphite2=1.3.13=h2f0025b_1003 - - gsl=2.7=h294027d_0 - - gxx=12.3.0=hdb0cc85_13 - - gxx_impl_linux-aarch64=12.3.0=hba91e99_13 - - gxx_linux-aarch64=12.3.0=h9d1f256_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h9812418_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h787c7f5_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h197073e_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h15043fe_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=h8af1aa0_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py310h4c7bcd0_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py310h4c7bcd0_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-aarch64=4.18.0=h5b4a56d_14 - - keyutils=1.6.1=h4e544f5_0 - - kiwisolver=1.4.5=py310he290b8a_1 - - krb5=1.21.2=hc419048_0 - - lcalc=2.0.5=he588f68_2 - - lcms2=2.16=h922389a_0 - - ld_impl_linux-aarch64=2.40=h9fc2d93_7 - - lerc=4.0.0=h4de3ea5_0 - - libatomic_ops=7.6.14=h4e544f5_0 - - libblas=3.9.0=20_linuxaarch64_openblas - - libboost=1.85.0=hb41fec8_2 - - libboost-devel=1.85.0=h37bb5a9_2 - - libboost-headers=1.85.0=h8af1aa0_2 - - libbraiding=1.2=hd600fc2_0 - - libbrial=1.2.12=h9429f74_3 - - libbrotlicommon=1.1.0=h31becfc_1 - - libbrotlidec=1.1.0=h31becfc_1 - - libbrotlienc=1.1.0=h31becfc_1 - - libcblas=3.9.0=20_linuxaarch64_openblas - - libcups=2.3.3=h405e4a8_4 - - libcurl=8.8.0=h4e8248e_0 - - libdeflate=1.20=h31becfc_0 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=h31becfc_2 - - libexpat=2.6.2=h2f0025b_0 - - libffi=3.4.2=h3557bc0_5 - - libflint=3.0.1=hc392af7_ntl_100 - - libgcc-devel_linux-aarch64=12.3.0=h6144e03_113 - - libgcc-ng=13.2.0=he277a41_13 - - libgd=2.3.3=hcd22fd5_9 - - libgfortran-ng=13.2.0=he9431aa_13 - - libgfortran5=13.2.0=h2af0866_13 - - libglib=2.80.2=haee52c6_1 - - libgomp=13.2.0=he277a41_13 - - libhomfly=1.02r6=h31becfc_1 - - libhwloc=2.10.0=default_h3030c0e_1001 - - libiconv=1.17=h31becfc_2 - - libjpeg-turbo=3.0.0=h31becfc_1 - - liblapack=3.9.0=20_linuxaarch64_openblas - - liblapacke=3.9.0=20_linuxaarch64_openblas - - libnghttp2=1.58.0=hb0e430d_1 - - libnsl=2.0.1=h31becfc_0 - - libopenblas=0.3.25=pthreads_h5a5ec62_0 - - libpng=1.6.43=h194ca79_0 - - libsanitizer=12.3.0=h57e2e72_13 - - libsodium=1.0.18=hb9de7d4_1 - - libsqlite=3.46.0=hf51ef55_0 - - libssh2=1.11.0=h492db2e_0 - - libstdcxx-devel_linux-aarch64=12.3.0=h6144e03_113 - - libstdcxx-ng=13.2.0=h3f4de04_13 - - libtiff=4.6.0=hf980d43_3 - - libtool=2.4.7=h4de3ea5_0 - - libuuid=2.38.1=hb4cce97_0 - - libuv=1.48.0=h31becfc_0 - - libwebp=1.4.0=h8b4e01b_0 - - libwebp-base=1.4.0=h31becfc_0 - - libxcb=1.16=h7935292_0 - - libxcrypt=4.4.36=h31becfc_1 - - libxml2=2.12.7=h49dc7a2_1 - - libzlib=1.3.1=h68df207_1 - - linbox=1.7.0=h681a5ee_0 - - llvm-openmp=18.1.8=hb063fc5_0 - - lrcalc=2.1=h2f0025b_6 - - m4=1.4.18=h516909a_1001 - - m4ri=20140914=hedfd65a_1006 - - m4rie=20150908=hf0a5ef3_1002 - - make=4.3=h309ac5b_1 - - markupsafe=2.1.5=py310h7c1f4a2_0 - - mathjax=3.2.2=h8af1aa0_0 - - matplotlib=3.8.4=py310hbbe02a8_2 - - matplotlib-base=3.8.4=py310h84f21c1_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h6475f26_2 - - memory-allocator=0.1.3=py310hb299538_0 - - metis=5.1.0=h2f0025b_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=hf4c8f4c_0 - - mpfi=1.5.4=h846f343_1001 - - mpfr=4.2.1=ha2d0fc4_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h31becfc_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h0425590_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h70be974_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=h0d7519b_1 - - numpy=1.26.4=py310hcbab775_0 - - openblas=0.3.25=pthreads_h339cbfa_0 - - openjdk=22.0.1=h3d4cd67_0 - - openjpeg=2.5.2=h0d9d63b_0 - - openssl=3.3.1=h68df207_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=hb9de7d4_0 - - pandoc=3.2.1=h8af1aa0_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h399c48b_0 - - pari=2.15.5=h169c2a7_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=hf897c2e_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h070dd5b_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h31becfc_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py310h611336f_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h2f0025b_0 - - pkg-config=0.29.2=hb9de7d4_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h31becfc_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h984aac9_1006 - - pplpy=0.8.9=py310h6665419_1 - - primecount=7.9=hd600fc2_0 - - primecountpy=0.1.0=py310h586407a_4 - - primesieve=11.1=h2f0025b_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py310hb52b2da_0 - - pthread-stubs=0.4=hb9de7d4_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py310h586407a_0 - - pybind11-global=2.12.0=py310h586407a_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py310h7c1f4a2_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.10.14=hbbe8eec_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py310hbb3657e_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.10=4_cp310 - - pythran=0.15.0=py310h5e48e15_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py310h4c7bcd0_4 - - pyyaml=6.0.1=py310hb299538_1 - - pyzmq=26.0.3=py310he875deb_0 - - qd=2.3.22=h05efe27_1004 - - qhull=2020.2=hd62202e_2 - - r-base=4.3.3=h7f20121_3 - - r-lattice=0.22_6=r43h25e906a_0 - - readline=8.2=h8fc344f_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h31becfc_0 - - rpds-py=0.18.1=py310h59d1b7a_0 - - rpy2=3.5.11=py310r43h8b6b5fc_3 - - rw=0.9=h31becfc_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.3=py310hcbab775_1 - - sed=4.8=ha0d5d3d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hbe76a8a_1 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=hdc7ab3c_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=h3944111_1 - - symmetrica=3.0.1=hd600fc2_0 - - sympow=2.023.6=h157afb5_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-aarch64=2.17=h5b4a56d_14 - - tachyon=0.99b6=ha0bfc61_1002 - - tar=1.34=h048efde_0 - - tbb=2021.12.0=h70be974_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h17f021e_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h194ca79_0 - - tktable=2.10=h52f7bd3_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py310h03727f4_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py310h4c7bcd0_0 - - unicodedata2=15.1.0=py310hb299538_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-fixesproto=5.0=h3557bc0_1002 - - xorg-inputproto=2.3.2=h3557bc0_1002 - - xorg-kbproto=1.0.7=h3557bc0_1002 - - xorg-libice=1.1.1=h7935292_0 - - xorg-libsm=1.2.4=h5a01bc2_0 - - xorg-libx11=1.8.9=h08be655_1 - - xorg-libxau=1.0.11=h31becfc_0 - - xorg-libxdmcp=1.1.3=h3557bc0_0 - - xorg-libxext=1.3.4=h2a766a3_2 - - xorg-libxfixes=5.0.3=h3557bc0_1004 - - xorg-libxi=1.7.10=h3557bc0_0 - - xorg-libxrender=0.9.11=h7935292_0 - - xorg-libxt=1.3.0=h7935292_1 - - xorg-libxtst=1.2.3=hf897c2e_1002 - - xorg-recordproto=1.14.2=hf897c2e_1002 - - xorg-renderproto=0.11.1=h3557bc0_1002 - - xorg-xextproto=7.3.0=h2a766a3_1003 - - xorg-xproto=7.0.31=h3557bc0_1007 - - xz=5.2.6=h9cdd2b7_0 - - yaml=0.2.5=hf897c2e_2 - - zeromq=4.3.5=h28faeed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h68df207_1 - - zstd=1.5.6=h02f22dd_0 diff --git a/environment-3.10-linux.yml b/environment-3.10-linux.yml deleted file mode 100644 index b764f92d2d7..00000000000 --- a/environment-3.10-linux.yml +++ /dev/null @@ -1,484 +0,0 @@ -name: sage -# Generated by conda-lock. -# platform: linux-64 -# input_hash: 5dc443f6ceb3674d099e0ec613ba37acf67d72b0b26699816fc7afb3c9523b1f - -channels: - - conda-forge -dependencies: - - _libgcc_mutex=0.1=conda_forge - - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.12=h4ab18f5_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py310h2372a71_4 - - arpack=3.9.1=nompi_h77f6705_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attr=2.5.1=h166bdaf_1 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321h2b4cb7a_1 - - automake=1.16.5=pl5321ha770c72_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=h7f98852_0 - - bdw-gc=8.0.6=h4bd325d_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=h4852527_7 - - binutils_impl_linux-64=2.40=ha1999f0_7 - - binutils_linux-64=2.40=hb3c18ed_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linux64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h44aadfe_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hd590300_1 - - brotli-bin=1.1.0=hd590300_1 - - brotli-python=1.1.0=py310hc6cd4ac_1 - - bwidget=1.9.14=ha770c72_1 - - bzip2=1.0.8=hd590300_5 - - c-ares=1.28.1=hd590300_0 - - c-compiler=1.7.0=hd590300_1 - - ca-certificates=2024.6.2=hbcca054_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=hbb29018_2 - - cddlib=1!0.94m=h9202a9a_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py310h2fee648_0 - - chardet=5.2.0=py310hff52083_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - cliquer=1.22=hd590300_1 - - cmake=3.29.6=hcafd917_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py310hff52083_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=ha770c72_1 - - contourpy=1.2.1=py310hd41b1e2_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=he654da7_0 - - cvxopt=1.3.2=py310h7b0674a_2 - - cxx-compiler=1.7.0=h00ab1b0_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py310h14ed79e_0 - - cysignals=1.11.2=py310h945e7c7_3 - - cython=3.0.10=py310hc6cd4ac_0 - - dbus=1.13.6=h5008d03_3 - - debugpy=1.8.1=py310hc6cd4ac_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hd9d9efa_1203 - - ecl=23.9.9=hed6455c_0 - - eclib=20231212=h96f522a_0 - - ecm=7.0.5=h9458935_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h59595ed_0 - - fflas-ffpack=2.5.0=h4f9960b_0 - - fftw=3.3.10=nompi_hf1063bd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h14ed4e7_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py310hc51659f_0 - - fortran-compiler=1.7.0=heb67821_1 - - fplll=5.4.5=h384768b_0 - - fpylll=0.6.1=py310h7e26f94_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=h267a509_2 - - fribidi=1.0.10=h36c2ea0_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he9a28a4_3 - - gap-defaults=4.12.2=ha770c72_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=h915e2ae_13 - - gcc_impl_linux-64=12.3.0=h58ffeeb_13 - - gcc_linux-64=12.3.0=h9528a6a_9 - - gengetopt=2.23=h9c3ff4c_0 - - gettext=0.22.5=h59595ed_2 - - gettext-tools=0.22.5=h59595ed_2 - - gf2x=1.3.0=ha476b99_2 - - gfan=0.6.2=hb86e20a_1003 - - gfortran=12.3.0=h915e2ae_13 - - gfortran_impl_linux-64=12.3.0=h8f2110c_13 - - gfortran_linux-64=12.3.0=h5877db1_9 - - giac=1.9.0.21=h673759e_1 - - giflib=5.2.2=hd590300_0 - - givaro=4.2.0=hb789bce_0 - - glib=2.80.2=h8a4344b_1 - - glib-tools=2.80.2=h73ef956_1 - - glpk=5.0=h445213a_0 - - gmp=6.3.0=hac33072_2 - - gmpy2=2.1.5=py310hc7909c9_1 - - graphite2=1.3.13=h59595ed_1003 - - gsl=2.7=he838d99_0 - - gst-plugins-base=1.24.5=hbaaba92_0 - - gstreamer=1.24.5=haf2f30d_0 - - gxx=12.3.0=h915e2ae_13 - - gxx_impl_linux-64=12.3.0=h2a574ab_13 - - gxx_linux-64=12.3.0=ha28b414_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=hfac3d4d_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h59595ed_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hef0740d_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h623f65a_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=ha770c72_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py310hff52083_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py310hff52083_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-64=2.6.32=he073ed8_17 - - keyutils=1.6.1=h166bdaf_0 - - kiwisolver=1.4.5=py310hd41b1e2_1 - - krb5=1.21.2=h659d440_0 - - lame=3.100=h166bdaf_1003 - - lcalc=2.0.5=h5aac1b6_2 - - lcms2=2.16=hb7c19ff_0 - - ld_impl_linux-64=2.40=hf3520f5_7 - - lerc=4.0.0=h27087fc_0 - - libasprintf=0.22.5=h661eb56_2 - - libasprintf-devel=0.22.5=h661eb56_2 - - libatomic_ops=7.6.14=h166bdaf_0 - - libblas=3.9.0=20_linux64_openblas - - libboost=1.85.0=hba137d9_2 - - libboost-devel=1.85.0=h00ab1b0_2 - - libboost-headers=1.85.0=ha770c72_2 - - libbraiding=1.2=hcb278e6_0 - - libbrial=1.2.12=h76af697_3 - - libbrotlicommon=1.1.0=hd590300_1 - - libbrotlidec=1.1.0=hd590300_1 - - libbrotlienc=1.1.0=hd590300_1 - - libcap=2.69=h0f662aa_0 - - libcblas=3.9.0=20_linux64_openblas - - libclang-cpp15=15.0.7=default_h127d8a8_5 - - libclang13=18.1.8=default_h6ae225f_0 - - libcups=2.3.3=h4637d8d_4 - - libcurl=8.8.0=hca28451_0 - - libdeflate=1.20=hd590300_0 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=hd590300_2 - - libevent=2.1.12=hf998b51_1 - - libexpat=2.6.2=h59595ed_0 - - libffi=3.4.2=h7f98852_5 - - libflac=1.4.3=h59595ed_0 - - libflint=3.0.1=h5f2e117_ntl_100 - - libgcc-devel_linux-64=12.3.0=h6b66f73_113 - - libgcc-ng=13.2.0=h77fa898_13 - - libgcrypt=1.10.3=hd590300_0 - - libgd=2.3.3=h119a65a_9 - - libgettextpo=0.22.5=h59595ed_2 - - libgettextpo-devel=0.22.5=h59595ed_2 - - libgfortran-ng=13.2.0=h69a702a_13 - - libgfortran5=13.2.0=h3d2ce59_13 - - libglib=2.80.2=h8a4344b_1 - - libgomp=13.2.0=h77fa898_13 - - libgpg-error=1.49=h4f305b6_0 - - libhomfly=1.02r6=hd590300_1 - - libhwloc=2.10.0=default_h5622ce7_1001 - - libiconv=1.17=hd590300_2 - - libjpeg-turbo=3.0.0=hd590300_1 - - liblapack=3.9.0=20_linux64_openblas - - liblapacke=3.9.0=20_linux64_openblas - - libllvm15=15.0.7=hb3ce162_4 - - libllvm18=18.1.8=hc9dba70_0 - - libnghttp2=1.58.0=h47da74e_1 - - libnsl=2.0.1=hd590300_0 - - libogg=1.3.5=h4ab18f5_0 - - libopenblas=0.3.25=pthreads_h413a1c8_0 - - libopus=1.3.1=h7f98852_1 - - libpng=1.6.43=h2797004_0 - - libpq=16.3=ha72fbe1_0 - - libsanitizer=12.3.0=hb8811af_13 - - libsndfile=1.2.2=hc60ed4a_1 - - libsodium=1.0.18=h36c2ea0_1 - - libsqlite=3.46.0=hde9e2c9_0 - - libssh2=1.11.0=h0841786_0 - - libstdcxx-devel_linux-64=12.3.0=h6b66f73_113 - - libstdcxx-ng=13.2.0=hc0a3c3a_13 - - libsystemd0=255=h3516f8a_1 - - libtiff=4.6.0=h1dd3fc0_3 - - libtool=2.4.7=h27087fc_0 - - libuuid=2.38.1=h0b41bf4_0 - - libuv=1.48.0=hd590300_0 - - libvorbis=1.3.7=h9c3ff4c_0 - - libwebp=1.4.0=h2c329e2_0 - - libwebp-base=1.4.0=hd590300_0 - - libxcb=1.16=hd590300_0 - - libxcrypt=4.4.36=hd590300_1 - - libxkbcommon=1.7.0=h2c5496b_1 - - libxml2=2.12.7=hc051c1a_1 - - libzlib=1.3.1=h4ab18f5_1 - - linbox=1.7.0=ha329b40_0 - - llvm-openmp=18.1.8=hf5423f3_0 - - lrcalc=2.1=h59595ed_6 - - lz4-c=1.9.4=hcb278e6_0 - - m4=1.4.18=h516909a_1001 - - m4ri=20140914=hae5d5c5_1006 - - m4rie=20150908=h267a509_1002 - - make=4.3=hd18ef5c_1 - - markupsafe=2.1.5=py310h2372a71_0 - - mathjax=3.2.2=ha770c72_0 - - matplotlib=3.8.4=py310hff52083_2 - - matplotlib-base=3.8.4=py310hef631a5_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=hed6455c_2 - - memory-allocator=0.1.3=py310h2372a71_0 - - metis=5.1.0=h59595ed_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=hfe3b2da_0 - - mpfi=1.5.4=h9f54685_1001 - - mpfr=4.2.1=h9458935_1 - - mpg123=1.32.6=h59595ed_0 - - mpmath=1.3.0=pyhd8ed1ab_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - mysql-common=8.3.0=hf1915f5_4 - - mysql-libs=8.3.0=hca2cd23_4 - - nauty=2.8.8=hd590300_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h59595ed_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h297d8ca_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - nspr=4.35=h27087fc_0 - - nss=3.101=h593d115_0 - - ntl=11.4.3=hef3c4d3_1 - - numpy=1.26.4=py310hb13e2d6_0 - - openblas=0.3.25=pthreads_h7a3da1a_0 - - openjdk=21.0.2=haa376d0_0 - - openjpeg=2.5.2=h488ebb8_0 - - openssl=3.3.1=h4ab18f5_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=h36c2ea0_0 - - pandoc=3.2.1=ha770c72_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h84a9a3c_0 - - pari=2.15.5=h4d4ae9b_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=h7f98852_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h0f59acf_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_hd590300_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py310hebfe307_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.2=h59595ed_0 - - pkg-config=0.29.2=h36c2ea0_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=hd590300_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h6ec01c2_1006 - - pplpy=0.8.9=py310h18554fa_1 - - primecount=7.9=hcb278e6_0 - - primecountpy=0.1.0=py310hd41b1e2_4 - - primesieve=11.1=h59595ed_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py310hc51659f_0 - - pthread-stubs=0.4=h36c2ea0_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pulseaudio-client=17.0=hb77b528_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py310hd41b1e2_0 - - pybind11-global=2.12.0=py310hd41b1e2_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyqt=5.15.9=py310h04931ad_5 - - pyqt5-sip=12.12.2=py310hc6cd4ac_5 - - pyrsistent=0.20.0=py310h2372a71_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.10.14=hd12c33a_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py310hc6cd4ac_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.10=4_cp310 - - pythran=0.15.0=py310hcb52e73_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py310hff52083_4 - - pyyaml=6.0.1=py310h2372a71_1 - - pyzmq=26.0.3=py310h6883aea_0 - - qd=2.3.22=h2cc385e_1004 - - qhull=2020.2=h4bd325d_2 - - qt-main=5.15.8=ha2b5568_22 - - r-base=4.3.3=he2d9a6e_3 - - r-lattice=0.22_6=r43h57805ef_0 - - readline=8.2=h8228510_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hd590300_0 - - rpds-py=0.18.1=py310he421c4c_0 - - rpy2=3.5.11=py310r43h1f7b6fc_3 - - rw=0.9=hd590300_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py310hb13e2d6_0 - - sed=4.8=he412f7d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h33f5c3f_1 - - sip=6.7.12=py310hc6cd4ac_0 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h6d4b2fc_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf4753ba_1 - - symmetrica=3.0.1=hcb278e6_0 - - sympow=2.023.6=hc6ab17c_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-64=2.12=he073ed8_17 - - tachyon=0.99b6=hba7d16a_1002 - - tar=1.34=hb2e2bae_1 - - tbb=2021.12.0=h297d8ca_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h0f457ee_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=noxft_h4845f30_101 - - tktable=2.10=h8bc8fbc_6 - - toml=0.10.2=pyhd8ed1ab_0 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py310hc51659f_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py310hff52083_0 - - unicodedata2=15.1.0=py310h2372a71_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xcb-util=0.4.1=hb711507_2 - - xcb-util-image=0.4.0=hb711507_2 - - xcb-util-keysyms=0.4.1=hb711507_0 - - xcb-util-renderutil=0.3.10=hb711507_0 - - xcb-util-wm=0.4.2=hb711507_0 - - xkeyboard-config=2.42=h4ab18f5_0 - - xorg-fixesproto=5.0=h7f98852_1002 - - xorg-inputproto=2.3.2=h7f98852_1002 - - xorg-kbproto=1.0.7=h7f98852_1002 - - xorg-libice=1.1.1=hd590300_0 - - xorg-libsm=1.2.4=h7391055_0 - - xorg-libx11=1.8.9=hb711507_1 - - xorg-libxau=1.0.11=hd590300_0 - - xorg-libxdmcp=1.1.3=h7f98852_0 - - xorg-libxext=1.3.4=h0b41bf4_2 - - xorg-libxfixes=5.0.3=h7f98852_1004 - - xorg-libxi=1.7.10=h7f98852_0 - - xorg-libxrender=0.9.11=hd590300_0 - - xorg-libxt=1.3.0=hd590300_1 - - xorg-libxtst=1.2.3=h7f98852_1002 - - xorg-recordproto=1.14.2=h7f98852_1002 - - xorg-renderproto=0.11.1=h7f98852_1002 - - xorg-xextproto=7.3.0=h0b41bf4_1003 - - xorg-xf86vidmodeproto=2.3.1=h7f98852_1002 - - xorg-xproto=7.0.31=h7f98852_1007 - - xz=5.2.6=h166bdaf_0 - - yaml=0.2.5=h7f98852_2 - - zeromq=4.3.5=h75354e8_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h4ab18f5_1 - - zstd=1.5.6=ha6fb4c9_0 diff --git a/environment-3.10-macos-x86_64.yml b/environment-3.10-macos-x86_64.yml deleted file mode 100644 index ebac3ba4872..00000000000 --- a/environment-3.10-macos-x86_64.yml +++ /dev/null @@ -1,424 +0,0 @@ -name: sage -# Generated by conda-lock. -# platform: osx-64 -# input_hash: 831a1103cbcd8c06cbae982446953e3de30517fdd302ac5aa70454b8d19f63d9 - -channels: - - conda-forge -dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py310h6729b98_4 - - arpack=3.9.1=nompi_hf81eadf_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321hed12c24_1 - - automake=1.16.5=pl5321h694c41f_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=h0d85af4_0 - - bdw-gc=8.0.6=h940c156_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osx64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h07eb623_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h0dc2134_1 - - brotli-bin=1.1.0=h0dc2134_1 - - brotli-python=1.1.0=py310h9e9d8ca_1 - - bwidget=1.9.14=h694c41f_1 - - bzip2=1.0.8=h10d778d_5 - - c-ares=1.28.1=h10d778d_0 - - c-compiler=1.7.0=h282daa2_1 - - ca-certificates=2024.6.2=h8857fd0_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=h9f650ed_2 - - cctools=986=h40f6528_0 - - cctools_osx-64=986=ha1c5b94_0 - - cddlib=1!0.94m=h0f52abe_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py310hdca579f_0 - - chardet=5.2.0=py310h2ec42d9_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_ha3b9224_8 - - clang-16=16.0.6=default_h4c8afb6_8 - - clang_impl_osx-64=16.0.6=h8787910_16 - - clang_osx-64=16.0.6=hb91bd55_16 - - clangxx=16.0.6=default_ha3b9224_8 - - clangxx_impl_osx-64=16.0.6=h6d92fbe_16 - - clangxx_osx-64=16.0.6=hb91bd55_16 - - cliquer=1.22=h10d778d_1 - - cmake=3.29.6=h749d262_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py310h2ec42d9_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=ha38d28d_2 - - compiler-rt_osx-64=16.0.6=ha38d28d_2 - - compilers=1.7.0=h694c41f_1 - - contourpy=1.2.1=py310hb3b189b_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=hea67d85_0 - - cvxopt=1.3.2=py310h1fac3e1_2 - - cxx-compiler=1.7.0=h7728843_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py310hc7df965_0 - - cysignals=1.11.2=py310h8c82e65_3 - - cython=3.0.10=py310h5daac23_0 - - debugpy=1.8.1=py310h5daac23_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h6e329d1_1203 - - ecl=23.9.9=h2b27fa8_0 - - eclib=20231212=h02435c3_0 - - ecm=7.0.5=h4f6b447_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h73e2aa4_0 - - fflas-ffpack=2.5.0=h5898d61_0 - - fftw=3.3.10=nompi_h292e606_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h5bb23bf_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py310h936d840_0 - - fortran-compiler=1.7.0=h6c2ab21_1 - - fplll=5.4.5=hb7981ad_0 - - fpylll=0.6.1=py310h65a3d7e_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=h60636b9_2 - - fribidi=1.0.10=hbcb3906_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=hc16eb5f_3 - - gap-defaults=4.12.2=h694c41f_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=he49afe7_0 - - gettext=0.22.5=h5ff76d1_2 - - gettext-tools=0.22.5=h5ff76d1_2 - - gf2x=1.3.0=hb2a7efb_2 - - gfan=0.6.2=hd793b56_1003 - - gfortran=12.3.0=h2c809b3_1 - - gfortran_impl_osx-64=12.3.0=hc328e78_3 - - gfortran_osx-64=12.3.0=h18f7dce_1 - - giac=1.9.0.21=h92f3f65_1 - - giflib=5.2.2=h10d778d_0 - - givaro=4.2.0=h1b3d6f7_0 - - glpk=5.0=h3cb5acd_0 - - gmp=6.3.0=hf036a51_2 - - gmpy2=2.1.5=py310h0310db1_1 - - graphite2=1.3.13=h73e2aa4_1003 - - gsl=2.7=h93259b0_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h053f038_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hf5e326d_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hde4452d_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h61918c1_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isl=0.26=imath32_h2e86a7b_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.9=h694c41f_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py310h2ec42d9_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py310h2ec42d9_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kiwisolver=1.4.5=py310h88cfcbd_1 - - krb5=1.21.2=hb884880_0 - - lcalc=2.0.5=h547a6ed_2 - - lcms2=2.16=ha2f27b4_0 - - ld64=711=ha02d983_0 - - ld64_osx-64=711=ha20a434_0 - - lerc=4.0.0=hb486fe8_0 - - libasprintf=0.22.5=h5ff76d1_2 - - libasprintf-devel=0.22.5=h5ff76d1_2 - - libatomic_ops=7.6.14=hb7f2c08_0 - - libblas=3.9.0=20_osx64_openblas - - libboost=1.85.0=h739af76_2 - - libboost-devel=1.85.0=h2b186f8_2 - - libboost-headers=1.85.0=h694c41f_2 - - libbraiding=1.2=hf0c8a7f_0 - - libbrial=1.2.12=h81e9653_3 - - libbrotlicommon=1.1.0=h0dc2134_1 - - libbrotlidec=1.1.0=h0dc2134_1 - - libbrotlienc=1.1.0=h0dc2134_1 - - libcblas=3.9.0=20_osx64_openblas - - libclang-cpp16=16.0.6=default_h4c8afb6_8 - - libcurl=8.8.0=hf9fcc65_0 - - libcxx=17.0.6=h88467a6_0 - - libdeflate=1.20=h49d49c5_0 - - libedit=3.1.20191231=h0678c8f_2 - - libev=4.33=h10d778d_2 - - libexpat=2.6.2=h73e2aa4_0 - - libffi=3.4.2=h0d85af4_5 - - libflint=3.0.1=h5d15de0_ntl_100 - - libgd=2.3.3=h0dceb68_9 - - libgettextpo=0.22.5=h5ff76d1_2 - - libgettextpo-devel=0.22.5=h5ff76d1_2 - - libgfortran=5.0.0=13_2_0_h97931a8_3 - - libgfortran-devel_osx-64=12.3.0=h0b6f5ec_3 - - libgfortran5=13.2.0=h2873a65_3 - - libglib=2.80.2=h736d271_1 - - libhomfly=1.02r6=h10d778d_1 - - libhwloc=2.10.0=default_h456cccd_1001 - - libiconv=1.17=hd75f5a5_2 - - libintl=0.22.5=h5ff76d1_2 - - libintl-devel=0.22.5=h5ff76d1_2 - - libjpeg-turbo=3.0.0=h0dc2134_1 - - liblapack=3.9.0=20_osx64_openblas - - liblapacke=3.9.0=20_osx64_openblas - - libllvm16=16.0.6=hbedff68_3 - - libnghttp2=1.58.0=h64cf6d3_1 - - libopenblas=0.3.25=openmp_hfef2a42_0 - - libpng=1.6.43=h92b6c6a_0 - - libsodium=1.0.18=hbcb3906_1 - - libsqlite=3.46.0=h1b8f9f3_0 - - libssh2=1.11.0=hd019ec5_0 - - libtiff=4.6.0=h129831d_3 - - libtool=2.4.7=hf0c8a7f_0 - - libuv=1.48.0=h67532ce_0 - - libwebp=1.4.0=hc207709_0 - - libwebp-base=1.4.0=h10d778d_0 - - libxcb=1.16=h0dc2134_0 - - libxml2=2.12.7=h3e169fe_1 - - libzlib=1.3.1=h87427d6_1 - - linbox=1.7.0=h7061c92_0 - - llvm-openmp=18.1.8=h15ab845_0 - - llvm-tools=16.0.6=hbedff68_3 - - lrcalc=2.1=h73e2aa4_6 - - m4=1.4.18=haf1e3a3_1001 - - m4ri=20140914=hd82a5f3_1006 - - m4rie=20150908=hc616cfc_1002 - - make=4.3=h22f3db7_1 - - markupsafe=2.1.5=py310hb372a2b_0 - - mathjax=3.2.2=h694c41f_0 - - matplotlib=3.8.4=py310h2ec42d9_2 - - matplotlib-base=3.8.4=py310h7ea1ff3_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2b27fa8_2 - - memory-allocator=0.1.3=py310h6729b98_0 - - metis=5.1.0=he965462_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=h81bd1dd_0 - - mpfi=1.5.4=h52b28e3_1001 - - mpfr=4.2.1=h4f6b447_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h10d778d_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h5846eda_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h3c5361c_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=h0ab3c2f_1 - - numpy=1.26.4=py310h4bfa8fc_0 - - openblas=0.3.25=openmp_h6794695_0 - - openjdk=22.0.1=h2d185b6_0 - - openjpeg=2.5.2=h7310d3a_0 - - openssl=3.3.1=h87427d6_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=hbcb3906_0 - - pandoc=3.2.1=h694c41f_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h880b76c_0 - - pari=2.15.5=h7ba67ff_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=hbcf498f_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h7634a1b_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h10d778d_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py310h2fdc51f_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h73e2aa4_0 - - pkg-config=0.29.2=ha3d46e9_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h10d778d_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=ha60d53e_1006 - - pplpy=0.8.9=py310hbe8aec3_1 - - primecount=7.6=ha894c9a_0 - - primecountpy=0.1.0=py310h88cfcbd_4 - - primesieve=11.0=hf0c8a7f_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py310h936d840_0 - - pthread-stubs=0.4=hc929b4f_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py310hb3b189b_0 - - pybind11-global=2.12.0=py310hb3b189b_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py310h445dc1f_0 - - pyobjc-framework-cocoa=10.3.1=py310h445dc1f_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py310hb372a2b_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.10.14=h00d2728_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py310h5daac23_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.10=4_cp310 - - pythran=0.15.0=py310h076e4b7_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py310h2ec42d9_4 - - pyyaml=6.0.1=py310h6729b98_1 - - pyzmq=26.0.3=py310he0bbd50_0 - - qd=2.3.22=h2beb688_1004 - - qhull=2020.2=h940c156_2 - - r-base=4.3.3=h4648a1f_3 - - r-lattice=0.22_6=r43hb2c329c_0 - - readline=8.2=h9e318b2_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h0dc2134_0 - - rpds-py=0.18.1=py310h12a1ced_0 - - rpy2=3.5.11=py310r43hf0b6da5_3 - - rw=0.9=h10d778d_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py310h3f1db6d_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - sigtool=0.1.3=h88f4db0_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h0d51a9f_1 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h28673e1_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hd2b2131_1 - - symmetrica=3.0.1=hf0c8a7f_0 - - sympow=2.023.6=h115ba6a_3 - - sympy=1.12.1=pypyh2585a3b_103 - - tachyon=0.99b6=h3a1d103_1002 - - tapi=1100.0.11=h9ce4665_0 - - tar=1.34=hcb2f6ea_1 - - tbb=2021.12.0=h3c5361c_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321hc47821c_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h1abcd95_1 - - tktable=2.10=hba9d6f1_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py310h936d840_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py310h2ec42d9_0 - - unicodedata2=15.1.0=py310h6729b98_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=h0dc2134_0 - - xorg-libxdmcp=1.1.3=h35c211d_0 - - xz=5.2.6=h775f41a_0 - - yaml=0.2.5=h0d85af4_2 - - zeromq=4.3.5=hde137ed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h87427d6_1 - - zstd=1.5.6=h915ae27_0 diff --git a/environment-3.10-macos.yml b/environment-3.10-macos.yml deleted file mode 100644 index 0c5d09880a1..00000000000 --- a/environment-3.10-macos.yml +++ /dev/null @@ -1,424 +0,0 @@ -name: sage -# Generated by conda-lock. -# platform: osx-arm64 -# input_hash: fce4b9b5cdb20ebb2d93612fa27b4d6584379772c37a8cccd6c2390e2ce5f3b1 - -channels: - - conda-forge -dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py310h2aa6e3c_4 - - arpack=3.9.1=nompi_h593882a_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321hcd07c0c_1 - - automake=1.16.5=pl5321hce30654_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=h3422bc3_0 - - bdw-gc=8.0.6=hc021e02_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osxarm64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=hca5e981_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hb547adb_1 - - brotli-bin=1.1.0=hb547adb_1 - - brotli-python=1.1.0=py310h1253130_1 - - bwidget=1.9.14=hce30654_1 - - bzip2=1.0.8=h93a5062_5 - - c-ares=1.28.1=h93a5062_0 - - c-compiler=1.7.0=h6aa9301_1 - - ca-certificates=2024.6.2=hf0a4a13_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=hc6c324b_2 - - cctools=986=h4faf515_0 - - cctools_osx-arm64=986=h62378fb_0 - - cddlib=1!0.94m=h6d7a090_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py310hdcd7c05_0 - - chardet=5.2.0=py310hbe9552e_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_h095aff0_8 - - clang-16=16.0.6=default_hb63da90_8 - - clang_impl_osx-arm64=16.0.6=hc421ffc_16 - - clang_osx-arm64=16.0.6=h54d7cd3_16 - - clangxx=16.0.6=default_h095aff0_8 - - clangxx_impl_osx-arm64=16.0.6=hcd7bac0_16 - - clangxx_osx-arm64=16.0.6=h54d7cd3_16 - - cliquer=1.22=h93a5062_1 - - cmake=3.29.6=had79d8f_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py310hbe9552e_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=h3808999_2 - - compiler-rt_osx-arm64=16.0.6=h3808999_2 - - compilers=1.7.0=hce30654_1 - - contourpy=1.2.1=py310h21239e6_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=h653d890_0 - - cvxopt=1.3.2=py310h7e4e7d1_2 - - cxx-compiler=1.7.0=h2ffa867_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py310h5e3d6bc_0 - - cysignals=1.11.2=py310hfd3b3fe_3 - - cython=3.0.10=py310h692a8b6_0 - - debugpy=1.8.1=py310h692a8b6_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h9397a75_1203 - - ecl=23.9.9=h1d9728a_0 - - eclib=20231212=h7f07de4_0 - - ecm=7.0.5=h41d338b_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=hebf3989_0 - - fflas-ffpack=2.5.0=h4bc3318_0 - - fftw=3.3.10=nompi_h6637ab6_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h82840c6_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py310ha6dd24b_0 - - fortran-compiler=1.7.0=hafb19e3_1 - - fplll=5.4.5=hb7d509d_0 - - fpylll=0.6.1=py310hd9be144_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=hadb7bae_2 - - fribidi=1.0.10=h27ca646_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he8f4e70_3 - - gap-defaults=4.12.2=hce30654_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=hbdafb3b_0 - - gettext=0.22.5=h8fbad5d_2 - - gettext-tools=0.22.5=h8fbad5d_2 - - gf2x=1.3.0=hdaa854c_2 - - gfan=0.6.2=hec08f5c_1003 - - gfortran=12.3.0=h1ca8e4b_1 - - gfortran_impl_osx-arm64=12.3.0=h53ed385_3 - - gfortran_osx-arm64=12.3.0=h57527a5_1 - - giac=1.9.0.21=h1c96721_1 - - giflib=5.2.2=h93a5062_0 - - givaro=4.2.0=h018886a_0 - - glpk=5.0=h6d7a090_0 - - gmp=6.3.0=h7bae524_2 - - gmpy2=2.1.5=py310h3bc658a_1 - - graphite2=1.3.13=hebf3989_1003 - - gsl=2.7=h6e638da_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h1836168_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hc8870d7_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h762ac30_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=hd73f12c_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isl=0.26=imath32_h347afa1_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=hce30654_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py310hbe9552e_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py310hbe9552e_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kiwisolver=1.4.5=py310h38f39d4_1 - - krb5=1.21.2=h92f50d5_0 - - lcalc=2.0.5=h4a402bc_2 - - lcms2=2.16=ha0e7c42_0 - - ld64=711=h634c8be_0 - - ld64_osx-arm64=711=ha4bd21c_0 - - lerc=4.0.0=h9a09cb3_0 - - libasprintf=0.22.5=h8fbad5d_2 - - libasprintf-devel=0.22.5=h8fbad5d_2 - - libatomic_ops=7.6.14=h1a8c8d9_0 - - libblas=3.9.0=20_osxarm64_openblas - - libboost=1.85.0=h17eb2be_2 - - libboost-devel=1.85.0=hf450f58_2 - - libboost-headers=1.85.0=hce30654_2 - - libbraiding=1.2=hb7217d7_0 - - libbrial=1.2.12=h56a29cd_3 - - libbrotlicommon=1.1.0=hb547adb_1 - - libbrotlidec=1.1.0=hb547adb_1 - - libbrotlienc=1.1.0=hb547adb_1 - - libcblas=3.9.0=20_osxarm64_openblas - - libclang-cpp16=16.0.6=default_hb63da90_8 - - libcurl=8.8.0=h7b6f9a7_0 - - libcxx=17.0.6=h5f092b4_0 - - libdeflate=1.20=h93a5062_0 - - libedit=3.1.20191231=hc8eb9b7_2 - - libev=4.33=h93a5062_2 - - libexpat=2.6.2=hebf3989_0 - - libffi=3.4.2=h3422bc3_5 - - libflint=3.0.1=h28749a5_ntl_100 - - libgd=2.3.3=hfdf3952_9 - - libgettextpo=0.22.5=h8fbad5d_2 - - libgettextpo-devel=0.22.5=h8fbad5d_2 - - libgfortran=5.0.0=13_2_0_hd922786_3 - - libgfortran-devel_osx-arm64=12.3.0=hc62be1c_3 - - libgfortran5=13.2.0=hf226fd6_3 - - libglib=2.80.2=h59d46d9_1 - - libhomfly=1.02r6=h93a5062_1 - - libhwloc=2.10.0=default_h7685b71_1001 - - libiconv=1.17=h0d3ecfb_2 - - libintl=0.22.5=h8fbad5d_2 - - libintl-devel=0.22.5=h8fbad5d_2 - - libjpeg-turbo=3.0.0=hb547adb_1 - - liblapack=3.9.0=20_osxarm64_openblas - - liblapacke=3.9.0=20_osxarm64_openblas - - libllvm16=16.0.6=haab561b_3 - - libnghttp2=1.58.0=ha4dd798_1 - - libopenblas=0.3.25=openmp_h6c19121_0 - - libpng=1.6.43=h091b4b1_0 - - libsodium=1.0.18=h27ca646_1 - - libsqlite=3.46.0=hfb93653_0 - - libssh2=1.11.0=h7a5bd25_0 - - libtiff=4.6.0=h07db509_3 - - libtool=2.4.7=hb7217d7_0 - - libuv=1.48.0=h93a5062_0 - - libwebp=1.4.0=h54798ee_0 - - libwebp-base=1.4.0=h93a5062_0 - - libxcb=1.16=hf2054a2_0 - - libxml2=2.12.7=ha661575_1 - - libzlib=1.3.1=hfb2fe0b_1 - - linbox=1.7.0=h3afee3a_0 - - llvm-openmp=18.1.8=hde57baf_0 - - llvm-tools=16.0.6=haab561b_3 - - lrcalc=2.1=hebf3989_6 - - m4=1.4.18=h642e427_1001 - - m4ri=20140914=hc97c1ff_1006 - - m4rie=20150908=h22b9e9d_1002 - - make=4.3=he57ea6c_1 - - markupsafe=2.1.5=py310hd125d64_0 - - mathjax=3.2.2=hce30654_0 - - matplotlib=3.8.4=py310hb6292c7_2 - - matplotlib-base=3.8.4=py310hedb7998_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2bbcd85_2 - - memory-allocator=0.1.3=py310h2aa6e3c_0 - - metis=5.1.0=h13dd4ca_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=h91ba8db_0 - - mpfi=1.5.4=hbde5f5b_1001 - - mpfr=4.2.1=h41d338b_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h93a5062_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=hb89a1cb_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h420ef59_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=hbb3f309_1 - - numpy=1.26.4=py310hd45542a_0 - - openblas=0.3.25=openmp_h55c453e_0 - - openjdk=22.0.1=hbeb2e11_0 - - openjpeg=2.5.2=h9f1df11_0 - - openssl=3.3.1=hfb2fe0b_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=h27ca646_0 - - pandoc=3.2.1=hce30654_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h5cb9fbc_0 - - pari=2.15.5=h4f2304c_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=h27ca646_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h297a79d_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h4614cfb_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py310h01af8b1_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=hebf3989_0 - - pkg-config=0.29.2=hab62308_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h93a5062_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h8b147cf_1006 - - pplpy=0.8.9=py310hc3af9bb_1 - - primecount=7.6=hb6e4faa_0 - - primecountpy=0.1.0=py310h38f39d4_4 - - primesieve=11.0=hb7217d7_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py310ha6dd24b_0 - - pthread-stubs=0.4=h27ca646_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py310h21239e6_0 - - pybind11-global=2.12.0=py310h21239e6_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py310h4b7648a_0 - - pyobjc-framework-cocoa=10.3.1=py310h4b7648a_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py310hd125d64_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.10.14=h2469fbe_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py310h692a8b6_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.10=4_cp310 - - pythran=0.15.0=py310h1359cc7_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py310hbe9552e_4 - - pyyaml=6.0.1=py310h2aa6e3c_1 - - pyzmq=26.0.3=py310h16e08c9_0 - - qd=2.3.22=hbec66e7_1004 - - qhull=2020.2=hc021e02_2 - - r-base=4.3.3=h8112bfe_3 - - r-lattice=0.22_6=r43hd2d937b_0 - - readline=8.2=h92ec313_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hb547adb_0 - - rpds-py=0.18.1=py310h947b723_0 - - rpy2=3.5.11=py310r43h280b8fa_3 - - rw=0.9=h93a5062_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py310h2b794db_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - sigtool=0.1.3=h44b9a77_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hb460b52_1 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h5838104_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf6fcff2_1 - - symmetrica=3.0.1=hb7217d7_0 - - sympow=2.023.6=hb0babe8_3 - - sympy=1.12.1=pypyh2585a3b_103 - - tachyon=0.99b6=hb8a568e_1002 - - tapi=1100.0.11=he4954df_0 - - tar=1.34=h7cb298e_1 - - tbb=2021.12.0=h420ef59_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321h9ea1dce_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h5083fa2_1 - - tktable=2.10=h1e387b8_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py310ha6dd24b_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py310hbe9552e_0 - - unicodedata2=15.1.0=py310h2aa6e3c_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=hb547adb_0 - - xorg-libxdmcp=1.1.3=h27ca646_0 - - xz=5.2.6=h57fd34a_0 - - yaml=0.2.5=h3422bc3_2 - - zeromq=4.3.5=hcc0f68c_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=hfb2fe0b_1 - - zstd=1.5.6=hb46c0d2_0 diff --git a/environment-3.11-linux-aarch64.yml b/environment-3.11-linux-aarch64.yml index e6a24cbe706..c17c3395c99 100644 --- a/environment-3.11-linux-aarch64.yml +++ b/environment-3.11-linux-aarch64.yml @@ -1,435 +1,338 @@ -name: sage +name: sage-dev # Generated by conda-lock. # platform: linux-aarch64 -# input_hash: 53cce21c9c8a4b11b84e96405de20cc945c84809a7997b8508761fc9ca727ee0 +# input_hash: 09e3b72a7aa5c065370cb8a339e14ed42ad43f0c89abc55b38713be2d4560fd9 channels: - conda-forge dependencies: - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - _sysroot_linux-aarch64_curr_repodata_hack=4=h57d6b7b_14 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.11=h31becfc_1 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py311hcd402e7_4 + - alabaster=1.0.0=pyhd8ed1ab_1 + - alsa-lib=1.2.13=h86ecc28_0 - arpack=3.9.1=nompi_hd363cd0_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 + - asttokens=3.0.0=pyhd8ed1ab_1 - autoconf=2.71=pl5321h2148fe1_1 - - automake=1.16.5=pl5321h8af1aa0_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=hf897c2e_0 + - automake=1.17=pl5321h8af1aa0_0 + - babel=2.16.0=pyhd8ed1ab_1 - bdw-gc=8.0.6=hd62202e_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=hf1166c9_7 - - binutils_impl_linux-aarch64=2.40=hf54a868_7 - - binutils_linux-aarch64=2.40=h1f91aba_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linuxaarch64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=ha990451_2 + - beautifulsoup4=4.12.3=pyha770c72_1 + - binutils=2.43=hf1166c9_2 + - binutils_impl_linux-aarch64=2.43=h4c662bb_2 + - binutils_linux-aarch64=2.43=hf1166c9_2 + - blas=2.126=openblas + - blas-devel=3.9.0=26_linuxaarch64_openblas + - boost-cpp=1.85.0=hdad291f_4 - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h31becfc_1 - - brotli-bin=1.1.0=h31becfc_1 - - brotli-python=1.1.0=py311h8715677_1 - - bwidget=1.9.14=h8af1aa0_1 - - bzip2=1.0.8=h31becfc_5 - - c-ares=1.28.1=h31becfc_0 - - c-compiler=1.7.0=h31becfc_1 - - ca-certificates=2024.6.2=hcefe29a_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=h5c54ea9_2 + - brotli=1.1.0=h86ecc28_2 + - brotli-bin=1.1.0=h86ecc28_2 + - brotli-python=1.1.0=py311h89d996e_2 + - bzip2=1.0.8=h68df207_7 + - c-ares=1.34.4=h86ecc28_0 + - c-compiler=1.8.0=h6561dab_1 + - ca-certificates=2024.12.14=hcefe29a_0 + - cairo=1.18.2=h83712da_1 - cddlib=1!0.94m=h719063d_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py311h7963103_0 - - chardet=5.2.0=py311hfecb2dc_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 + - certifi=2024.12.14=pyhd8ed1ab_0 + - cffi=1.17.1=py311h14e8bb7_0 + - charset-normalizer=3.4.0=pyhd8ed1ab_1 - cliquer=1.22=h31becfc_1 - - cmake=3.29.6=h7042e5d_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py311hec3470c_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=h8af1aa0_1 - - contourpy=1.2.1=py311h098ece5_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=h7daf2e0_0 - - cvxopt=1.3.2=py311ha095bbf_2 - - cxx-compiler=1.7.0=h2a328a1_1 - - cycler=0.12.1=pyhd8ed1ab_0 + - colorama=0.4.6=pyhd8ed1ab_1 + - comm=0.2.2=pyhd8ed1ab_1 + - contourpy=1.3.1=py311hc07b1fb_0 + - conway-polynomials=0.10=pyhd8ed1ab_0 + - coverage=7.6.9=py311ha09ea12_0 + - cpython=3.11.11=py311hd8ed1ab_1 + - cxx-compiler=1.8.0=heb6c788_1 + - cycler=0.12.1=pyhd8ed1ab_1 - cypari2=2.1.5=py311h5ab95f0_0 + - cyrus-sasl=2.1.27=hf6b2984_7 - cysignals=1.11.2=py311h644d908_3 - - cython=3.0.10=py311h8715677_0 - - debugpy=1.8.1=py311h8715677_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hb12102e_1203 - - ecl=23.9.9=h6475f26_0 - - eclib=20231212=he26bab5_0 + - cython=3.0.11=py311hac78f04_3 + - dbus=1.13.6=h12b9eeb_3 + - debugpy=1.8.11=py311h89d996e_0 + - decorator=5.1.1=pyhd8ed1ab_1 + - docutils=0.21.2=pyhd8ed1ab_1 + - double-conversion=3.3.0=h2f0025b_0 + - ecl=24.5.10=h5567cc5_0 + - eclib=20231212=h154513d_1 - ecm=7.0.5=ha2d0fc4_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h2f0025b_0 + - exceptiongroup=1.2.2=pyhd8ed1ab_1 + - execnet=2.1.1=pyhd8ed1ab_1 + - executing=2.1.0=pyhd8ed1ab_1 + - expat=2.6.4=h5ad3122_0 - fflas-ffpack=2.5.0=h503e619_0 - - fftw=3.3.10=nompi_h020dacd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - font-ttf-inconsolata=3.000=h77eed37_0 - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=ha9a116f_0 + - font-ttf-ubuntu=0.83=h77eed37_3 + - fontconfig=2.15.0=h8dda3cd_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.53.0=py311hf4892ed_0 - - fortran-compiler=1.7.0=h7048d53_1 + - fonttools=4.55.3=py311h58d527c_0 + - fortran-compiler=1.8.0=h25a59a9_1 - fplll=5.4.5=hb3a790e_0 - fpylll=0.6.1=py311h5d3d69a_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - freetype=2.12.1=hf0a5ef3_2 - - fribidi=1.0.10=hb9de7d4_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=h597289e_3 - - gap-defaults=4.12.2=h8af1aa0_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=hdb0cc85_13 - - gcc_impl_linux-aarch64=12.3.0=h3d98823_13 - - gcc_linux-aarch64=12.3.0=ha52a6ea_9 - - gengetopt=2.23=h01db608_0 - - gf2x=1.3.0=h1b3b3a3_2 + - furo=2024.8.6=pyhd8ed1ab_1 + - gap-core=4.14.0=h1754e88_1 + - gap-defaults=4.14.0=h8af1aa0_1 + - gcc=13.3.0=h8a56e6e_1 + - gcc_impl_linux-aarch64=13.3.0=hcdea9b6_1 + - gcc_linux-aarch64=13.3.0=h1cd514b_7 + - gf2x=1.3.0=h9af5f66_3 - gfan=0.6.2=h5f589ec_1003 - - gfortran=12.3.0=hdb0cc85_13 - - gfortran_impl_linux-aarch64=12.3.0=h97ebfd2_13 - - gfortran_linux-aarch64=12.3.0=ha7b8e4b_9 + - gfortran=13.3.0=h8a56e6e_1 + - gfortran_impl_linux-aarch64=13.3.0=h174a3c4_1 + - gfortran_linux-aarch64=13.3.0=h2809cf8_7 - giac=1.9.0.21=h04922a4_1 - - giflib=5.2.2=h31becfc_0 - givaro=4.2.0=h364d21b_0 - glpk=5.0=h66325d0_0 - gmp=6.3.0=h0a1ffab_2 - - gmpy2=2.1.5=py311h3c136a7_1 + - gmpy2=2.1.5=py311h8dd2ae4_3 - graphite2=1.3.13=h2f0025b_1003 - gsl=2.7=h294027d_0 - - gxx=12.3.0=hdb0cc85_13 - - gxx_impl_linux-aarch64=12.3.0=hba91e99_13 - - gxx_linux-aarch64=12.3.0=h9d1f256_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h9812418_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h787c7f5_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h197073e_1 + - gxx=13.3.0=h8a56e6e_1 + - gxx_impl_linux-aarch64=13.3.0=h1211b58_1 + - gxx_linux-aarch64=13.3.0=h2864abd_7 + - h2=4.1.0=pyhd8ed1ab_1 + - harfbuzz=9.0.0=hbf49d6b_1 + - hpack=4.0.0=pyhd8ed1ab_1 + - hyperframe=6.0.1=pyhd8ed1ab_1 + - icu=75.1=hf9b3779_0 + - idna=3.10=pyhd8ed1ab_1 + - igraph=0.10.15=h207f3e5_1 - imagesize=1.4.1=pyhd8ed1ab_0 - iml=1.0.5=h15043fe_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=h8af1aa0_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py311hec3470c_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py311hec3470c_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-aarch64=4.18.0=h5b4a56d_14 + - importlib-metadata=8.5.0=pyha770c72_1 + - iniconfig=2.0.0=pyhd8ed1ab_1 + - ipykernel=6.29.5=pyh3099207_0 + - ipython=8.30.0=pyh707e725_0 + - ipywidgets=8.1.5=pyhd8ed1ab_1 + - jedi=0.19.2=pyhd8ed1ab_1 + - jinja2=3.1.4=pyhd8ed1ab_1 + - jupyter_client=8.6.3=pyhd8ed1ab_1 + - jupyter_core=5.7.2=pyh31011fe_1 + - jupyterlab_widgets=3.0.13=pyhd8ed1ab_1 + - kernel-headers_linux-aarch64=4.18.0=h05a177a_18 - keyutils=1.6.1=h4e544f5_0 - - kiwisolver=1.4.5=py311h0d5d7b0_1 - - krb5=1.21.2=hc419048_0 + - kiwisolver=1.4.7=py311h75754e6_0 + - krb5=1.21.3=h50a48e9_0 - lcalc=2.0.5=he588f68_2 - lcms2=2.16=h922389a_0 - - ld_impl_linux-aarch64=2.40=h9fc2d93_7 + - ld_impl_linux-aarch64=2.43=h80caac9_2 - lerc=4.0.0=h4de3ea5_0 - - libatomic_ops=7.6.14=h4e544f5_0 - - libblas=3.9.0=20_linuxaarch64_openblas - - libboost=1.85.0=hb41fec8_2 - - libboost-devel=1.85.0=h37bb5a9_2 - - libboost-headers=1.85.0=h8af1aa0_2 - - libbraiding=1.2=hd600fc2_0 + - libblas=3.9.0=26_linuxaarch64_openblas + - libboost=1.85.0=h9fa81b4_4 + - libboost-devel=1.85.0=h37bb5a9_4 + - libboost-headers=1.85.0=h8af1aa0_4 + - libbraiding=1.3=h5ad3122_0 - libbrial=1.2.12=h9429f74_3 - - libbrotlicommon=1.1.0=h31becfc_1 - - libbrotlidec=1.1.0=h31becfc_1 - - libbrotlienc=1.1.0=h31becfc_1 - - libcblas=3.9.0=20_linuxaarch64_openblas + - libbrotlicommon=1.1.0=h86ecc28_2 + - libbrotlidec=1.1.0=h86ecc28_2 + - libbrotlienc=1.1.0=h86ecc28_2 + - libcblas=3.9.0=26_linuxaarch64_openblas + - libclang-cpp19.1=19.1.6=default_he324ac1_0 + - libclang13=19.1.6=default_h4390ef5_0 - libcups=2.3.3=h405e4a8_4 - - libcurl=8.8.0=h4e8248e_0 - - libdeflate=1.20=h31becfc_0 + - libcurl=8.11.1=h6702fde_0 + - libdeflate=1.23=h5e3c512_0 + - libdrm=2.4.124=h86ecc28_0 - libedit=3.1.20191231=he28a2e2_2 + - libegl=1.7.0=hd24410f_2 - libev=4.33=h31becfc_2 - - libexpat=2.6.2=h2f0025b_0 + - libexpat=2.6.4=h5ad3122_0 - libffi=3.4.2=h3557bc0_5 - - libflint=3.0.1=hc392af7_ntl_100 - - libgcc-devel_linux-aarch64=12.3.0=h6144e03_113 - - libgcc-ng=13.2.0=he277a41_13 - - libgd=2.3.3=hcd22fd5_9 - - libgfortran-ng=13.2.0=he9431aa_13 - - libgfortran5=13.2.0=h2af0866_13 - - libglib=2.80.2=haee52c6_1 - - libgomp=13.2.0=he277a41_13 + - libflint=3.1.2=h0433c20_101 + - libgcc=14.2.0=he277a41_1 + - libgcc-devel_linux-aarch64=13.3.0=h0c07274_101 + - libgcc-ng=14.2.0=he9431aa_1 + - libgd=2.3.3=h6818b27_10 + - libgfortran=14.2.0=he9431aa_1 + - libgfortran-ng=14.2.0=he9431aa_1 + - libgfortran5=14.2.0=hb6113d0_1 + - libgl=1.7.0=hd24410f_2 + - libglib=2.82.2=hc486b8e_0 + - libglvnd=1.7.0=hd24410f_2 + - libglx=1.7.0=hd24410f_2 + - libgomp=14.2.0=he277a41_1 - libhomfly=1.02r6=h31becfc_1 - - libhwloc=2.10.0=default_h3030c0e_1001 - libiconv=1.17=h31becfc_2 - libjpeg-turbo=3.0.0=h31becfc_1 - - liblapack=3.9.0=20_linuxaarch64_openblas - - liblapacke=3.9.0=20_linuxaarch64_openblas - - libnghttp2=1.58.0=hb0e430d_1 + - liblapack=3.9.0=26_linuxaarch64_openblas + - liblapacke=3.9.0=26_linuxaarch64_openblas + - libllvm19=19.1.6=h2edbd07_0 + - liblzma=5.6.3=h86ecc28_1 + - liblzma-devel=5.6.3=h86ecc28_1 + - libnghttp2=1.64.0=hc8609a4_0 - libnsl=2.0.1=h31becfc_0 - - libopenblas=0.3.25=pthreads_h5a5ec62_0 - - libpng=1.6.43=h194ca79_0 - - libsanitizer=12.3.0=h57e2e72_13 - - libsodium=1.0.18=hb9de7d4_1 - - libsqlite=3.46.0=hf51ef55_0 - - libssh2=1.11.0=h492db2e_0 - - libstdcxx-devel_linux-aarch64=12.3.0=h6144e03_113 - - libstdcxx-ng=13.2.0=h3f4de04_13 - - libtiff=4.6.0=hf980d43_3 - - libtool=2.4.7=h4de3ea5_0 + - libntlm=1.4=hf897c2e_1002 + - libopenblas=0.3.28=pthreads_h9d3fd7e_1 + - libopengl=1.7.0=hd24410f_2 + - libpciaccess=0.18=h31becfc_0 + - libpng=1.6.44=hc4a20ef_0 + - libpq=17.2=hd56632b_1 + - libsanitizer=13.3.0=ha58e236_1 + - libsodium=1.0.20=h68df207_0 + - libsqlite=3.47.2=h5eb1b54_0 + - libssh2=1.11.1=ha41c0db_0 + - libstdcxx=14.2.0=h3f4de04_1 + - libstdcxx-devel_linux-aarch64=13.3.0=h0c07274_101 + - libstdcxx-ng=14.2.0=hf1166c9_1 + - libtiff=4.7.0=h88f7998_3 - libuuid=2.38.1=hb4cce97_0 - - libuv=1.48.0=h31becfc_0 - - libwebp=1.4.0=h8b4e01b_0 - libwebp-base=1.4.0=h31becfc_0 - - libxcb=1.16=h7935292_0 + - libxcb=1.17.0=h262b8f6_0 - libxcrypt=4.4.36=h31becfc_1 - - libxml2=2.12.7=h49dc7a2_1 - - libzlib=1.3.1=h68df207_1 - - linbox=1.7.0=h681a5ee_0 - - llvm-openmp=18.1.8=hb063fc5_0 - - lrcalc=2.1=h2f0025b_6 + - libxkbcommon=1.7.0=h46f2afe_1 + - libxml2=2.13.5=h2e0c361_1 + - libxslt=1.1.39=h1cc9640_0 + - libzlib=1.3.1=h86ecc28_2 + - linbox=1.7.0=hf74d613_1 + - llvm-openmp=19.1.6=h013ceaa_0 + - lrcalc=2.1=h5ad3122_7 - m4=1.4.18=h516909a_1001 - m4ri=20140914=hedfd65a_1006 - - m4rie=20150908=hf0a5ef3_1002 - - make=4.3=h309ac5b_1 - - markupsafe=2.1.5=py311hc8f2f60_0 - - mathjax=3.2.2=h8af1aa0_0 - - matplotlib=3.8.4=py311hfecb2dc_2 - - matplotlib-base=3.8.4=py311h55059f0_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h6475f26_2 - - memory-allocator=0.1.3=py311hcd402e7_0 - - metis=5.1.0=h2f0025b_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=hf4c8f4c_0 + - m4rie=20200125=hedfd65a_0 + - markupsafe=3.0.2=py311ha09ea12_1 + - matplotlib=3.10.0=py311hfecb2dc_0 + - matplotlib-base=3.10.0=py311h0385ec1_0 + - matplotlib-inline=0.1.7=pyhd8ed1ab_1 + - maxima=5.47.0=h043f013_3 + - memory-allocator=0.1.3=py311ha879c10_1 + - meson=1.6.1=pyhd8ed1ab_0 + - meson-python=0.17.1=pyh70fd9c4_1 + - mpc=1.3.1=h783934e_1 - mpfi=1.5.4=h846f343_1001 - - mpfr=4.2.1=ha2d0fc4_1 - - mpmath=1.3.0=pyhd8ed1ab_0 + - mpfr=4.2.1=h2305555_3 + - mpmath=1.3.0=pyhd8ed1ab_1 - munkres=1.1.4=pyh9f0ad1d_0 + - mysql-common=9.0.1=h3f5c77f_3 + - mysql-libs=9.0.1=h11569fd_3 - nauty=2.8.8=h31becfc_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h0425590_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 + - ncurses=6.5=hcccb83c_1 + - nest-asyncio=1.6.0=pyhd8ed1ab_1 + - networkx=3.4.2=pyh267e887_2 - ninja=1.12.1=h70be974_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - ntl=11.4.3=h0d7519b_1 - numpy=1.26.4=py311h69ead2a_0 - - openblas=0.3.25=pthreads_h339cbfa_0 - - openjdk=22.0.1=h3d4cd67_0 - - openjpeg=2.5.2=h0d9d63b_0 - - openssl=3.3.1=h68df207_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 + - openblas=0.3.28=pthreads_h3a8cbd8_1 + - openjpeg=2.5.3=h3f56577_0 + - openldap=2.6.9=h30c48ee_0 + - openssl=3.4.0=h86ecc28_0 + - packaging=24.2=pyhd8ed1ab_2 - palp=2.20=hb9de7d4_0 - - pandoc=3.2.1=h8af1aa0_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h399c48b_0 - pari=2.15.5=h169c2a7_2_pthread - pari-elldata=0.0.20161017=0 - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - pari-seadata=0.0.20090618=0 - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=hf897c2e_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h070dd5b_0 - - pep517=0.13.0=pyhd8ed1ab_0 + - parso=0.8.4=pyhd8ed1ab_1 + - pcre2=10.44=h070dd5b_2 - perl=5.32.1=7_h31becfc_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py311h54289d1_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h2f0025b_0 - - pkg-config=0.29.2=hb9de7d4_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 + - pexpect=4.9.0=pyhd8ed1ab_1 + - pickleshare=0.7.5=pyhd8ed1ab_1004 + - pillow=11.0.0=py311hb2a0dd2_0 + - pip=24.3.1=pyh8b19718_2 + - pixman=0.44.2=h86a87f0_0 + - pkg-config=0.29.2=hce167ba_1009 + - pkgconfig=1.5.5=pyhd8ed1ab_5 - planarity=3.0.2.0=h31becfc_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 + - platformdirs=4.3.6=pyhd8ed1ab_1 + - pluggy=1.5.0=pyhd8ed1ab_1 - ppl=1.2=h984aac9_1006 - pplpy=0.8.9=py311ha3770eb_1 - primecount=7.9=hd600fc2_0 - primecountpy=0.1.0=py311h098ece5_4 - primesieve=11.1=h2f0025b_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py311hf4892ed_0 - - pthread-stubs=0.4=hb9de7d4_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py311h098ece5_0 - - pybind11-global=2.12.0=py311h098ece5_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py311hc8f2f60_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.11.9=hddfb980_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py311h8715677_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.11=4_cp311 - - pythran=0.15.0=py311hec5c23b_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py311hec3470c_4 - - pyyaml=6.0.1=py311hcd402e7_1 - - pyzmq=26.0.3=py311hb8d4657_0 + - prompt-toolkit=3.0.48=pyha770c72_1 + - psutil=6.1.0=py311ha879c10_0 + - pthread-stubs=0.4=h86ecc28_1002 + - ptyprocess=0.7.0=pyhd8ed1ab_1 + - pure_eval=0.2.3=pyhd8ed1ab_1 + - pycparser=2.22=pyh29332c3_1 + - pygments=2.18.0=pyhd8ed1ab_1 + - pyparsing=3.2.0=pyhd8ed1ab_2 + - pyproject-metadata=0.9.0=pyhd8ed1ab_1 + - pyside6=6.8.1=py311habb2604_0 + - pysocks=1.7.1=pyha55dd90_7 + - pytest=8.3.4=pyhd8ed1ab_1 + - pytest-xdist=3.6.1=pyhd8ed1ab_1 + - python=3.11.11=h1683364_1_cpython + - python-dateutil=2.9.0.post0=pyhff2d567_1 + - python-lrcalc=2.1=py311h89d996e_7 + - python_abi=3.11=5_cp311 + - pytz=2024.2=pyhd8ed1ab_1 + - pyzmq=26.2.0=py311h826da9f_3 - qd=2.3.22=h05efe27_1004 - - qhull=2020.2=hd62202e_2 - - r-base=4.3.3=h7f20121_3 - - r-lattice=0.22_6=r43h25e906a_0 + - qhull=2020.2=h70be974_5 + - qt6-main=6.8.1=h0d3cc05_0 - readline=8.2=h8fc344f_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h31becfc_0 - - rpds-py=0.18.1=py311h949f54a_0 - - rpy2=3.5.11=py311r43hf13da56_3 + - requests=2.32.3=pyhd8ed1ab_1 - rw=0.9=h31becfc_2 - - sagemath-db-combinatorial-designs=20140630=1 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.3=py311h69ead2a_1 - - sed=4.8=ha0d5d3d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hbe76a8a_1 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 + - scipy=1.14.1=py311h5912639_2 + - setuptools=75.6.0=pyhff2d567_1 + - singular=4.4.0=hee12f27_1 + - six=1.17.0=pyhd8ed1ab_0 - snowballstemmer=2.2.0=pyhd8ed1ab_0 - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=hdc7ab3c_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=h3944111_1 + - sphinx=8.1.3=pyhd8ed1ab_1 + - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_2 + - sphinx-inline-tabs=2023.4.21=pyhd8ed1ab_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_1 + - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 + - sqlite=3.47.2=h578a6b9_0 + - stack_data=0.6.3=pyhd8ed1ab_1 - symmetrica=3.0.1=hd600fc2_0 - sympow=2.023.6=h157afb5_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-aarch64=2.17=h5b4a56d_14 + - sympy=1.13.3=pyh2585a3b_104 + - sysroot_linux-aarch64=2.17=h5b4a56d_18 - tachyon=0.99b6=ha0bfc61_1002 - - tar=1.34=h048efde_0 - - tbb=2021.12.0=h70be974_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h17f021e_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - tk=8.6.13=h194ca79_0 - - tktable=2.10=h52f7bd3_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py311h323e239_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py311hec3470c_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-fixesproto=5.0=h3557bc0_1002 - - xorg-inputproto=2.3.2=h3557bc0_1002 - - xorg-kbproto=1.0.7=h3557bc0_1002 - - xorg-libice=1.1.1=h7935292_0 - - xorg-libsm=1.2.4=h5a01bc2_0 - - xorg-libx11=1.8.9=h08be655_1 - - xorg-libxau=1.0.11=h31becfc_0 - - xorg-libxdmcp=1.1.3=h3557bc0_0 - - xorg-libxext=1.3.4=h2a766a3_2 - - xorg-libxfixes=5.0.3=h3557bc0_1004 - - xorg-libxi=1.7.10=h3557bc0_0 - - xorg-libxrender=0.9.11=h7935292_0 - - xorg-libxt=1.3.0=h7935292_1 - - xorg-libxtst=1.2.3=hf897c2e_1002 - - xorg-recordproto=1.14.2=hf897c2e_1002 - - xorg-renderproto=0.11.1=h3557bc0_1002 - - xorg-xextproto=7.3.0=h2a766a3_1003 - - xorg-xproto=7.0.31=h3557bc0_1007 - - xz=5.2.6=h9cdd2b7_0 - - yaml=0.2.5=hf897c2e_2 - - zeromq=4.3.5=h28faeed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h68df207_1 + - tomli=2.2.1=pyhd8ed1ab_1 + - tornado=6.4.2=py311h5487e9b_0 + - traitlets=5.14.3=pyhd8ed1ab_1 + - typing_extensions=4.12.2=pyha770c72_1 + - tzdata=2024b=hc8b5060_0 + - unicodedata2=15.1.0=py311ha879c10_1 + - urllib3=2.2.3=pyhd8ed1ab_1 + - wayland=1.23.1=h698ed42_0 + - wcwidth=0.2.13=pyhd8ed1ab_1 + - wheel=0.45.1=pyhd8ed1ab_1 + - widgetsnbextension=4.0.13=pyhd8ed1ab_1 + - xcb-util=0.4.1=h5c728e9_2 + - xcb-util-cursor=0.1.5=h86ecc28_0 + - xcb-util-image=0.4.0=h5c728e9_2 + - xcb-util-keysyms=0.4.1=h5c728e9_0 + - xcb-util-renderutil=0.3.10=h5c728e9_0 + - xcb-util-wm=0.4.2=h5c728e9_0 + - xkeyboard-config=2.43=h86ecc28_0 + - xorg-libice=1.1.2=h86ecc28_0 + - xorg-libsm=1.2.5=h0808dbd_0 + - xorg-libx11=1.8.10=hca56bd8_1 + - xorg-libxau=1.0.12=h86ecc28_0 + - xorg-libxcomposite=0.4.6=h86ecc28_2 + - xorg-libxcursor=1.2.3=h86ecc28_0 + - xorg-libxdamage=1.1.6=h86ecc28_0 + - xorg-libxdmcp=1.1.5=h57736b2_0 + - xorg-libxext=1.3.6=h57736b2_0 + - xorg-libxfixes=6.0.1=h57736b2_0 + - xorg-libxi=1.8.2=h57736b2_0 + - xorg-libxrandr=1.5.4=h86ecc28_0 + - xorg-libxrender=0.9.12=h86ecc28_0 + - xorg-libxtst=1.2.5=h57736b2_3 + - xorg-libxxf86vm=1.1.6=h86ecc28_0 + - xz=5.6.3=h2dbfc1b_1 + - xz-gpl-tools=5.6.3=h2dbfc1b_1 + - xz-tools=5.6.3=h86ecc28_1 + - zeromq=4.3.5=h5efb499_7 + - zipp=3.21.0=pyhd8ed1ab_1 + - zlib=1.3.1=h86ecc28_2 + - zstandard=0.23.0=py311hd5293d8_1 - zstd=1.5.6=h02f22dd_0 diff --git a/environment-3.11-linux.yml b/environment-3.11-linux.yml index e169439f85d..2d99c14d61c 100644 --- a/environment-3.11-linux.yml +++ b/environment-3.11-linux.yml @@ -1,483 +1,339 @@ -name: sage +name: sage-dev # Generated by conda-lock. # platform: linux-64 -# input_hash: 042b3b9a5ce5e44ed6334284078d156e424e41f02852c8c6a155cb9b4e620e60 +# input_hash: 71d6929e3ba448868bcdf30d6cb1d190d88758e7272df5cf428554adbbf0ff6a channels: - conda-forge dependencies: - _libgcc_mutex=0.1=conda_forge - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.12=h4ab18f5_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py311h459d7ec_4 + - alabaster=1.0.0=pyhd8ed1ab_1 + - alsa-lib=1.2.13=hb9d3cd8_0 - arpack=3.9.1=nompi_h77f6705_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attr=2.5.1=h166bdaf_1 - - attrs=23.2.0=pyh71513ae_0 + - asttokens=3.0.0=pyhd8ed1ab_1 - autoconf=2.71=pl5321h2b4cb7a_1 - - automake=1.16.5=pl5321ha770c72_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=h7f98852_0 + - automake=1.17=pl5321ha770c72_0 + - babel=2.16.0=pyhd8ed1ab_1 - bdw-gc=8.0.6=h4bd325d_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=h4852527_7 - - binutils_impl_linux-64=2.40=ha1999f0_7 - - binutils_linux-64=2.40=hb3c18ed_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linux64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h44aadfe_2 + - beautifulsoup4=4.12.3=pyha770c72_1 + - binutils=2.43=h4852527_2 + - binutils_impl_linux-64=2.43=h4bf12b8_2 + - binutils_linux-64=2.43=h4852527_2 + - blas=2.126=openblas + - blas-devel=3.9.0=26_linux64_openblas + - boost-cpp=1.85.0=h3c6214e_4 - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hd590300_1 - - brotli-bin=1.1.0=hd590300_1 - - brotli-python=1.1.0=py311hb755f60_1 - - bwidget=1.9.14=ha770c72_1 - - bzip2=1.0.8=hd590300_5 - - c-ares=1.28.1=hd590300_0 - - c-compiler=1.7.0=hd590300_1 - - ca-certificates=2024.6.2=hbcca054_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=hbb29018_2 + - brotli=1.1.0=hb9d3cd8_2 + - brotli-bin=1.1.0=hb9d3cd8_2 + - brotli-python=1.1.0=py311hfdbb021_2 + - bzip2=1.0.8=h4bc722e_7 + - c-ares=1.34.4=hb9d3cd8_0 + - c-compiler=1.8.0=h2b85faf_1 + - ca-certificates=2024.12.14=hbcca054_0 + - cairo=1.18.2=h3394656_1 - cddlib=1!0.94m=h9202a9a_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py311hb3a22ac_0 - - chardet=5.2.0=py311h38be061_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 + - certifi=2024.12.14=pyhd8ed1ab_0 + - cffi=1.17.1=py311hf29c0ef_0 + - charset-normalizer=3.4.0=pyhd8ed1ab_1 - cliquer=1.22=hd590300_1 - - cmake=3.29.6=hcafd917_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py311h38be061_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=ha770c72_1 - - contourpy=1.2.1=py311h9547e67_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=he654da7_0 - - cvxopt=1.3.2=py311hec6cc1f_2 - - cxx-compiler=1.7.0=h00ab1b0_1 - - cycler=0.12.1=pyhd8ed1ab_0 + - colorama=0.4.6=pyhd8ed1ab_1 + - comm=0.2.2=pyhd8ed1ab_1 + - contourpy=1.3.1=py311hd18a35c_0 + - conway-polynomials=0.10=pyhd8ed1ab_0 + - coverage=7.6.9=py311h2dc5d0c_0 + - cpython=3.11.11=py311hd8ed1ab_1 + - cxx-compiler=1.8.0=h1a2810e_1 + - cycler=0.12.1=pyhd8ed1ab_1 - cypari2=2.1.5=py311hd2352ae_0 + - cyrus-sasl=2.1.27=h54b06d7_7 - cysignals=1.11.2=py311h82528dc_3 - - cython=3.0.10=py311hb755f60_0 + - cython=3.0.11=py311h55d416d_3 - dbus=1.13.6=h5008d03_3 - - debugpy=1.8.1=py311hb755f60_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hd9d9efa_1203 - - ecl=23.9.9=hed6455c_0 - - eclib=20231212=h96f522a_0 + - debugpy=1.8.11=py311hfdbb021_0 + - decorator=5.1.1=pyhd8ed1ab_1 + - docutils=0.21.2=pyhd8ed1ab_1 + - double-conversion=3.3.0=h59595ed_0 + - ecl=24.5.10=h0f3afd4_0 + - eclib=20231212=h43e5eba_1 - ecm=7.0.5=h9458935_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h59595ed_0 + - exceptiongroup=1.2.2=pyhd8ed1ab_1 + - execnet=2.1.1=pyhd8ed1ab_1 + - executing=2.1.0=pyhd8ed1ab_1 + - expat=2.6.4=h5888daf_0 - fflas-ffpack=2.5.0=h4f9960b_0 - - fftw=3.3.10=nompi_hf1063bd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - font-ttf-inconsolata=3.000=h77eed37_0 - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h14ed4e7_0 + - font-ttf-ubuntu=0.83=h77eed37_3 + - fontconfig=2.15.0=h7e30c49_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.53.0=py311h331c9d8_0 - - fortran-compiler=1.7.0=heb67821_1 + - fonttools=4.55.3=py311h2dc5d0c_0 + - fortran-compiler=1.8.0=h36df796_1 - fplll=5.4.5=h384768b_0 - fpylll=0.6.1=py311hcfae7cf_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - freetype=2.12.1=h267a509_2 - - fribidi=1.0.10=h36c2ea0_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he9a28a4_3 - - gap-defaults=4.12.2=ha770c72_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=h915e2ae_13 - - gcc_impl_linux-64=12.3.0=h58ffeeb_13 - - gcc_linux-64=12.3.0=h9528a6a_9 - - gengetopt=2.23=h9c3ff4c_0 - - gettext=0.22.5=h59595ed_2 - - gettext-tools=0.22.5=h59595ed_2 - - gf2x=1.3.0=ha476b99_2 + - furo=2024.8.6=pyhd8ed1ab_1 + - gap-core=4.14.0=h3b03731_1 + - gap-defaults=4.14.0=ha770c72_1 + - gcc=13.3.0=h9576a4e_1 + - gcc_impl_linux-64=13.3.0=hfea6d02_1 + - gcc_linux-64=13.3.0=hc28eda2_7 + - gf2x=1.3.0=h55551d5_3 - gfan=0.6.2=hb86e20a_1003 - - gfortran=12.3.0=h915e2ae_13 - - gfortran_impl_linux-64=12.3.0=h8f2110c_13 - - gfortran_linux-64=12.3.0=h5877db1_9 + - gfortran=13.3.0=h9576a4e_1 + - gfortran_impl_linux-64=13.3.0=h10434e7_1 + - gfortran_linux-64=13.3.0=hb919d3a_7 - giac=1.9.0.21=h673759e_1 - - giflib=5.2.2=hd590300_0 - givaro=4.2.0=hb789bce_0 - - glib=2.80.2=h8a4344b_1 - - glib-tools=2.80.2=h73ef956_1 - glpk=5.0=h445213a_0 - gmp=6.3.0=hac33072_2 - - gmpy2=2.1.5=py311hc4f1f91_1 + - gmpy2=2.1.5=py311h0f6cedb_3 - graphite2=1.3.13=h59595ed_1003 - gsl=2.7=he838d99_0 - - gst-plugins-base=1.24.5=hbaaba92_0 - - gstreamer=1.24.5=haf2f30d_0 - - gxx=12.3.0=h915e2ae_13 - - gxx_impl_linux-64=12.3.0=h2a574ab_13 - - gxx_linux-64=12.3.0=ha28b414_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=hfac3d4d_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h59595ed_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hef0740d_1 + - gxx=13.3.0=h9576a4e_1 + - gxx_impl_linux-64=13.3.0=hdbfa832_1 + - gxx_linux-64=13.3.0=h6834431_7 + - h2=4.1.0=pyhd8ed1ab_1 + - harfbuzz=9.0.0=hda332d3_1 + - hpack=4.0.0=pyhd8ed1ab_1 + - hyperframe=6.0.1=pyhd8ed1ab_1 + - icu=75.1=he02047a_0 + - idna=3.10=pyhd8ed1ab_1 + - igraph=0.10.15=he44f51b_1 - imagesize=1.4.1=pyhd8ed1ab_0 - iml=1.0.5=h623f65a_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=ha770c72_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py311h38be061_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py311h38be061_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-64=2.6.32=he073ed8_17 + - importlib-metadata=8.5.0=pyha770c72_1 + - iniconfig=2.0.0=pyhd8ed1ab_1 + - ipykernel=6.29.5=pyh3099207_0 + - ipython=8.30.0=pyh707e725_0 + - ipywidgets=8.1.5=pyhd8ed1ab_1 + - jedi=0.19.2=pyhd8ed1ab_1 + - jinja2=3.1.4=pyhd8ed1ab_1 + - jupyter_client=8.6.3=pyhd8ed1ab_1 + - jupyter_core=5.7.2=pyh31011fe_1 + - jupyterlab_widgets=3.0.13=pyhd8ed1ab_1 + - kernel-headers_linux-64=3.10.0=he073ed8_18 - keyutils=1.6.1=h166bdaf_0 - - kiwisolver=1.4.5=py311h9547e67_1 - - krb5=1.21.2=h659d440_0 - - lame=3.100=h166bdaf_1003 + - kiwisolver=1.4.7=py311hd18a35c_0 + - krb5=1.21.3=h659f571_0 - lcalc=2.0.5=h5aac1b6_2 - lcms2=2.16=hb7c19ff_0 - - ld_impl_linux-64=2.40=hf3520f5_7 + - ld_impl_linux-64=2.43=h712a8e2_2 - lerc=4.0.0=h27087fc_0 - - libasprintf=0.22.5=h661eb56_2 - - libasprintf-devel=0.22.5=h661eb56_2 - - libatomic_ops=7.6.14=h166bdaf_0 - - libblas=3.9.0=20_linux64_openblas - - libboost=1.85.0=hba137d9_2 - - libboost-devel=1.85.0=h00ab1b0_2 - - libboost-headers=1.85.0=ha770c72_2 - - libbraiding=1.2=hcb278e6_0 + - libblas=3.9.0=26_linux64_openblas + - libboost=1.85.0=h0ccab89_4 + - libboost-devel=1.85.0=h00ab1b0_4 + - libboost-headers=1.85.0=ha770c72_4 + - libbraiding=1.3=h5888daf_0 - libbrial=1.2.12=h76af697_3 - - libbrotlicommon=1.1.0=hd590300_1 - - libbrotlidec=1.1.0=hd590300_1 - - libbrotlienc=1.1.0=hd590300_1 - - libcap=2.69=h0f662aa_0 - - libcblas=3.9.0=20_linux64_openblas - - libclang-cpp15=15.0.7=default_h127d8a8_5 - - libclang13=18.1.8=default_h6ae225f_0 + - libbrotlicommon=1.1.0=hb9d3cd8_2 + - libbrotlidec=1.1.0=hb9d3cd8_2 + - libbrotlienc=1.1.0=hb9d3cd8_2 + - libcblas=3.9.0=26_linux64_openblas + - libclang-cpp19.1=19.1.6=default_hb5137d0_0 + - libclang13=19.1.6=default_h9c6a7e4_0 - libcups=2.3.3=h4637d8d_4 - - libcurl=8.8.0=hca28451_0 - - libdeflate=1.20=hd590300_0 + - libcurl=8.11.1=h332b0f4_0 + - libdeflate=1.23=h4ddbbb0_0 + - libdrm=2.4.124=hb9d3cd8_0 - libedit=3.1.20191231=he28a2e2_2 + - libegl=1.7.0=ha4b6fd6_2 - libev=4.33=hd590300_2 - - libevent=2.1.12=hf998b51_1 - - libexpat=2.6.2=h59595ed_0 + - libexpat=2.6.4=h5888daf_0 - libffi=3.4.2=h7f98852_5 - - libflac=1.4.3=h59595ed_0 - - libflint=3.0.1=h5f2e117_ntl_100 - - libgcc-devel_linux-64=12.3.0=h6b66f73_113 - - libgcc-ng=13.2.0=h77fa898_13 - - libgcrypt=1.10.3=hd590300_0 - - libgd=2.3.3=h119a65a_9 - - libgettextpo=0.22.5=h59595ed_2 - - libgettextpo-devel=0.22.5=h59595ed_2 - - libgfortran-ng=13.2.0=h69a702a_13 - - libgfortran5=13.2.0=h3d2ce59_13 - - libglib=2.80.2=h8a4344b_1 - - libgomp=13.2.0=h77fa898_13 - - libgpg-error=1.49=h4f305b6_0 + - libflint=3.1.2=h6fb9888_101 + - libgcc=14.2.0=h77fa898_1 + - libgcc-devel_linux-64=13.3.0=h84ea5a7_101 + - libgcc-ng=14.2.0=h69a702a_1 + - libgd=2.3.3=hd3e95f3_10 + - libgfortran=14.2.0=h69a702a_1 + - libgfortran-ng=14.2.0=h69a702a_1 + - libgfortran5=14.2.0=hd5240d6_1 + - libgl=1.7.0=ha4b6fd6_2 + - libglib=2.82.2=h2ff4ddf_0 + - libglvnd=1.7.0=ha4b6fd6_2 + - libglx=1.7.0=ha4b6fd6_2 + - libgomp=14.2.0=h77fa898_1 - libhomfly=1.02r6=hd590300_1 - - libhwloc=2.10.0=default_h5622ce7_1001 - libiconv=1.17=hd590300_2 - libjpeg-turbo=3.0.0=hd590300_1 - - liblapack=3.9.0=20_linux64_openblas - - liblapacke=3.9.0=20_linux64_openblas - - libllvm15=15.0.7=hb3ce162_4 - - libllvm18=18.1.8=hc9dba70_0 - - libnghttp2=1.58.0=h47da74e_1 + - liblapack=3.9.0=26_linux64_openblas + - liblapacke=3.9.0=26_linux64_openblas + - libllvm19=19.1.6=ha7bfdaf_0 + - liblzma=5.6.3=hb9d3cd8_1 + - liblzma-devel=5.6.3=hb9d3cd8_1 + - libnghttp2=1.64.0=h161d5f1_0 - libnsl=2.0.1=hd590300_0 - - libogg=1.3.5=h4ab18f5_0 - - libopenblas=0.3.25=pthreads_h413a1c8_0 - - libopus=1.3.1=h7f98852_1 - - libpng=1.6.43=h2797004_0 - - libpq=16.3=ha72fbe1_0 - - libsanitizer=12.3.0=hb8811af_13 - - libsndfile=1.2.2=hc60ed4a_1 - - libsodium=1.0.18=h36c2ea0_1 - - libsqlite=3.46.0=hde9e2c9_0 - - libssh2=1.11.0=h0841786_0 - - libstdcxx-devel_linux-64=12.3.0=h6b66f73_113 - - libstdcxx-ng=13.2.0=hc0a3c3a_13 - - libsystemd0=255=h3516f8a_1 - - libtiff=4.6.0=h1dd3fc0_3 - - libtool=2.4.7=h27087fc_0 + - libntlm=1.4=h7f98852_1002 + - libopenblas=0.3.28=pthreads_h94d23a6_1 + - libopengl=1.7.0=ha4b6fd6_2 + - libpciaccess=0.18=hd590300_0 + - libpng=1.6.44=hadc24fc_0 + - libpq=17.2=h3b95a9b_1 + - libsanitizer=13.3.0=heb74ff8_1 + - libsodium=1.0.20=h4ab18f5_0 + - libsqlite=3.47.2=hee588c1_0 + - libssh2=1.11.1=hf672d98_0 + - libstdcxx=14.2.0=hc0a3c3a_1 + - libstdcxx-devel_linux-64=13.3.0=h84ea5a7_101 + - libstdcxx-ng=14.2.0=h4852527_1 + - libtiff=4.7.0=hd9ff511_3 - libuuid=2.38.1=h0b41bf4_0 - - libuv=1.48.0=hd590300_0 - - libvorbis=1.3.7=h9c3ff4c_0 - - libwebp=1.4.0=h2c329e2_0 - libwebp-base=1.4.0=hd590300_0 - - libxcb=1.16=hd590300_0 + - libxcb=1.17.0=h8a09558_0 - libxcrypt=4.4.36=hd590300_1 - libxkbcommon=1.7.0=h2c5496b_1 - - libxml2=2.12.7=hc051c1a_1 - - libzlib=1.3.1=h4ab18f5_1 - - linbox=1.7.0=ha329b40_0 - - llvm-openmp=18.1.8=hf5423f3_0 - - lrcalc=2.1=h59595ed_6 - - lz4-c=1.9.4=hcb278e6_0 + - libxml2=2.13.5=h8d12d68_1 + - libxslt=1.1.39=h76b75d6_0 + - libzlib=1.3.1=hb9d3cd8_2 + - linbox=1.7.0=h7298d08_1 + - llvm-openmp=19.1.6=h024ca30_0 + - lrcalc=2.1=h5888daf_7 - m4=1.4.18=h516909a_1001 - m4ri=20140914=hae5d5c5_1006 - - m4rie=20150908=h267a509_1002 - - make=4.3=hd18ef5c_1 - - markupsafe=2.1.5=py311h459d7ec_0 - - mathjax=3.2.2=ha770c72_0 - - matplotlib=3.8.4=py311h38be061_2 - - matplotlib-base=3.8.4=py311ha4ca890_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=hed6455c_2 - - memory-allocator=0.1.3=py311h459d7ec_0 - - metis=5.1.0=h59595ed_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=hfe3b2da_0 + - m4rie=20200125=h051dbe0_0 + - markupsafe=3.0.2=py311h2dc5d0c_1 + - matplotlib=3.10.0=py311h38be061_0 + - matplotlib-base=3.10.0=py311h2b939e6_0 + - matplotlib-inline=0.1.7=pyhd8ed1ab_1 + - maxima=5.47.0=h75482ee_3 + - memory-allocator=0.1.3=py311h9ecbd09_1 + - meson=1.6.1=pyhd8ed1ab_0 + - meson-python=0.17.1=pyh70fd9c4_1 + - mpc=1.3.1=h24ddda3_1 - mpfi=1.5.4=h9f54685_1001 - - mpfr=4.2.1=h9458935_1 - - mpg123=1.32.6=h59595ed_0 - - mpmath=1.3.0=pyhd8ed1ab_0 + - mpfr=4.2.1=h90cbb55_3 + - mpmath=1.3.0=pyhd8ed1ab_1 - munkres=1.1.4=pyh9f0ad1d_0 - - mysql-common=8.3.0=hf1915f5_4 - - mysql-libs=8.3.0=hca2cd23_4 + - mysql-common=9.0.1=h266115a_3 + - mysql-libs=9.0.1=he0572af_3 - nauty=2.8.8=hd590300_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h59595ed_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 + - ncurses=6.5=he02047a_1 + - nest-asyncio=1.6.0=pyhd8ed1ab_1 + - networkx=3.4.2=pyh267e887_2 - ninja=1.12.1=h297d8ca_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - nspr=4.35=h27087fc_0 - - nss=3.101=h593d115_0 - ntl=11.4.3=hef3c4d3_1 - numpy=1.26.4=py311h64a7726_0 - - openblas=0.3.25=pthreads_h7a3da1a_0 - - openjdk=21.0.2=haa376d0_0 - - openjpeg=2.5.2=h488ebb8_0 - - openssl=3.3.1=h4ab18f5_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 + - openblas=0.3.28=pthreads_h6ec200e_1 + - openjpeg=2.5.3=h5fbd93e_0 + - openldap=2.6.9=he970967_0 + - openssl=3.4.0=hb9d3cd8_0 + - packaging=24.2=pyhd8ed1ab_2 - palp=2.20=h36c2ea0_0 - - pandoc=3.2.1=ha770c72_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h84a9a3c_0 - pari=2.15.5=h4d4ae9b_2_pthread - pari-elldata=0.0.20161017=0 - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - pari-seadata=0.0.20090618=0 - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=h7f98852_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h0f59acf_0 - - pep517=0.13.0=pyhd8ed1ab_0 + - parso=0.8.4=pyhd8ed1ab_1 + - pcre2=10.44=hba22ea6_2 - perl=5.32.1=7_hd590300_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py311h82a398c_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.2=h59595ed_0 - - pkg-config=0.29.2=h36c2ea0_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 + - pexpect=4.9.0=pyhd8ed1ab_1 + - pickleshare=0.7.5=pyhd8ed1ab_1004 + - pillow=11.0.0=py311h49e9ac3_0 + - pip=24.3.1=pyh8b19718_2 + - pixman=0.44.2=h29eaf8c_0 + - pkg-config=0.29.2=h4bc722e_1009 + - pkgconfig=1.5.5=pyhd8ed1ab_5 - planarity=3.0.2.0=hd590300_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 + - platformdirs=4.3.6=pyhd8ed1ab_1 + - pluggy=1.5.0=pyhd8ed1ab_1 - ppl=1.2=h6ec01c2_1006 - pplpy=0.8.9=py311ha9f9f00_1 - primecount=7.9=hcb278e6_0 - primecountpy=0.1.0=py311h9547e67_4 - primesieve=11.1=h59595ed_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py311h331c9d8_0 - - pthread-stubs=0.4=h36c2ea0_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pulseaudio-client=17.0=hb77b528_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py311h9547e67_0 - - pybind11-global=2.12.0=py311h9547e67_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyqt=5.15.9=py311hf0fb5b6_5 - - pyqt5-sip=12.12.2=py311hb755f60_5 - - pyrsistent=0.20.0=py311h459d7ec_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.11.9=hb806964_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py311hb755f60_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.11=4_cp311 - - pythran=0.15.0=py311h92ebd52_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py311h38be061_4 - - pyyaml=6.0.1=py311h459d7ec_1 - - pyzmq=26.0.3=py311h08a0b41_0 + - prompt-toolkit=3.0.48=pyha770c72_1 + - psutil=6.1.0=py311h9ecbd09_0 + - pthread-stubs=0.4=hb9d3cd8_1002 + - ptyprocess=0.7.0=pyhd8ed1ab_1 + - pure_eval=0.2.3=pyhd8ed1ab_1 + - pycparser=2.22=pyh29332c3_1 + - pygments=2.18.0=pyhd8ed1ab_1 + - pyparsing=3.2.0=pyhd8ed1ab_2 + - pyproject-metadata=0.9.0=pyhd8ed1ab_1 + - pyside6=6.8.1=py311h9053184_0 + - pysocks=1.7.1=pyha55dd90_7 + - pytest=8.3.4=pyhd8ed1ab_1 + - pytest-xdist=3.6.1=pyhd8ed1ab_1 + - python=3.11.11=h9e4cc4f_1_cpython + - python-dateutil=2.9.0.post0=pyhff2d567_1 + - python-lrcalc=2.1=py311hfdbb021_7 + - python_abi=3.11=5_cp311 + - pytz=2024.2=pyhd8ed1ab_1 + - pyzmq=26.2.0=py311h7deb3e3_3 - qd=2.3.22=h2cc385e_1004 - - qhull=2020.2=h4bd325d_2 - - qt-main=5.15.8=ha2b5568_22 - - r-base=4.3.3=he2d9a6e_3 - - r-lattice=0.22_6=r43h57805ef_0 + - qhull=2020.2=h434a139_5 + - qt6-main=6.8.1=h9d28a51_0 - readline=8.2=h8228510_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hd590300_0 - - rpds-py=0.18.1=py311h5ecf98a_0 - - rpy2=3.5.11=py311r43h1f0f07a_3 + - requests=2.32.3=pyhd8ed1ab_1 - rw=0.9=hd590300_2 - - sagemath-db-combinatorial-designs=20140630=1 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py311h64a7726_0 - - sed=4.8=he412f7d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h33f5c3f_1 - - sip=6.7.12=py311hb755f60_0 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 + - scipy=1.14.1=py311he9a78e4_2 + - setuptools=75.6.0=pyhff2d567_1 + - singular=4.4.0=hc910cb2_1 + - six=1.17.0=pyhd8ed1ab_0 - snowballstemmer=2.2.0=pyhd8ed1ab_0 - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h6d4b2fc_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf4753ba_1 + - sphinx=8.1.3=pyhd8ed1ab_1 + - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_2 + - sphinx-inline-tabs=2023.4.21=pyhd8ed1ab_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_1 + - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 + - sqlite=3.47.2=h9eae976_0 + - stack_data=0.6.3=pyhd8ed1ab_1 - symmetrica=3.0.1=hcb278e6_0 - sympow=2.023.6=hc6ab17c_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-64=2.12=he073ed8_17 + - sympy=1.13.3=pyh2585a3b_104 + - sysroot_linux-64=2.17=h4a8ded7_18 - tachyon=0.99b6=hba7d16a_1002 - - tar=1.34=hb2e2bae_1 - - tbb=2021.12.0=h297d8ca_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h0f457ee_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - tk=8.6.13=noxft_h4845f30_101 - - tktable=2.10=h8bc8fbc_6 - - toml=0.10.2=pyhd8ed1ab_0 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py311h331c9d8_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py311h38be061_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 + - tomli=2.2.1=pyhd8ed1ab_1 + - tornado=6.4.2=py311h9ecbd09_0 + - traitlets=5.14.3=pyhd8ed1ab_1 + - typing_extensions=4.12.2=pyha770c72_1 + - tzdata=2024b=hc8b5060_0 + - unicodedata2=15.1.0=py311h9ecbd09_1 + - urllib3=2.2.3=pyhd8ed1ab_1 + - wayland=1.23.1=h3e06ad9_0 + - wcwidth=0.2.13=pyhd8ed1ab_1 + - wheel=0.45.1=pyhd8ed1ab_1 + - widgetsnbextension=4.0.13=pyhd8ed1ab_1 - xcb-util=0.4.1=hb711507_2 + - xcb-util-cursor=0.1.5=hb9d3cd8_0 - xcb-util-image=0.4.0=hb711507_2 - xcb-util-keysyms=0.4.1=hb711507_0 - xcb-util-renderutil=0.3.10=hb711507_0 - xcb-util-wm=0.4.2=hb711507_0 - - xkeyboard-config=2.42=h4ab18f5_0 - - xorg-fixesproto=5.0=h7f98852_1002 - - xorg-inputproto=2.3.2=h7f98852_1002 - - xorg-kbproto=1.0.7=h7f98852_1002 - - xorg-libice=1.1.1=hd590300_0 - - xorg-libsm=1.2.4=h7391055_0 - - xorg-libx11=1.8.9=hb711507_1 - - xorg-libxau=1.0.11=hd590300_0 - - xorg-libxdmcp=1.1.3=h7f98852_0 - - xorg-libxext=1.3.4=h0b41bf4_2 - - xorg-libxfixes=5.0.3=h7f98852_1004 - - xorg-libxi=1.7.10=h7f98852_0 - - xorg-libxrender=0.9.11=hd590300_0 - - xorg-libxt=1.3.0=hd590300_1 - - xorg-libxtst=1.2.3=h7f98852_1002 - - xorg-recordproto=1.14.2=h7f98852_1002 - - xorg-renderproto=0.11.1=h7f98852_1002 - - xorg-xextproto=7.3.0=h0b41bf4_1003 - - xorg-xf86vidmodeproto=2.3.1=h7f98852_1002 - - xorg-xproto=7.0.31=h7f98852_1007 - - xz=5.2.6=h166bdaf_0 - - yaml=0.2.5=h7f98852_2 - - zeromq=4.3.5=h75354e8_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h4ab18f5_1 + - xkeyboard-config=2.43=hb9d3cd8_0 + - xorg-libice=1.1.2=hb9d3cd8_0 + - xorg-libsm=1.2.5=he73a12e_0 + - xorg-libx11=1.8.10=h4f16b4b_1 + - xorg-libxau=1.0.12=hb9d3cd8_0 + - xorg-libxcomposite=0.4.6=hb9d3cd8_2 + - xorg-libxcursor=1.2.3=hb9d3cd8_0 + - xorg-libxdamage=1.1.6=hb9d3cd8_0 + - xorg-libxdmcp=1.1.5=hb9d3cd8_0 + - xorg-libxext=1.3.6=hb9d3cd8_0 + - xorg-libxfixes=6.0.1=hb9d3cd8_0 + - xorg-libxi=1.8.2=hb9d3cd8_0 + - xorg-libxrandr=1.5.4=hb9d3cd8_0 + - xorg-libxrender=0.9.12=hb9d3cd8_0 + - xorg-libxtst=1.2.5=hb9d3cd8_3 + - xorg-libxxf86vm=1.1.6=hb9d3cd8_0 + - xz=5.6.3=hbcc6ac9_1 + - xz-gpl-tools=5.6.3=hbcc6ac9_1 + - xz-tools=5.6.3=hb9d3cd8_1 + - zeromq=4.3.5=h3b0a872_7 + - zipp=3.21.0=pyhd8ed1ab_1 + - zlib=1.3.1=hb9d3cd8_2 + - zstandard=0.23.0=py311hbc35293_1 - zstd=1.5.6=ha6fb4c9_0 diff --git a/environment-3.11-macos-x86_64.yml b/environment-3.11-macos-x86_64.yml index ddfef2df9d4..fb34c25a567 100644 --- a/environment-3.11-macos-x86_64.yml +++ b/environment-3.11-macos-x86_64.yml @@ -1,423 +1,292 @@ -name: sage +name: sage-dev # Generated by conda-lock. # platform: osx-64 -# input_hash: 2d3e06919a9241aca6e25ca728e3013423030e7220d74f404ad621f0ad0ff5bd +# input_hash: 58971dc791eb5f5f7e12b0e44db07ecd9b2fc48def89f671effaabd2bd0720d6 channels: - conda-forge dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py311h2725bcf_4 + - alabaster=1.0.0=pyhd8ed1ab_1 + - appnope=0.1.4=pyhd8ed1ab_1 - arpack=3.9.1=nompi_hf81eadf_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 + - asttokens=3.0.0=pyhd8ed1ab_1 - autoconf=2.71=pl5321hed12c24_1 - - automake=1.16.5=pl5321h694c41f_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=h0d85af4_0 + - automake=1.17=pl5321h694c41f_0 + - babel=2.16.0=pyhd8ed1ab_1 - bdw-gc=8.0.6=h940c156_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osx64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h07eb623_2 + - beautifulsoup4=4.12.3=pyha770c72_1 + - blas=2.126=openblas + - blas-devel=3.9.0=26_osx64_openblas + - boost-cpp=1.85.0=hfcd56d9_4 - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h0dc2134_1 - - brotli-bin=1.1.0=h0dc2134_1 - - brotli-python=1.1.0=py311hdf8f085_1 - - bwidget=1.9.14=h694c41f_1 - - bzip2=1.0.8=h10d778d_5 - - c-ares=1.28.1=h10d778d_0 - - c-compiler=1.7.0=h282daa2_1 - - ca-certificates=2024.6.2=h8857fd0_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=h9f650ed_2 - - cctools=986=h40f6528_0 - - cctools_osx-64=986=ha1c5b94_0 + - brotli=1.1.0=h00291cd_2 + - brotli-bin=1.1.0=h00291cd_2 + - brotli-python=1.1.0=py311hd89902b_2 + - bzip2=1.0.8=hfdf4475_7 + - c-ares=1.34.4=hf13058a_0 + - c-compiler=1.8.0=hfc4bf79_1 + - ca-certificates=2024.12.14=h8857fd0_0 + - cctools=1010.6=h5b2de21_2 + - cctools_osx-64=1010.6=hea4301f_2 - cddlib=1!0.94m=h0f52abe_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py311hc0b63fd_0 - - chardet=5.2.0=py311h6eed73b_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_ha3b9224_8 - - clang-16=16.0.6=default_h4c8afb6_8 - - clang_impl_osx-64=16.0.6=h8787910_16 - - clang_osx-64=16.0.6=hb91bd55_16 - - clangxx=16.0.6=default_ha3b9224_8 - - clangxx_impl_osx-64=16.0.6=h6d92fbe_16 - - clangxx_osx-64=16.0.6=hb91bd55_16 + - certifi=2024.12.14=pyhd8ed1ab_0 + - cffi=1.17.1=py311h137bacd_0 + - charset-normalizer=3.4.0=pyhd8ed1ab_1 + - clang=17.0.6=default_he371ed4_7 + - clang-17=17.0.6=default_hb173f14_7 + - clang_impl_osx-64=17.0.6=h1af8efd_23 + - clang_osx-64=17.0.6=h7e5c614_23 + - clangxx=17.0.6=default_he371ed4_7 + - clangxx_impl_osx-64=17.0.6=hc3430b7_23 + - clangxx_osx-64=17.0.6=h7e5c614_23 - cliquer=1.22=h10d778d_1 - - cmake=3.29.6=h749d262_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py311h6eed73b_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=ha38d28d_2 - - compiler-rt_osx-64=16.0.6=ha38d28d_2 - - compilers=1.7.0=h694c41f_1 - - contourpy=1.2.1=py311h1d816ee_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=hea67d85_0 - - cvxopt=1.3.2=py311he94735a_2 - - cxx-compiler=1.7.0=h7728843_1 - - cycler=0.12.1=pyhd8ed1ab_0 + - colorama=0.4.6=pyhd8ed1ab_1 + - comm=0.2.2=pyhd8ed1ab_1 + - compiler-rt=17.0.6=h1020d70_2 + - compiler-rt_osx-64=17.0.6=hf2b8a54_2 + - contourpy=1.3.1=py311h4e34fa0_0 + - conway-polynomials=0.10=pyhd8ed1ab_0 + - coverage=7.6.9=py311ha3cf9ac_0 + - cpython=3.11.11=py311hd8ed1ab_1 + - cxx-compiler=1.8.0=h385f146_1 + - cycler=0.12.1=pyhd8ed1ab_1 - cypari2=2.1.5=py311h4fde0ae_0 - cysignals=1.11.2=py311h8a58447_3 - - cython=3.0.10=py311hdd0406b_0 - - debugpy=1.8.1=py311hdd0406b_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h6e329d1_1203 - - ecl=23.9.9=h2b27fa8_0 - - eclib=20231212=h02435c3_0 + - cython=3.0.11=py311h4cb39f0_3 + - debugpy=1.8.11=py311hc356e98_0 + - decorator=5.1.1=pyhd8ed1ab_1 + - docutils=0.21.2=pyhd8ed1ab_1 + - ecl=24.5.10=h56bac16_0 + - eclib=20231212=h960c116_1 - ecm=7.0.5=h4f6b447_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h73e2aa4_0 + - exceptiongroup=1.2.2=pyhd8ed1ab_1 + - execnet=2.1.1=pyhd8ed1ab_1 + - executing=2.1.0=pyhd8ed1ab_1 + - expat=2.6.4=h240833e_0 - fflas-ffpack=2.5.0=h5898d61_0 - - fftw=3.3.10=nompi_h292e606_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - font-ttf-inconsolata=3.000=h77eed37_0 - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h5bb23bf_0 + - font-ttf-ubuntu=0.83=h77eed37_3 + - fontconfig=2.15.0=h37eeddb_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.53.0=py311h72ae277_0 - - fortran-compiler=1.7.0=h6c2ab21_1 + - fonttools=4.55.3=py311ha3cf9ac_0 + - fortran-compiler=1.8.0=h33d1f46_1 - fplll=5.4.5=hb7981ad_0 - fpylll=0.6.1=py311h85fbf69_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - freetype=2.12.1=h60636b9_2 - - fribidi=1.0.10=hbcb3906_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=hc16eb5f_3 - - gap-defaults=4.12.2=h694c41f_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=he49afe7_0 - - gettext=0.22.5=h5ff76d1_2 - - gettext-tools=0.22.5=h5ff76d1_2 - - gf2x=1.3.0=hb2a7efb_2 + - furo=2024.8.6=pyhd8ed1ab_1 + - gap-core=4.14.0=hb9686a1_1 + - gap-defaults=4.14.0=h694c41f_1 + - gettext=0.22.5=hdfe23c8_3 + - gettext-tools=0.22.5=hdfe23c8_3 + - gf2x=1.3.0=h35ac7d9_3 - gfan=0.6.2=hd793b56_1003 - - gfortran=12.3.0=h2c809b3_1 - - gfortran_impl_osx-64=12.3.0=hc328e78_3 - - gfortran_osx-64=12.3.0=h18f7dce_1 + - gfortran=13.2.0=h2c809b3_1 + - gfortran_impl_osx-64=13.2.0=h2bc304d_3 + - gfortran_osx-64=13.2.0=h18f7dce_1 - giac=1.9.0.21=h92f3f65_1 - - giflib=5.2.2=h10d778d_0 - givaro=4.2.0=h1b3d6f7_0 - glpk=5.0=h3cb5acd_0 - gmp=6.3.0=hf036a51_2 - - gmpy2=2.1.5=py311hab17429_1 - - graphite2=1.3.13=h73e2aa4_1003 + - gmpy2=2.1.5=py311h7945f45_3 - gsl=2.7=h93259b0_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h053f038_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hf5e326d_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hde4452d_1 + - h2=4.1.0=pyhd8ed1ab_1 + - hpack=4.0.0=pyhd8ed1ab_1 + - hyperframe=6.0.1=pyhd8ed1ab_1 + - icu=75.1=h120a0e1_0 + - idna=3.10=pyhd8ed1ab_1 + - igraph=0.10.15=h5479cbe_1 - imagesize=1.4.1=pyhd8ed1ab_0 - iml=1.0.5=h61918c1_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 + - importlib-metadata=8.5.0=pyha770c72_1 + - iniconfig=2.0.0=pyhd8ed1ab_1 + - ipykernel=6.29.5=pyh57ce528_0 + - ipython=8.30.0=pyh707e725_0 + - ipywidgets=8.1.5=pyhd8ed1ab_1 - isl=0.26=imath32_h2e86a7b_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.9=h694c41f_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py311h6eed73b_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py311h6eed73b_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kiwisolver=1.4.5=py311h5fe6e05_1 - - krb5=1.21.2=hb884880_0 + - jedi=0.19.2=pyhd8ed1ab_1 + - jinja2=3.1.4=pyhd8ed1ab_1 + - jupyter_client=8.6.3=pyhd8ed1ab_1 + - jupyter_core=5.7.2=pyh31011fe_1 + - jupyterlab_widgets=3.0.13=pyhd8ed1ab_1 + - kiwisolver=1.4.7=py311hf2f7c97_0 + - krb5=1.21.3=h37d8d59_0 - lcalc=2.0.5=h547a6ed_2 - lcms2=2.16=ha2f27b4_0 - - ld64=711=ha02d983_0 - - ld64_osx-64=711=ha20a434_0 + - ld64=951.9=h0a3eb4e_2 + - ld64_osx-64=951.9=h5ffbe8e_2 - lerc=4.0.0=hb486fe8_0 - - libasprintf=0.22.5=h5ff76d1_2 - - libasprintf-devel=0.22.5=h5ff76d1_2 - - libatomic_ops=7.6.14=hb7f2c08_0 - - libblas=3.9.0=20_osx64_openblas - - libboost=1.85.0=h739af76_2 - - libboost-devel=1.85.0=h2b186f8_2 - - libboost-headers=1.85.0=h694c41f_2 - - libbraiding=1.2=hf0c8a7f_0 + - libasprintf=0.22.5=hdfe23c8_3 + - libasprintf-devel=0.22.5=hdfe23c8_3 + - libblas=3.9.0=26_osx64_openblas + - libboost=1.85.0=hcca3243_4 + - libboost-devel=1.85.0=h2b186f8_4 + - libboost-headers=1.85.0=h694c41f_4 + - libbraiding=1.3=h240833e_0 - libbrial=1.2.12=h81e9653_3 - - libbrotlicommon=1.1.0=h0dc2134_1 - - libbrotlidec=1.1.0=h0dc2134_1 - - libbrotlienc=1.1.0=h0dc2134_1 - - libcblas=3.9.0=20_osx64_openblas - - libclang-cpp16=16.0.6=default_h4c8afb6_8 - - libcurl=8.8.0=hf9fcc65_0 - - libcxx=17.0.6=h88467a6_0 - - libdeflate=1.20=h49d49c5_0 + - libbrotlicommon=1.1.0=h00291cd_2 + - libbrotlidec=1.1.0=h00291cd_2 + - libbrotlienc=1.1.0=h00291cd_2 + - libcblas=3.9.0=26_osx64_openblas + - libclang-cpp17=17.0.6=default_hb173f14_7 + - libcurl=8.11.1=h5dec5d8_0 + - libcxx=19.1.6=hf95d169_1 + - libcxx-devel=17.0.6=h8f8a49f_6 + - libdeflate=1.23=he65b83e_0 - libedit=3.1.20191231=h0678c8f_2 - libev=4.33=h10d778d_2 - - libexpat=2.6.2=h73e2aa4_0 + - libexpat=2.6.4=h240833e_0 - libffi=3.4.2=h0d85af4_5 - - libflint=3.0.1=h5d15de0_ntl_100 - - libgd=2.3.3=h0dceb68_9 - - libgettextpo=0.22.5=h5ff76d1_2 - - libgettextpo-devel=0.22.5=h5ff76d1_2 + - libflint=3.1.2=h1d27844_101 + - libgd=2.3.3=h2e77e4f_10 + - libgettextpo=0.22.5=hdfe23c8_3 + - libgettextpo-devel=0.22.5=hdfe23c8_3 - libgfortran=5.0.0=13_2_0_h97931a8_3 - - libgfortran-devel_osx-64=12.3.0=h0b6f5ec_3 + - libgfortran-devel_osx-64=13.2.0=h80d4556_3 - libgfortran5=13.2.0=h2873a65_3 - - libglib=2.80.2=h736d271_1 - libhomfly=1.02r6=h10d778d_1 - - libhwloc=2.10.0=default_h456cccd_1001 - libiconv=1.17=hd75f5a5_2 - - libintl=0.22.5=h5ff76d1_2 - - libintl-devel=0.22.5=h5ff76d1_2 + - libintl=0.22.5=hdfe23c8_3 + - libintl-devel=0.22.5=hdfe23c8_3 - libjpeg-turbo=3.0.0=h0dc2134_1 - - liblapack=3.9.0=20_osx64_openblas - - liblapacke=3.9.0=20_osx64_openblas - - libllvm16=16.0.6=hbedff68_3 - - libnghttp2=1.58.0=h64cf6d3_1 - - libopenblas=0.3.25=openmp_hfef2a42_0 - - libpng=1.6.43=h92b6c6a_0 - - libsodium=1.0.18=hbcb3906_1 - - libsqlite=3.46.0=h1b8f9f3_0 - - libssh2=1.11.0=hd019ec5_0 - - libtiff=4.6.0=h129831d_3 - - libtool=2.4.7=hf0c8a7f_0 - - libuv=1.48.0=h67532ce_0 - - libwebp=1.4.0=hc207709_0 + - liblapack=3.9.0=26_osx64_openblas + - liblapacke=3.9.0=26_osx64_openblas + - libllvm17=17.0.6=hbedff68_1 + - liblzma=5.6.3=hd471939_1 + - liblzma-devel=5.6.3=hd471939_1 + - libnghttp2=1.64.0=hc7306c3_0 + - libopenblas=0.3.28=openmp_hbf64a52_1 + - libpng=1.6.44=h4b8f8c9_0 + - libsodium=1.0.20=hfdf4475_0 + - libsqlite=3.47.2=hdb6dae5_0 + - libssh2=1.11.1=h3dc7d44_0 + - libtiff=4.7.0=hb77a491_3 - libwebp-base=1.4.0=h10d778d_0 - - libxcb=1.16=h0dc2134_0 - - libxml2=2.12.7=h3e169fe_1 - - libzlib=1.3.1=h87427d6_1 - - linbox=1.7.0=h7061c92_0 - - llvm-openmp=18.1.8=h15ab845_0 - - llvm-tools=16.0.6=hbedff68_3 - - lrcalc=2.1=h73e2aa4_6 + - libxcb=1.17.0=hf1f96e2_0 + - libxml2=2.13.5=hebb159f_1 + - libzlib=1.3.1=hd23fc13_2 + - linbox=1.7.0=h9325161_1 + - llvm-openmp=19.1.6=ha54dae1_0 + - llvm-tools=17.0.6=hbedff68_1 + - lrcalc=2.1=hac325c4_7 - m4=1.4.18=haf1e3a3_1001 - m4ri=20140914=hd82a5f3_1006 - - m4rie=20150908=hc616cfc_1002 - - make=4.3=h22f3db7_1 - - markupsafe=2.1.5=py311he705e18_0 - - mathjax=3.2.2=h694c41f_0 - - matplotlib=3.8.4=py311h6eed73b_2 - - matplotlib-base=3.8.4=py311hff79762_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2b27fa8_2 - - memory-allocator=0.1.3=py311h2725bcf_0 - - metis=5.1.0=he965462_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=h81bd1dd_0 + - m4rie=20200125=hd82a5f3_0 + - markupsafe=3.0.2=py311ha3cf9ac_1 + - matplotlib=3.10.0=py311h6eed73b_0 + - matplotlib-base=3.10.0=py311h19a4563_0 + - matplotlib-inline=0.1.7=pyhd8ed1ab_1 + - maxima=5.47.0=h3080a4d_3 + - memory-allocator=0.1.3=py311h3336109_1 + - meson=1.6.1=pyhd8ed1ab_0 + - meson-python=0.17.1=pyh70fd9c4_1 + - mpc=1.3.1=h9d8efa1_1 - mpfi=1.5.4=h52b28e3_1001 - - mpfr=4.2.1=h4f6b447_1 - - mpmath=1.3.0=pyhd8ed1ab_0 + - mpfr=4.2.1=haed47dc_3 + - mpmath=1.3.0=pyhd8ed1ab_1 - munkres=1.1.4=pyh9f0ad1d_0 - nauty=2.8.8=h10d778d_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h5846eda_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 + - ncurses=6.5=hf036a51_1 + - nest-asyncio=1.6.0=pyhd8ed1ab_1 + - networkx=3.4.2=pyh267e887_2 - ninja=1.12.1=h3c5361c_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - ntl=11.4.3=h0ab3c2f_1 - numpy=1.26.4=py311hc43a94b_0 - - openblas=0.3.25=openmp_h6794695_0 - - openjdk=22.0.1=h2d185b6_0 - - openjpeg=2.5.2=h7310d3a_0 - - openssl=3.3.1=h87427d6_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 + - openblas=0.3.28=openmp_h30af337_1 + - openjpeg=2.5.3=h7fd6d84_0 + - openssl=3.4.0=hd471939_0 + - packaging=24.2=pyhd8ed1ab_2 - palp=2.20=hbcb3906_0 - - pandoc=3.2.1=h694c41f_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h880b76c_0 - pari=2.15.5=h7ba67ff_2_pthread - pari-elldata=0.0.20161017=0 - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - pari-seadata=0.0.20090618=0 - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=hbcf498f_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h7634a1b_0 - - pep517=0.13.0=pyhd8ed1ab_0 + - parso=0.8.4=pyhd8ed1ab_1 - perl=5.32.1=7_h10d778d_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py311h2755ac0_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h73e2aa4_0 - - pkg-config=0.29.2=ha3d46e9_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 + - pexpect=4.9.0=pyhd8ed1ab_1 + - pickleshare=0.7.5=pyhd8ed1ab_1004 + - pillow=11.0.0=py311h1f68098_0 + - pip=24.3.1=pyh8b19718_2 + - pkg-config=0.29.2=hf7e621a_1009 + - pkgconfig=1.5.5=pyhd8ed1ab_5 - planarity=3.0.2.0=h10d778d_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 + - platformdirs=4.3.6=pyhd8ed1ab_1 + - pluggy=1.5.0=pyhd8ed1ab_1 - ppl=1.2=ha60d53e_1006 - pplpy=0.8.9=py311h922ec50_1 - primecount=7.6=ha894c9a_0 - primecountpy=0.1.0=py311h5fe6e05_4 - primesieve=11.0=hf0c8a7f_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py311h72ae277_0 - - pthread-stubs=0.4=hc929b4f_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py311h1d816ee_0 - - pybind11-global=2.12.0=py311h1d816ee_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py311h9d23797_0 - - pyobjc-framework-cocoa=10.3.1=py311h9d23797_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py311he705e18_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.11.9=h657bba9_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py311hdd0406b_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.11=4_cp311 - - pythran=0.15.0=py311ha853786_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py311h6eed73b_4 - - pyyaml=6.0.1=py311h2725bcf_1 - - pyzmq=26.0.3=py311h89e2aaa_0 + - prompt-toolkit=3.0.48=pyha770c72_1 + - psutil=6.1.0=py311h1314207_0 + - pthread-stubs=0.4=h00291cd_1002 + - ptyprocess=0.7.0=pyhd8ed1ab_1 + - pure_eval=0.2.3=pyhd8ed1ab_1 + - pycparser=2.22=pyh29332c3_1 + - pygments=2.18.0=pyhd8ed1ab_1 + - pyparsing=3.2.0=pyhd8ed1ab_2 + - pyproject-metadata=0.9.0=pyhd8ed1ab_1 + - pysocks=1.7.1=pyha55dd90_7 + - pytest=8.3.4=pyhd8ed1ab_1 + - pytest-xdist=3.6.1=pyhd8ed1ab_1 + - python=3.11.11=h9ccd52b_1_cpython + - python-dateutil=2.9.0.post0=pyhff2d567_1 + - python-lrcalc=2.1=py311hd89902b_7 + - python_abi=3.11=5_cp311 + - pytz=2024.2=pyhd8ed1ab_1 + - pyzmq=26.2.0=py311h4d3da15_3 - qd=2.3.22=h2beb688_1004 - - qhull=2020.2=h940c156_2 - - r-base=4.3.3=h4648a1f_3 - - r-lattice=0.22_6=r43hb2c329c_0 + - qhull=2020.2=h3c5361c_5 - readline=8.2=h9e318b2_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h0dc2134_0 - - rpds-py=0.18.1=py311h295b1db_0 - - rpy2=3.5.11=py311r43h4a70a88_3 + - requests=2.32.3=pyhd8ed1ab_1 - rw=0.9=h10d778d_2 - - sagemath-db-combinatorial-designs=20140630=1 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py311he0bea55_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 + - scipy=1.14.1=py311h86b91e6_2 + - setuptools=75.6.0=pyhff2d567_1 - sigtool=0.1.3=h88f4db0_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h0d51a9f_1 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 + - singular=4.4.0=h604985e_1 + - six=1.17.0=pyhd8ed1ab_0 - snowballstemmer=2.2.0=pyhd8ed1ab_0 - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h28673e1_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hd2b2131_1 + - sphinx=8.1.3=pyhd8ed1ab_1 + - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_2 + - sphinx-inline-tabs=2023.4.21=pyhd8ed1ab_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_1 + - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 + - sqlite=3.47.2=h2e4c9dc_0 + - stack_data=0.6.3=pyhd8ed1ab_1 - symmetrica=3.0.1=hf0c8a7f_0 - sympow=2.023.6=h115ba6a_3 - - sympy=1.12.1=pypyh2585a3b_103 + - sympy=1.13.3=pyh2585a3b_104 - tachyon=0.99b6=h3a1d103_1002 - - tapi=1100.0.11=h9ce4665_0 - - tar=1.34=hcb2f6ea_1 - - tbb=2021.12.0=h3c5361c_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321hc47821c_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 + - tapi=1300.6.5=h390ca13_0 - tk=8.6.13=h1abcd95_1 - - tktable=2.10=hba9d6f1_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py311h72ae277_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py311h6eed73b_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=h0dc2134_0 - - xorg-libxdmcp=1.1.3=h35c211d_0 - - xz=5.2.6=h775f41a_0 - - yaml=0.2.5=h0d85af4_2 - - zeromq=4.3.5=hde137ed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h87427d6_1 + - tomli=2.2.1=pyhd8ed1ab_1 + - tornado=6.4.2=py311h4d7f069_0 + - traitlets=5.14.3=pyhd8ed1ab_1 + - typing_extensions=4.12.2=pyha770c72_1 + - tzdata=2024b=hc8b5060_0 + - unicodedata2=15.1.0=py311h1314207_1 + - urllib3=2.2.3=pyhd8ed1ab_1 + - wcwidth=0.2.13=pyhd8ed1ab_1 + - wheel=0.45.1=pyhd8ed1ab_1 + - widgetsnbextension=4.0.13=pyhd8ed1ab_1 + - xorg-libxau=1.0.12=h6e16a3a_0 + - xorg-libxdmcp=1.1.5=h00291cd_0 + - xz=5.6.3=h357f2ed_1 + - xz-gpl-tools=5.6.3=h357f2ed_1 + - xz-tools=5.6.3=hd471939_1 + - zeromq=4.3.5=h7130eaa_7 + - zipp=3.21.0=pyhd8ed1ab_1 + - zlib=1.3.1=hd23fc13_2 + - zstandard=0.23.0=py311hdf6fcd6_1 - zstd=1.5.6=h915ae27_0 diff --git a/environment-3.11-macos.yml b/environment-3.11-macos.yml index 8ae6a449026..ec10b78a4b5 100644 --- a/environment-3.11-macos.yml +++ b/environment-3.11-macos.yml @@ -1,423 +1,294 @@ -name: sage +name: sage-dev # Generated by conda-lock. # platform: osx-arm64 -# input_hash: fd2f5edaba32b4c1f22d499071de74bde7eb804a27ac64e89ee82df0d733a829 +# input_hash: 4396163dbc4fafd471282f306c16bb7bd73ecc3c006335c8faf512742014e1e4 channels: - conda-forge dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py311heffc1b2_4 + - alabaster=1.0.0=pyhd8ed1ab_1 + - appnope=0.1.4=pyhd8ed1ab_1 - arpack=3.9.1=nompi_h593882a_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 + - asttokens=3.0.0=pyhd8ed1ab_1 - autoconf=2.71=pl5321hcd07c0c_1 - - automake=1.16.5=pl5321hce30654_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=h3422bc3_0 + - automake=1.17=pl5321hce30654_0 + - babel=2.16.0=pyhd8ed1ab_1 - bdw-gc=8.0.6=hc021e02_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osxarm64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=hca5e981_2 + - beautifulsoup4=4.12.3=pyha770c72_1 + - blas=2.126=openblas + - blas-devel=3.9.0=26_osxarm64_openblas + - boost-cpp=1.85.0=h103c1d6_4 - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hb547adb_1 - - brotli-bin=1.1.0=hb547adb_1 - - brotli-python=1.1.0=py311ha891d26_1 - - bwidget=1.9.14=hce30654_1 - - bzip2=1.0.8=h93a5062_5 - - c-ares=1.28.1=h93a5062_0 - - c-compiler=1.7.0=h6aa9301_1 - - ca-certificates=2024.6.2=hf0a4a13_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=hc6c324b_2 - - cctools=986=h4faf515_0 - - cctools_osx-arm64=986=h62378fb_0 + - brotli=1.1.0=hd74edd7_2 + - brotli-bin=1.1.0=hd74edd7_2 + - brotli-python=1.1.0=py311h3f08180_2 + - bzip2=1.0.8=h99b78c6_7 + - c-ares=1.34.4=h5505292_0 + - c-compiler=1.8.0=hf48404e_1 + - ca-certificates=2024.12.14=hf0a4a13_0 + - cctools=1010.6=hf67d63f_2 + - cctools_osx-arm64=1010.6=h623e0ac_2 - cddlib=1!0.94m=h6d7a090_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py311h4a08483_0 - - chardet=5.2.0=py311h267d04e_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_h095aff0_8 - - clang-16=16.0.6=default_hb63da90_8 - - clang_impl_osx-arm64=16.0.6=hc421ffc_16 - - clang_osx-arm64=16.0.6=h54d7cd3_16 - - clangxx=16.0.6=default_h095aff0_8 - - clangxx_impl_osx-arm64=16.0.6=hcd7bac0_16 - - clangxx_osx-arm64=16.0.6=h54d7cd3_16 + - certifi=2024.12.14=pyhd8ed1ab_0 + - cffi=1.17.1=py311h3a79f62_0 + - charset-normalizer=3.4.0=pyhd8ed1ab_1 + - clang=17.0.6=default_h360f5da_7 + - clang-17=17.0.6=default_h146c034_7 + - clang_impl_osx-arm64=17.0.6=he47c785_23 + - clang_osx-arm64=17.0.6=h07b0088_23 + - clangxx=17.0.6=default_h360f5da_7 + - clangxx_impl_osx-arm64=17.0.6=h50f59cd_23 + - clangxx_osx-arm64=17.0.6=h07b0088_23 - cliquer=1.22=h93a5062_1 - - cmake=3.29.6=had79d8f_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py311h267d04e_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=h3808999_2 - - compiler-rt_osx-arm64=16.0.6=h3808999_2 - - compilers=1.7.0=hce30654_1 - - contourpy=1.2.1=py311hcc98501_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=h653d890_0 - - cvxopt=1.3.2=py311h77cf4c7_2 - - cxx-compiler=1.7.0=h2ffa867_1 - - cycler=0.12.1=pyhd8ed1ab_0 + - colorama=0.4.6=pyhd8ed1ab_1 + - comm=0.2.2=pyhd8ed1ab_1 + - compiler-rt=17.0.6=h856b3c1_2 + - compiler-rt_osx-arm64=17.0.6=h832e737_2 + - contourpy=1.3.1=py311h210dab8_0 + - conway-polynomials=0.10=pyhd8ed1ab_0 + - coverage=7.6.9=py311h4921393_0 + - cpython=3.11.11=py311hd8ed1ab_1 + - cxx-compiler=1.8.0=h18dbf2f_1 + - cycler=0.12.1=pyhd8ed1ab_1 - cypari2=2.1.5=py311h2c49a9d_0 - cysignals=1.11.2=py311he42fc87_3 - - cython=3.0.10=py311h92babd0_0 - - debugpy=1.8.1=py311h92babd0_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h9397a75_1203 + - cython=3.0.11=py311hf7f79b8_3 + - debugpy=1.8.11=py311h155a34a_0 + - decorator=5.1.1=pyhd8ed1ab_1 + - docutils=0.21.2=pyhd8ed1ab_1 - ecl=23.9.9=h1d9728a_0 - - eclib=20231212=h7f07de4_0 + - eclib=20231212=h3d50bd9_1 - ecm=7.0.5=h41d338b_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=hebf3989_0 + - exceptiongroup=1.2.2=pyhd8ed1ab_1 + - execnet=2.1.1=pyhd8ed1ab_1 + - executing=2.1.0=pyhd8ed1ab_1 + - expat=2.6.4=h286801f_0 - fflas-ffpack=2.5.0=h4bc3318_0 - - fftw=3.3.10=nompi_h6637ab6_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - font-ttf-inconsolata=3.000=h77eed37_0 - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h82840c6_0 + - font-ttf-ubuntu=0.83=h77eed37_3 + - fontconfig=2.15.0=h1383a14_1 - fonts-conda-ecosystem=1=0 - fonts-conda-forge=1=0 - - fonttools=4.53.0=py311hd3f4193_0 - - fortran-compiler=1.7.0=hafb19e3_1 + - fonttools=4.55.3=py311h4921393_0 + - fortran-compiler=1.8.0=hc3477c4_1 - fplll=5.4.5=hb7d509d_0 - fpylll=0.6.1=py311h341b96b_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - freetype=2.12.1=hadb7bae_2 - - fribidi=1.0.10=h27ca646_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he8f4e70_3 - - gap-defaults=4.12.2=hce30654_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=hbdafb3b_0 - - gettext=0.22.5=h8fbad5d_2 - - gettext-tools=0.22.5=h8fbad5d_2 - - gf2x=1.3.0=hdaa854c_2 + - furo=2024.8.6=pyhd8ed1ab_1 + - gap-core=4.14.0=h25f1785_1 + - gap-defaults=4.14.0=hce30654_1 + - gettext=0.22.5=h8414b35_3 + - gettext-tools=0.22.5=h8414b35_3 + - gf2x=1.3.0=hf8f8af4_3 - gfan=0.6.2=hec08f5c_1003 - - gfortran=12.3.0=h1ca8e4b_1 - - gfortran_impl_osx-arm64=12.3.0=h53ed385_3 - - gfortran_osx-arm64=12.3.0=h57527a5_1 + - gfortran=13.2.0=h1ca8e4b_1 + - gfortran_impl_osx-arm64=13.2.0=h252ada1_3 + - gfortran_osx-arm64=13.2.0=h57527a5_1 - giac=1.9.0.21=h1c96721_1 - - giflib=5.2.2=h93a5062_0 - givaro=4.2.0=h018886a_0 - glpk=5.0=h6d7a090_0 - gmp=6.3.0=h7bae524_2 - - gmpy2=2.1.5=py311h1e33d93_1 - - graphite2=1.3.13=hebf3989_1003 + - gmpy2=2.1.5=py311hb5d9ff4_3 - gsl=2.7=h6e638da_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h1836168_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hc8870d7_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h762ac30_1 + - h2=4.1.0=pyhd8ed1ab_1 + - hpack=4.0.0=pyhd8ed1ab_1 + - hyperframe=6.0.1=pyhd8ed1ab_1 + - icu=75.1=hfee45f7_0 + - idna=3.10=pyhd8ed1ab_1 + - igraph=0.10.15=h3fe6531_1 - imagesize=1.4.1=pyhd8ed1ab_0 - iml=1.0.5=hd73f12c_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 + - importlib-metadata=8.5.0=pyha770c72_1 + - iniconfig=2.0.0=pyhd8ed1ab_1 + - ipykernel=6.29.5=pyh57ce528_0 + - ipython=8.30.0=pyh707e725_0 + - ipywidgets=8.1.5=pyhd8ed1ab_1 - isl=0.26=imath32_h347afa1_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=hce30654_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py311h267d04e_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py311h267d04e_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kiwisolver=1.4.5=py311he4fd1f5_1 - - krb5=1.21.2=h92f50d5_0 + - jedi=0.19.2=pyhd8ed1ab_1 + - jinja2=3.1.4=pyhd8ed1ab_1 + - jupyter_client=8.6.3=pyhd8ed1ab_1 + - jupyter_core=5.7.2=pyh31011fe_1 + - jupyterlab_widgets=3.0.13=pyhd8ed1ab_1 + - kiwisolver=1.4.7=py311h2c37856_0 + - krb5=1.21.3=h237132a_0 - lcalc=2.0.5=h4a402bc_2 - lcms2=2.16=ha0e7c42_0 - - ld64=711=h634c8be_0 - - ld64_osx-arm64=711=ha4bd21c_0 + - ld64=951.9=h39a299f_2 + - ld64_osx-arm64=951.9=h3f9b568_2 - lerc=4.0.0=h9a09cb3_0 - - libasprintf=0.22.5=h8fbad5d_2 - - libasprintf-devel=0.22.5=h8fbad5d_2 - - libatomic_ops=7.6.14=h1a8c8d9_0 - - libblas=3.9.0=20_osxarm64_openblas - - libboost=1.85.0=h17eb2be_2 - - libboost-devel=1.85.0=hf450f58_2 - - libboost-headers=1.85.0=hce30654_2 - - libbraiding=1.2=hb7217d7_0 + - libasprintf=0.22.5=h8414b35_3 + - libasprintf-devel=0.22.5=h8414b35_3 + - libblas=3.9.0=26_osxarm64_openblas + - libboost=1.85.0=hf763ba5_4 + - libboost-devel=1.85.0=hf450f58_4 + - libboost-headers=1.85.0=hce30654_4 + - libbraiding=1.3=h286801f_0 - libbrial=1.2.12=h56a29cd_3 - - libbrotlicommon=1.1.0=hb547adb_1 - - libbrotlidec=1.1.0=hb547adb_1 - - libbrotlienc=1.1.0=hb547adb_1 - - libcblas=3.9.0=20_osxarm64_openblas - - libclang-cpp16=16.0.6=default_hb63da90_8 - - libcurl=8.8.0=h7b6f9a7_0 - - libcxx=17.0.6=h5f092b4_0 - - libdeflate=1.20=h93a5062_0 + - libbrotlicommon=1.1.0=hd74edd7_2 + - libbrotlidec=1.1.0=hd74edd7_2 + - libbrotlienc=1.1.0=hd74edd7_2 + - libcblas=3.9.0=26_osxarm64_openblas + - libclang-cpp17=17.0.6=default_h146c034_7 + - libcurl=8.11.1=h73640d1_0 + - libcxx=19.1.6=ha82da77_1 + - libcxx-devel=17.0.6=h86353a2_6 + - libdeflate=1.23=hec38601_0 - libedit=3.1.20191231=hc8eb9b7_2 - libev=4.33=h93a5062_2 - - libexpat=2.6.2=hebf3989_0 + - libexpat=2.6.4=h286801f_0 - libffi=3.4.2=h3422bc3_5 - - libflint=3.0.1=h28749a5_ntl_100 - - libgd=2.3.3=hfdf3952_9 - - libgettextpo=0.22.5=h8fbad5d_2 - - libgettextpo-devel=0.22.5=h8fbad5d_2 + - libflint=3.1.2=he28cf6d_101 + - libgd=2.3.3=hac1b3a8_10 + - libgettextpo=0.22.5=h8414b35_3 + - libgettextpo-devel=0.22.5=h8414b35_3 - libgfortran=5.0.0=13_2_0_hd922786_3 - - libgfortran-devel_osx-arm64=12.3.0=hc62be1c_3 + - libgfortran-devel_osx-arm64=13.2.0=h5d7a38c_3 - libgfortran5=13.2.0=hf226fd6_3 - - libglib=2.80.2=h59d46d9_1 + - libglib=2.82.2=h07bd6cf_0 - libhomfly=1.02r6=h93a5062_1 - - libhwloc=2.10.0=default_h7685b71_1001 - libiconv=1.17=h0d3ecfb_2 - - libintl=0.22.5=h8fbad5d_2 - - libintl-devel=0.22.5=h8fbad5d_2 + - libintl=0.22.5=h8414b35_3 + - libintl-devel=0.22.5=h8414b35_3 - libjpeg-turbo=3.0.0=hb547adb_1 - - liblapack=3.9.0=20_osxarm64_openblas - - liblapacke=3.9.0=20_osxarm64_openblas - - libllvm16=16.0.6=haab561b_3 - - libnghttp2=1.58.0=ha4dd798_1 - - libopenblas=0.3.25=openmp_h6c19121_0 - - libpng=1.6.43=h091b4b1_0 - - libsodium=1.0.18=h27ca646_1 - - libsqlite=3.46.0=hfb93653_0 - - libssh2=1.11.0=h7a5bd25_0 - - libtiff=4.6.0=h07db509_3 - - libtool=2.4.7=hb7217d7_0 - - libuv=1.48.0=h93a5062_0 - - libwebp=1.4.0=h54798ee_0 + - liblapack=3.9.0=26_osxarm64_openblas + - liblapacke=3.9.0=26_osxarm64_openblas + - libllvm17=17.0.6=h5090b49_2 + - liblzma=5.6.3=h39f12f2_1 + - liblzma-devel=5.6.3=h39f12f2_1 + - libnghttp2=1.64.0=h6d7220d_0 + - libopenblas=0.3.28=openmp_hf332438_1 + - libpng=1.6.44=hc14010f_0 + - libsodium=1.0.20=h99b78c6_0 + - libsqlite=3.47.2=h3f77e49_0 + - libssh2=1.11.1=h9cc3647_0 + - libtiff=4.7.0=h551f018_3 - libwebp-base=1.4.0=h93a5062_0 - - libxcb=1.16=hf2054a2_0 - - libxml2=2.12.7=ha661575_1 - - libzlib=1.3.1=hfb2fe0b_1 - - linbox=1.7.0=h3afee3a_0 - - llvm-openmp=18.1.8=hde57baf_0 - - llvm-tools=16.0.6=haab561b_3 - - lrcalc=2.1=hebf3989_6 + - libxcb=1.17.0=hdb1d25a_0 + - libxml2=2.13.5=h178c5d8_1 + - libzlib=1.3.1=h8359307_2 + - linbox=1.7.0=h9da6ecd_1 + - llvm-openmp=19.1.6=hdb05f8b_0 + - llvm-tools=17.0.6=h5090b49_2 + - lrcalc=2.1=hf9b8971_7 - m4=1.4.18=h642e427_1001 - m4ri=20140914=hc97c1ff_1006 - - m4rie=20150908=h22b9e9d_1002 - - make=4.3=he57ea6c_1 - - markupsafe=2.1.5=py311h05b510d_0 - - mathjax=3.2.2=hce30654_0 - - matplotlib=3.8.4=py311ha1ab1f8_2 - - matplotlib-base=3.8.4=py311h000fb6e_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 + - m4rie=20200125=hc97c1ff_0 + - markupsafe=3.0.2=py311h4921393_1 + - matplotlib=3.10.0=py311ha1ab1f8_0 + - matplotlib-base=3.10.0=py311h031da69_0 + - matplotlib-inline=0.1.7=pyhd8ed1ab_1 - maxima=5.47.0=h2bbcd85_2 - - memory-allocator=0.1.3=py311heffc1b2_0 - - metis=5.1.0=h13dd4ca_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=h91ba8db_0 + - memory-allocator=0.1.3=py311h460d6c5_1 + - meson=1.6.1=pyhd8ed1ab_0 + - meson-python=0.17.1=pyh70fd9c4_1 + - mpc=1.3.1=h8f1351a_1 - mpfi=1.5.4=hbde5f5b_1001 - - mpfr=4.2.1=h41d338b_1 - - mpmath=1.3.0=pyhd8ed1ab_0 + - mpfr=4.2.1=hb693164_3 + - mpmath=1.3.0=pyhd8ed1ab_1 - munkres=1.1.4=pyh9f0ad1d_0 - nauty=2.8.8=h93a5062_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=hb89a1cb_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 + - ncurses=6.5=h7bae524_1 + - nest-asyncio=1.6.0=pyhd8ed1ab_1 + - networkx=3.4.2=pyh267e887_2 - ninja=1.12.1=h420ef59_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - ntl=11.4.3=hbb3f309_1 - numpy=1.26.4=py311h7125741_0 - - openblas=0.3.25=openmp_h55c453e_0 - - openjdk=22.0.1=hbeb2e11_0 - - openjpeg=2.5.2=h9f1df11_0 - - openssl=3.3.1=hfb2fe0b_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 + - openblas=0.3.28=openmp_hea878ba_1 + - openjpeg=2.5.3=h8a3d83b_0 + - openssl=3.4.0=h39f12f2_0 + - packaging=24.2=pyhd8ed1ab_2 - palp=2.20=h27ca646_0 - - pandoc=3.2.1=hce30654_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h5cb9fbc_0 - pari=2.15.5=h4f2304c_2_pthread - pari-elldata=0.0.20161017=0 - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - pari-seadata=0.0.20090618=0 - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=h27ca646_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h297a79d_0 - - pep517=0.13.0=pyhd8ed1ab_0 + - parso=0.8.4=pyhd8ed1ab_1 + - pcre2=10.44=h297a79d_2 - perl=5.32.1=7_h4614cfb_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py311hd7951ec_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=hebf3989_0 - - pkg-config=0.29.2=hab62308_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 + - pexpect=4.9.0=pyhd8ed1ab_1 + - pickleshare=0.7.5=pyhd8ed1ab_1004 + - pillow=11.0.0=py311h3894ae9_0 + - pip=24.3.1=pyh8b19718_2 + - pkg-config=0.29.2=hde07d2e_1009 + - pkgconfig=1.5.5=pyhd8ed1ab_5 - planarity=3.0.2.0=h93a5062_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 + - platformdirs=4.3.6=pyhd8ed1ab_1 + - pluggy=1.5.0=pyhd8ed1ab_1 - ppl=1.2=h8b147cf_1006 - pplpy=0.8.9=py311h3d77d83_1 - primecount=7.6=hb6e4faa_0 - primecountpy=0.1.0=py311he4fd1f5_4 - primesieve=11.0=hb7217d7_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py311hd3f4193_0 - - pthread-stubs=0.4=h27ca646_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py311hcc98501_0 - - pybind11-global=2.12.0=py311hcc98501_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py311h5f135c3_0 - - pyobjc-framework-cocoa=10.3.1=py311h5f135c3_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py311h05b510d_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.11.9=h932a869_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py311h92babd0_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.11=4_cp311 - - pythran=0.15.0=py311hceb3b21_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py311h267d04e_4 - - pyyaml=6.0.1=py311heffc1b2_1 - - pyzmq=26.0.3=py311h9bed540_0 + - prompt-toolkit=3.0.48=pyha770c72_1 + - psutil=6.1.0=py311hae2e1ce_0 + - pthread-stubs=0.4=hd74edd7_1002 + - ptyprocess=0.7.0=pyhd8ed1ab_1 + - pure_eval=0.2.3=pyhd8ed1ab_1 + - pycparser=2.22=pyh29332c3_1 + - pygments=2.18.0=pyhd8ed1ab_1 + - pyparsing=3.2.0=pyhd8ed1ab_2 + - pyproject-metadata=0.9.0=pyhd8ed1ab_1 + - pysocks=1.7.1=pyha55dd90_7 + - pytest=8.3.4=pyhd8ed1ab_1 + - pytest-xdist=3.6.1=pyhd8ed1ab_1 + - python=3.11.11=hc22306f_1_cpython + - python-dateutil=2.9.0.post0=pyhff2d567_1 + - python-lrcalc=2.1=py311h3f08180_7 + - python_abi=3.11=5_cp311 + - pytz=2024.2=pyhd8ed1ab_1 + - pyzmq=26.2.0=py311h730b646_3 - qd=2.3.22=hbec66e7_1004 - - qhull=2020.2=hc021e02_2 - - r-base=4.3.3=h8112bfe_3 - - r-lattice=0.22_6=r43hd2d937b_0 + - qhull=2020.2=h420ef59_5 - readline=8.2=h92ec313_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hb547adb_0 - - rpds-py=0.18.1=py311h98c6a39_0 - - rpy2=3.5.11=py311r43hb49d859_3 + - requests=2.32.3=pyhd8ed1ab_1 - rw=0.9=h93a5062_2 - - sagemath-db-combinatorial-designs=20140630=1 - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - sagemath-db-graphs=20210214=hd8ed1ab_0 - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py311h2b215a9_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 + - scipy=1.14.1=py311hf056e50_2 + - setuptools=75.6.0=pyhff2d567_1 - sigtool=0.1.3=h44b9a77_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hb460b52_1 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 + - singular=4.4.0=h5a8969a_1 + - six=1.17.0=pyhd8ed1ab_0 - snowballstemmer=2.2.0=pyhd8ed1ab_0 - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h5838104_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf6fcff2_1 + - sphinx=8.1.3=pyhd8ed1ab_1 + - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_2 + - sphinx-inline-tabs=2023.4.21=pyhd8ed1ab_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_1 + - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 + - sqlite=3.47.2=hd7222ec_0 + - stack_data=0.6.3=pyhd8ed1ab_1 - symmetrica=3.0.1=hb7217d7_0 - sympow=2.023.6=hb0babe8_3 - - sympy=1.12.1=pypyh2585a3b_103 + - sympy=1.13.3=pyh2585a3b_104 - tachyon=0.99b6=hb8a568e_1002 - - tapi=1100.0.11=he4954df_0 - - tar=1.34=h7cb298e_1 - - tbb=2021.12.0=h420ef59_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321h9ea1dce_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 + - tapi=1300.6.5=h03f4b80_0 - tk=8.6.13=h5083fa2_1 - - tktable=2.10=h1e387b8_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py311hd3f4193_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py311h267d04e_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=hb547adb_0 - - xorg-libxdmcp=1.1.3=h27ca646_0 - - xz=5.2.6=h57fd34a_0 - - yaml=0.2.5=h3422bc3_2 - - zeromq=4.3.5=hcc0f68c_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=hfb2fe0b_1 + - tomli=2.2.1=pyhd8ed1ab_1 + - tornado=6.4.2=py311h917b07b_0 + - traitlets=5.14.3=pyhd8ed1ab_1 + - typing_extensions=4.12.2=pyha770c72_1 + - tzdata=2024b=hc8b5060_0 + - unicodedata2=15.1.0=py311hae2e1ce_1 + - urllib3=2.2.3=pyhd8ed1ab_1 + - wcwidth=0.2.13=pyhd8ed1ab_1 + - wheel=0.45.1=pyhd8ed1ab_1 + - widgetsnbextension=4.0.13=pyhd8ed1ab_1 + - xorg-libxau=1.0.12=h5505292_0 + - xorg-libxdmcp=1.1.5=hd74edd7_0 + - xz=5.6.3=h9a6d368_1 + - xz-gpl-tools=5.6.3=h9a6d368_1 + - xz-tools=5.6.3=h39f12f2_1 + - zeromq=4.3.5=hc1bb282_7 + - zipp=3.21.0=pyhd8ed1ab_1 + - zlib=1.3.1=h8359307_2 + - zstandard=0.23.0=py311ha60cc69_1 - zstd=1.5.6=hb46c0d2_0 diff --git a/environment-3.12-linux-aarch64.yml b/environment-3.12-linux-aarch64.yml new file mode 100644 index 00000000000..b97f90268d1 --- /dev/null +++ b/environment-3.12-linux-aarch64.yml @@ -0,0 +1,338 @@ +name: sage-dev +# Generated by conda-lock. +# platform: linux-aarch64 +# input_hash: 28dba81f3f7cbaa4e6f35a34c9679049f47c3d73414a0a80eda04a53603e8a12 + +channels: + - conda-forge +dependencies: + - _openmp_mutex=4.5=2_kmp_llvm + - alabaster=1.0.0=pyhd8ed1ab_1 + - alsa-lib=1.2.13=h86ecc28_0 + - arpack=3.9.1=nompi_hd363cd0_101 + - asttokens=3.0.0=pyhd8ed1ab_1 + - autoconf=2.71=pl5321h2148fe1_1 + - automake=1.17=pl5321h8af1aa0_0 + - babel=2.16.0=pyhd8ed1ab_1 + - bdw-gc=8.0.6=hd62202e_0 + - beautifulsoup4=4.12.3=pyha770c72_1 + - binutils=2.43=hf1166c9_2 + - binutils_impl_linux-aarch64=2.43=h4c662bb_2 + - binutils_linux-aarch64=2.43=hf1166c9_2 + - blas=2.126=openblas + - blas-devel=3.9.0=26_linuxaarch64_openblas + - boost-cpp=1.85.0=hdad291f_4 + - brial=1.2.12=pyh694c41f_3 + - brotli=1.1.0=h86ecc28_2 + - brotli-bin=1.1.0=h86ecc28_2 + - brotli-python=1.1.0=py312h6f74592_2 + - bzip2=1.0.8=h68df207_7 + - c-ares=1.34.4=h86ecc28_0 + - c-compiler=1.8.0=h6561dab_1 + - ca-certificates=2024.12.14=hcefe29a_0 + - cairo=1.18.2=h83712da_1 + - cddlib=1!0.94m=h719063d_0 + - certifi=2024.12.14=pyhd8ed1ab_0 + - cffi=1.17.1=py312hac81daf_0 + - charset-normalizer=3.4.0=pyhd8ed1ab_1 + - cliquer=1.22=h31becfc_1 + - colorama=0.4.6=pyhd8ed1ab_1 + - comm=0.2.2=pyhd8ed1ab_1 + - contourpy=1.3.1=py312h451a7dd_0 + - conway-polynomials=0.10=pyhd8ed1ab_0 + - coverage=7.6.9=py312h74ce7d3_0 + - cpython=3.12.8=py312hd8ed1ab_1 + - cxx-compiler=1.8.0=heb6c788_1 + - cycler=0.12.1=pyhd8ed1ab_1 + - cypari2=2.1.5=py312h7f7bc3d_0 + - cyrus-sasl=2.1.27=hf6b2984_7 + - cysignals=1.11.2=py312haf3d6d2_3 + - cython=3.0.11=py312hdfe4e29_3 + - dbus=1.13.6=h12b9eeb_3 + - debugpy=1.8.11=py312h6f74592_0 + - decorator=5.1.1=pyhd8ed1ab_1 + - docutils=0.21.2=pyhd8ed1ab_1 + - double-conversion=3.3.0=h2f0025b_0 + - ecl=24.5.10=h5567cc5_0 + - eclib=20231212=h154513d_1 + - ecm=7.0.5=ha2d0fc4_0 + - exceptiongroup=1.2.2=pyhd8ed1ab_1 + - execnet=2.1.1=pyhd8ed1ab_1 + - executing=2.1.0=pyhd8ed1ab_1 + - expat=2.6.4=h5ad3122_0 + - fflas-ffpack=2.5.0=h503e619_0 + - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 + - font-ttf-inconsolata=3.000=h77eed37_0 + - font-ttf-source-code-pro=2.038=h77eed37_0 + - font-ttf-ubuntu=0.83=h77eed37_3 + - fontconfig=2.15.0=h8dda3cd_1 + - fonts-conda-ecosystem=1=0 + - fonts-conda-forge=1=0 + - fonttools=4.55.3=py312hcc812fe_0 + - fortran-compiler=1.8.0=h25a59a9_1 + - fplll=5.4.5=hb3a790e_0 + - fpylll=0.6.1=py312h8b93be1_0 + - freetype=2.12.1=hf0a5ef3_2 + - furo=2024.8.6=pyhd8ed1ab_1 + - gap-core=4.14.0=h1754e88_1 + - gap-defaults=4.14.0=h8af1aa0_1 + - gcc=13.3.0=h8a56e6e_1 + - gcc_impl_linux-aarch64=13.3.0=hcdea9b6_1 + - gcc_linux-aarch64=13.3.0=h1cd514b_7 + - gf2x=1.3.0=h9af5f66_3 + - gfan=0.6.2=h5f589ec_1003 + - gfortran=13.3.0=h8a56e6e_1 + - gfortran_impl_linux-aarch64=13.3.0=h174a3c4_1 + - gfortran_linux-aarch64=13.3.0=h2809cf8_7 + - giac=1.9.0.21=h04922a4_1 + - givaro=4.2.0=h364d21b_0 + - glpk=5.0=h66325d0_0 + - gmp=6.3.0=h0a1ffab_2 + - gmpy2=2.1.5=py312he9d48ea_3 + - graphite2=1.3.13=h2f0025b_1003 + - gsl=2.7=h294027d_0 + - gxx=13.3.0=h8a56e6e_1 + - gxx_impl_linux-aarch64=13.3.0=h1211b58_1 + - gxx_linux-aarch64=13.3.0=h2864abd_7 + - h2=4.1.0=pyhd8ed1ab_1 + - harfbuzz=9.0.0=hbf49d6b_1 + - hpack=4.0.0=pyhd8ed1ab_1 + - hyperframe=6.0.1=pyhd8ed1ab_1 + - icu=75.1=hf9b3779_0 + - idna=3.10=pyhd8ed1ab_1 + - igraph=0.10.15=h207f3e5_1 + - imagesize=1.4.1=pyhd8ed1ab_0 + - iml=1.0.5=h15043fe_1004 + - importlib-metadata=8.5.0=pyha770c72_1 + - iniconfig=2.0.0=pyhd8ed1ab_1 + - ipykernel=6.29.5=pyh3099207_0 + - ipython=8.30.0=pyh707e725_0 + - ipywidgets=8.1.5=pyhd8ed1ab_1 + - jedi=0.19.2=pyhd8ed1ab_1 + - jinja2=3.1.4=pyhd8ed1ab_1 + - jupyter_client=8.6.3=pyhd8ed1ab_1 + - jupyter_core=5.7.2=pyh31011fe_1 + - jupyterlab_widgets=3.0.13=pyhd8ed1ab_1 + - kernel-headers_linux-aarch64=4.18.0=h05a177a_18 + - keyutils=1.6.1=h4e544f5_0 + - kiwisolver=1.4.7=py312h88dc405_0 + - krb5=1.21.3=h50a48e9_0 + - lcalc=2.0.5=he588f68_2 + - lcms2=2.16=h922389a_0 + - ld_impl_linux-aarch64=2.43=h80caac9_2 + - lerc=4.0.0=h4de3ea5_0 + - libblas=3.9.0=26_linuxaarch64_openblas + - libboost=1.85.0=h9fa81b4_4 + - libboost-devel=1.85.0=h37bb5a9_4 + - libboost-headers=1.85.0=h8af1aa0_4 + - libbraiding=1.3=h5ad3122_0 + - libbrial=1.2.12=h9429f74_3 + - libbrotlicommon=1.1.0=h86ecc28_2 + - libbrotlidec=1.1.0=h86ecc28_2 + - libbrotlienc=1.1.0=h86ecc28_2 + - libcblas=3.9.0=26_linuxaarch64_openblas + - libclang-cpp19.1=19.1.6=default_he324ac1_0 + - libclang13=19.1.6=default_h4390ef5_0 + - libcups=2.3.3=h405e4a8_4 + - libcurl=8.11.1=h6702fde_0 + - libdeflate=1.23=h5e3c512_0 + - libdrm=2.4.124=h86ecc28_0 + - libedit=3.1.20191231=he28a2e2_2 + - libegl=1.7.0=hd24410f_2 + - libev=4.33=h31becfc_2 + - libexpat=2.6.4=h5ad3122_0 + - libffi=3.4.2=h3557bc0_5 + - libflint=3.1.2=h0433c20_101 + - libgcc=14.2.0=he277a41_1 + - libgcc-devel_linux-aarch64=13.3.0=h0c07274_101 + - libgcc-ng=14.2.0=he9431aa_1 + - libgd=2.3.3=h6818b27_10 + - libgfortran=14.2.0=he9431aa_1 + - libgfortran-ng=14.2.0=he9431aa_1 + - libgfortran5=14.2.0=hb6113d0_1 + - libgl=1.7.0=hd24410f_2 + - libglib=2.82.2=hc486b8e_0 + - libglvnd=1.7.0=hd24410f_2 + - libglx=1.7.0=hd24410f_2 + - libgomp=14.2.0=he277a41_1 + - libhomfly=1.02r6=h31becfc_1 + - libiconv=1.17=h31becfc_2 + - libjpeg-turbo=3.0.0=h31becfc_1 + - liblapack=3.9.0=26_linuxaarch64_openblas + - liblapacke=3.9.0=26_linuxaarch64_openblas + - libllvm19=19.1.6=h2edbd07_0 + - liblzma=5.6.3=h86ecc28_1 + - liblzma-devel=5.6.3=h86ecc28_1 + - libnghttp2=1.64.0=hc8609a4_0 + - libnsl=2.0.1=h31becfc_0 + - libntlm=1.4=hf897c2e_1002 + - libopenblas=0.3.28=pthreads_h9d3fd7e_1 + - libopengl=1.7.0=hd24410f_2 + - libpciaccess=0.18=h31becfc_0 + - libpng=1.6.44=hc4a20ef_0 + - libpq=17.2=hd56632b_1 + - libsanitizer=13.3.0=ha58e236_1 + - libsodium=1.0.20=h68df207_0 + - libsqlite=3.47.2=h5eb1b54_0 + - libssh2=1.11.1=ha41c0db_0 + - libstdcxx=14.2.0=h3f4de04_1 + - libstdcxx-devel_linux-aarch64=13.3.0=h0c07274_101 + - libstdcxx-ng=14.2.0=hf1166c9_1 + - libtiff=4.7.0=h88f7998_3 + - libuuid=2.38.1=hb4cce97_0 + - libwebp-base=1.4.0=h31becfc_0 + - libxcb=1.17.0=h262b8f6_0 + - libxcrypt=4.4.36=h31becfc_1 + - libxkbcommon=1.7.0=h46f2afe_1 + - libxml2=2.13.5=h2e0c361_1 + - libxslt=1.1.39=h1cc9640_0 + - libzlib=1.3.1=h86ecc28_2 + - linbox=1.7.0=hf74d613_1 + - llvm-openmp=19.1.6=h013ceaa_0 + - lrcalc=2.1=h5ad3122_7 + - m4=1.4.18=h516909a_1001 + - m4ri=20140914=hedfd65a_1006 + - m4rie=20200125=hedfd65a_0 + - markupsafe=3.0.2=py312h74ce7d3_1 + - matplotlib=3.10.0=py312h8025657_0 + - matplotlib-base=3.10.0=py312h965bf68_0 + - matplotlib-inline=0.1.7=pyhd8ed1ab_1 + - maxima=5.47.0=h043f013_3 + - memory-allocator=0.1.3=py312hb2c0f52_1 + - meson=1.6.1=pyhd8ed1ab_0 + - meson-python=0.17.1=pyh70fd9c4_1 + - mpc=1.3.1=h783934e_1 + - mpfi=1.5.4=h846f343_1001 + - mpfr=4.2.1=h2305555_3 + - mpmath=1.3.0=pyhd8ed1ab_1 + - munkres=1.1.4=pyh9f0ad1d_0 + - mysql-common=9.0.1=h3f5c77f_3 + - mysql-libs=9.0.1=h11569fd_3 + - nauty=2.8.8=h31becfc_1 + - ncurses=6.5=hcccb83c_1 + - nest-asyncio=1.6.0=pyhd8ed1ab_1 + - networkx=3.4.2=pyh267e887_2 + - ninja=1.12.1=h70be974_0 + - ntl=11.4.3=h0d7519b_1 + - numpy=1.26.4=py312h470d778_0 + - openblas=0.3.28=pthreads_h3a8cbd8_1 + - openjpeg=2.5.3=h3f56577_0 + - openldap=2.6.9=h30c48ee_0 + - openssl=3.4.0=h86ecc28_0 + - packaging=24.2=pyhd8ed1ab_2 + - palp=2.20=hb9de7d4_0 + - pari=2.15.5=h169c2a7_2_pthread + - pari-elldata=0.0.20161017=0 + - pari-galdata=0.0.20180411=0 + - pari-seadata=0.0.20090618=0 + - pari-seadata-small=0.0.20090618=0 + - parso=0.8.4=pyhd8ed1ab_1 + - pcre2=10.44=h070dd5b_2 + - perl=5.32.1=7_h31becfc_perl5 + - pexpect=4.9.0=pyhd8ed1ab_1 + - pickleshare=0.7.5=pyhd8ed1ab_1004 + - pillow=11.0.0=py312h5ab5af3_0 + - pip=24.3.1=pyh8b19718_2 + - pixman=0.44.2=h86a87f0_0 + - pkg-config=0.29.2=hce167ba_1009 + - pkgconfig=1.5.5=pyhd8ed1ab_5 + - planarity=3.0.2.0=h31becfc_0 + - platformdirs=4.3.6=pyhd8ed1ab_1 + - pluggy=1.5.0=pyhd8ed1ab_1 + - ppl=1.2=h984aac9_1006 + - pplpy=0.8.9=py312hbd99ab9_1 + - primecount=7.9=hd600fc2_0 + - primecountpy=0.1.0=py312h8f0b210_4 + - primesieve=11.1=h2f0025b_0 + - prompt-toolkit=3.0.48=pyha770c72_1 + - psutil=6.1.0=py312hb2c0f52_0 + - pthread-stubs=0.4=h86ecc28_1002 + - ptyprocess=0.7.0=pyhd8ed1ab_1 + - pure_eval=0.2.3=pyhd8ed1ab_1 + - pycparser=2.22=pyh29332c3_1 + - pygments=2.18.0=pyhd8ed1ab_1 + - pyparsing=3.2.0=pyhd8ed1ab_2 + - pyproject-metadata=0.9.0=pyhd8ed1ab_1 + - pyside6=6.8.1=py312hdd999d0_0 + - pysocks=1.7.1=pyha55dd90_7 + - pytest=8.3.4=pyhd8ed1ab_1 + - pytest-xdist=3.6.1=pyhd8ed1ab_1 + - python=3.12.8=h1683364_1_cpython + - python-dateutil=2.9.0.post0=pyhff2d567_1 + - python-lrcalc=2.1=py312h6f74592_7 + - python_abi=3.12=5_cp312 + - pytz=2024.2=pyhd8ed1ab_1 + - pyzmq=26.2.0=py312h2427ae1_3 + - qd=2.3.22=h05efe27_1004 + - qhull=2020.2=h70be974_5 + - qt6-main=6.8.1=h0d3cc05_0 + - readline=8.2=h8fc344f_1 + - requests=2.32.3=pyhd8ed1ab_1 + - rw=0.9=h31becfc_2 + - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 + - sagemath-db-graphs=20210214=hd8ed1ab_0 + - sagemath-db-polytopes=20170220=1 + - scipy=1.14.1=py312hcbff3fa_2 + - setuptools=75.6.0=pyhff2d567_1 + - singular=4.4.0=hee12f27_1 + - six=1.17.0=pyhd8ed1ab_0 + - snowballstemmer=2.2.0=pyhd8ed1ab_0 + - soupsieve=2.5=pyhd8ed1ab_1 + - sphinx=8.1.3=pyhd8ed1ab_1 + - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_2 + - sphinx-inline-tabs=2023.4.21=pyhd8ed1ab_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_1 + - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 + - sqlite=3.47.2=h578a6b9_0 + - stack_data=0.6.3=pyhd8ed1ab_1 + - symmetrica=3.0.1=hd600fc2_0 + - sympow=2.023.6=h157afb5_3 + - sympy=1.13.3=pyh2585a3b_104 + - sysroot_linux-aarch64=2.17=h5b4a56d_18 + - tachyon=0.99b6=ha0bfc61_1002 + - tk=8.6.13=h194ca79_0 + - tomli=2.2.1=pyhd8ed1ab_1 + - tornado=6.4.2=py312h52516f5_0 + - traitlets=5.14.3=pyhd8ed1ab_1 + - typing_extensions=4.12.2=pyha770c72_1 + - tzdata=2024b=hc8b5060_0 + - unicodedata2=15.1.0=py312hb2c0f52_1 + - urllib3=2.2.3=pyhd8ed1ab_1 + - wayland=1.23.1=h698ed42_0 + - wcwidth=0.2.13=pyhd8ed1ab_1 + - wheel=0.45.1=pyhd8ed1ab_1 + - widgetsnbextension=4.0.13=pyhd8ed1ab_1 + - xcb-util=0.4.1=h5c728e9_2 + - xcb-util-cursor=0.1.5=h86ecc28_0 + - xcb-util-image=0.4.0=h5c728e9_2 + - xcb-util-keysyms=0.4.1=h5c728e9_0 + - xcb-util-renderutil=0.3.10=h5c728e9_0 + - xcb-util-wm=0.4.2=h5c728e9_0 + - xkeyboard-config=2.43=h86ecc28_0 + - xorg-libice=1.1.2=h86ecc28_0 + - xorg-libsm=1.2.5=h0808dbd_0 + - xorg-libx11=1.8.10=hca56bd8_1 + - xorg-libxau=1.0.12=h86ecc28_0 + - xorg-libxcomposite=0.4.6=h86ecc28_2 + - xorg-libxcursor=1.2.3=h86ecc28_0 + - xorg-libxdamage=1.1.6=h86ecc28_0 + - xorg-libxdmcp=1.1.5=h57736b2_0 + - xorg-libxext=1.3.6=h57736b2_0 + - xorg-libxfixes=6.0.1=h57736b2_0 + - xorg-libxi=1.8.2=h57736b2_0 + - xorg-libxrandr=1.5.4=h86ecc28_0 + - xorg-libxrender=0.9.12=h86ecc28_0 + - xorg-libxtst=1.2.5=h57736b2_3 + - xorg-libxxf86vm=1.1.6=h86ecc28_0 + - xz=5.6.3=h2dbfc1b_1 + - xz-gpl-tools=5.6.3=h2dbfc1b_1 + - xz-tools=5.6.3=h86ecc28_1 + - zeromq=4.3.5=h5efb499_7 + - zipp=3.21.0=pyhd8ed1ab_1 + - zlib=1.3.1=h86ecc28_2 + - zstandard=0.23.0=py312hb698573_1 + - zstd=1.5.6=h02f22dd_0 diff --git a/environment-3.12-linux.yml b/environment-3.12-linux.yml new file mode 100644 index 00000000000..7b2496e151e --- /dev/null +++ b/environment-3.12-linux.yml @@ -0,0 +1,339 @@ +name: sage-dev +# Generated by conda-lock. +# platform: linux-64 +# input_hash: 40be535db1c7eaa6a4654bde814ad7958eb5c8b150e3158a6897927158b3bd6f + +channels: + - conda-forge +dependencies: + - _libgcc_mutex=0.1=conda_forge + - _openmp_mutex=4.5=2_kmp_llvm + - alabaster=1.0.0=pyhd8ed1ab_1 + - alsa-lib=1.2.13=hb9d3cd8_0 + - arpack=3.9.1=nompi_h77f6705_101 + - asttokens=3.0.0=pyhd8ed1ab_1 + - autoconf=2.71=pl5321h2b4cb7a_1 + - automake=1.17=pl5321ha770c72_0 + - babel=2.16.0=pyhd8ed1ab_1 + - bdw-gc=8.0.6=h4bd325d_0 + - beautifulsoup4=4.12.3=pyha770c72_1 + - binutils=2.43=h4852527_2 + - binutils_impl_linux-64=2.43=h4bf12b8_2 + - binutils_linux-64=2.43=h4852527_2 + - blas=2.126=openblas + - blas-devel=3.9.0=26_linux64_openblas + - boost-cpp=1.85.0=h3c6214e_4 + - brial=1.2.12=pyh694c41f_3 + - brotli=1.1.0=hb9d3cd8_2 + - brotli-bin=1.1.0=hb9d3cd8_2 + - brotli-python=1.1.0=py312h2ec8cdc_2 + - bzip2=1.0.8=h4bc722e_7 + - c-ares=1.34.4=hb9d3cd8_0 + - c-compiler=1.8.0=h2b85faf_1 + - ca-certificates=2024.12.14=hbcca054_0 + - cairo=1.18.2=h3394656_1 + - cddlib=1!0.94m=h9202a9a_0 + - certifi=2024.12.14=pyhd8ed1ab_0 + - cffi=1.17.1=py312h06ac9bb_0 + - charset-normalizer=3.4.0=pyhd8ed1ab_1 + - cliquer=1.22=hd590300_1 + - colorama=0.4.6=pyhd8ed1ab_1 + - comm=0.2.2=pyhd8ed1ab_1 + - contourpy=1.3.1=py312h68727a3_0 + - conway-polynomials=0.10=pyhd8ed1ab_0 + - coverage=7.6.9=py312h178313f_0 + - cpython=3.12.8=py312hd8ed1ab_1 + - cxx-compiler=1.8.0=h1a2810e_1 + - cycler=0.12.1=pyhd8ed1ab_1 + - cypari2=2.1.5=py312h597db99_0 + - cyrus-sasl=2.1.27=h54b06d7_7 + - cysignals=1.11.2=py312h9d3d55b_3 + - cython=3.0.11=py312h8fd2918_3 + - dbus=1.13.6=h5008d03_3 + - debugpy=1.8.11=py312h2ec8cdc_0 + - decorator=5.1.1=pyhd8ed1ab_1 + - docutils=0.21.2=pyhd8ed1ab_1 + - double-conversion=3.3.0=h59595ed_0 + - ecl=24.5.10=h0f3afd4_0 + - eclib=20231212=h43e5eba_1 + - ecm=7.0.5=h9458935_0 + - exceptiongroup=1.2.2=pyhd8ed1ab_1 + - execnet=2.1.1=pyhd8ed1ab_1 + - executing=2.1.0=pyhd8ed1ab_1 + - expat=2.6.4=h5888daf_0 + - fflas-ffpack=2.5.0=h4f9960b_0 + - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 + - font-ttf-inconsolata=3.000=h77eed37_0 + - font-ttf-source-code-pro=2.038=h77eed37_0 + - font-ttf-ubuntu=0.83=h77eed37_3 + - fontconfig=2.15.0=h7e30c49_1 + - fonts-conda-ecosystem=1=0 + - fonts-conda-forge=1=0 + - fonttools=4.55.3=py312h178313f_0 + - fortran-compiler=1.8.0=h36df796_1 + - fplll=5.4.5=h384768b_0 + - fpylll=0.6.1=py312h59a3f1e_0 + - freetype=2.12.1=h267a509_2 + - furo=2024.8.6=pyhd8ed1ab_1 + - gap-core=4.14.0=h3b03731_1 + - gap-defaults=4.14.0=ha770c72_1 + - gcc=13.3.0=h9576a4e_1 + - gcc_impl_linux-64=13.3.0=hfea6d02_1 + - gcc_linux-64=13.3.0=hc28eda2_7 + - gf2x=1.3.0=h55551d5_3 + - gfan=0.6.2=hb86e20a_1003 + - gfortran=13.3.0=h9576a4e_1 + - gfortran_impl_linux-64=13.3.0=h10434e7_1 + - gfortran_linux-64=13.3.0=hb919d3a_7 + - giac=1.9.0.21=h673759e_1 + - givaro=4.2.0=hb789bce_0 + - glpk=5.0=h445213a_0 + - gmp=6.3.0=hac33072_2 + - gmpy2=2.1.5=py312h7201bc8_3 + - graphite2=1.3.13=h59595ed_1003 + - gsl=2.7=he838d99_0 + - gxx=13.3.0=h9576a4e_1 + - gxx_impl_linux-64=13.3.0=hdbfa832_1 + - gxx_linux-64=13.3.0=h6834431_7 + - h2=4.1.0=pyhd8ed1ab_1 + - harfbuzz=9.0.0=hda332d3_1 + - hpack=4.0.0=pyhd8ed1ab_1 + - hyperframe=6.0.1=pyhd8ed1ab_1 + - icu=75.1=he02047a_0 + - idna=3.10=pyhd8ed1ab_1 + - igraph=0.10.15=he44f51b_1 + - imagesize=1.4.1=pyhd8ed1ab_0 + - iml=1.0.5=h623f65a_1004 + - importlib-metadata=8.5.0=pyha770c72_1 + - iniconfig=2.0.0=pyhd8ed1ab_1 + - ipykernel=6.29.5=pyh3099207_0 + - ipython=8.30.0=pyh707e725_0 + - ipywidgets=8.1.5=pyhd8ed1ab_1 + - jedi=0.19.2=pyhd8ed1ab_1 + - jinja2=3.1.4=pyhd8ed1ab_1 + - jupyter_client=8.6.3=pyhd8ed1ab_1 + - jupyter_core=5.7.2=pyh31011fe_1 + - jupyterlab_widgets=3.0.13=pyhd8ed1ab_1 + - kernel-headers_linux-64=3.10.0=he073ed8_18 + - keyutils=1.6.1=h166bdaf_0 + - kiwisolver=1.4.7=py312h68727a3_0 + - krb5=1.21.3=h659f571_0 + - lcalc=2.0.5=h5aac1b6_2 + - lcms2=2.16=hb7c19ff_0 + - ld_impl_linux-64=2.43=h712a8e2_2 + - lerc=4.0.0=h27087fc_0 + - libblas=3.9.0=26_linux64_openblas + - libboost=1.85.0=h0ccab89_4 + - libboost-devel=1.85.0=h00ab1b0_4 + - libboost-headers=1.85.0=ha770c72_4 + - libbraiding=1.3=h5888daf_0 + - libbrial=1.2.12=h76af697_3 + - libbrotlicommon=1.1.0=hb9d3cd8_2 + - libbrotlidec=1.1.0=hb9d3cd8_2 + - libbrotlienc=1.1.0=hb9d3cd8_2 + - libcblas=3.9.0=26_linux64_openblas + - libclang-cpp19.1=19.1.6=default_hb5137d0_0 + - libclang13=19.1.6=default_h9c6a7e4_0 + - libcups=2.3.3=h4637d8d_4 + - libcurl=8.11.1=h332b0f4_0 + - libdeflate=1.23=h4ddbbb0_0 + - libdrm=2.4.124=hb9d3cd8_0 + - libedit=3.1.20191231=he28a2e2_2 + - libegl=1.7.0=ha4b6fd6_2 + - libev=4.33=hd590300_2 + - libexpat=2.6.4=h5888daf_0 + - libffi=3.4.2=h7f98852_5 + - libflint=3.1.2=h6fb9888_101 + - libgcc=14.2.0=h77fa898_1 + - libgcc-devel_linux-64=13.3.0=h84ea5a7_101 + - libgcc-ng=14.2.0=h69a702a_1 + - libgd=2.3.3=hd3e95f3_10 + - libgfortran=14.2.0=h69a702a_1 + - libgfortran-ng=14.2.0=h69a702a_1 + - libgfortran5=14.2.0=hd5240d6_1 + - libgl=1.7.0=ha4b6fd6_2 + - libglib=2.82.2=h2ff4ddf_0 + - libglvnd=1.7.0=ha4b6fd6_2 + - libglx=1.7.0=ha4b6fd6_2 + - libgomp=14.2.0=h77fa898_1 + - libhomfly=1.02r6=hd590300_1 + - libiconv=1.17=hd590300_2 + - libjpeg-turbo=3.0.0=hd590300_1 + - liblapack=3.9.0=26_linux64_openblas + - liblapacke=3.9.0=26_linux64_openblas + - libllvm19=19.1.6=ha7bfdaf_0 + - liblzma=5.6.3=hb9d3cd8_1 + - liblzma-devel=5.6.3=hb9d3cd8_1 + - libnghttp2=1.64.0=h161d5f1_0 + - libnsl=2.0.1=hd590300_0 + - libntlm=1.4=h7f98852_1002 + - libopenblas=0.3.28=pthreads_h94d23a6_1 + - libopengl=1.7.0=ha4b6fd6_2 + - libpciaccess=0.18=hd590300_0 + - libpng=1.6.44=hadc24fc_0 + - libpq=17.2=h3b95a9b_1 + - libsanitizer=13.3.0=heb74ff8_1 + - libsodium=1.0.20=h4ab18f5_0 + - libsqlite=3.47.2=hee588c1_0 + - libssh2=1.11.1=hf672d98_0 + - libstdcxx=14.2.0=hc0a3c3a_1 + - libstdcxx-devel_linux-64=13.3.0=h84ea5a7_101 + - libstdcxx-ng=14.2.0=h4852527_1 + - libtiff=4.7.0=hd9ff511_3 + - libuuid=2.38.1=h0b41bf4_0 + - libwebp-base=1.4.0=hd590300_0 + - libxcb=1.17.0=h8a09558_0 + - libxcrypt=4.4.36=hd590300_1 + - libxkbcommon=1.7.0=h2c5496b_1 + - libxml2=2.13.5=h8d12d68_1 + - libxslt=1.1.39=h76b75d6_0 + - libzlib=1.3.1=hb9d3cd8_2 + - linbox=1.7.0=h7298d08_1 + - llvm-openmp=19.1.6=h024ca30_0 + - lrcalc=2.1=h5888daf_7 + - m4=1.4.18=h516909a_1001 + - m4ri=20140914=hae5d5c5_1006 + - m4rie=20200125=h051dbe0_0 + - markupsafe=3.0.2=py312h178313f_1 + - matplotlib=3.10.0=py312h7900ff3_0 + - matplotlib-base=3.10.0=py312hd3ec401_0 + - matplotlib-inline=0.1.7=pyhd8ed1ab_1 + - maxima=5.47.0=h75482ee_3 + - memory-allocator=0.1.3=py312h66e93f0_1 + - meson=1.6.1=pyhd8ed1ab_0 + - meson-python=0.17.1=pyh70fd9c4_1 + - mpc=1.3.1=h24ddda3_1 + - mpfi=1.5.4=h9f54685_1001 + - mpfr=4.2.1=h90cbb55_3 + - mpmath=1.3.0=pyhd8ed1ab_1 + - munkres=1.1.4=pyh9f0ad1d_0 + - mysql-common=9.0.1=h266115a_3 + - mysql-libs=9.0.1=he0572af_3 + - nauty=2.8.8=hd590300_1 + - ncurses=6.5=he02047a_1 + - nest-asyncio=1.6.0=pyhd8ed1ab_1 + - networkx=3.4.2=pyh267e887_2 + - ninja=1.12.1=h297d8ca_0 + - ntl=11.4.3=hef3c4d3_1 + - numpy=1.26.4=py312heda63a1_0 + - openblas=0.3.28=pthreads_h6ec200e_1 + - openjpeg=2.5.3=h5fbd93e_0 + - openldap=2.6.9=he970967_0 + - openssl=3.4.0=hb9d3cd8_0 + - packaging=24.2=pyhd8ed1ab_2 + - palp=2.20=h36c2ea0_0 + - pari=2.15.5=h4d4ae9b_2_pthread + - pari-elldata=0.0.20161017=0 + - pari-galdata=0.0.20180411=0 + - pari-seadata=0.0.20090618=0 + - pari-seadata-small=0.0.20090618=0 + - parso=0.8.4=pyhd8ed1ab_1 + - pcre2=10.44=hba22ea6_2 + - perl=5.32.1=7_hd590300_perl5 + - pexpect=4.9.0=pyhd8ed1ab_1 + - pickleshare=0.7.5=pyhd8ed1ab_1004 + - pillow=11.0.0=py312h7b63e92_0 + - pip=24.3.1=pyh8b19718_2 + - pixman=0.44.2=h29eaf8c_0 + - pkg-config=0.29.2=h4bc722e_1009 + - pkgconfig=1.5.5=pyhd8ed1ab_5 + - planarity=3.0.2.0=hd590300_0 + - platformdirs=4.3.6=pyhd8ed1ab_1 + - pluggy=1.5.0=pyhd8ed1ab_1 + - ppl=1.2=h6ec01c2_1006 + - pplpy=0.8.9=py312h12a6c6f_1 + - primecount=7.9=hcb278e6_0 + - primecountpy=0.1.0=py312h8572e83_4 + - primesieve=11.1=h59595ed_0 + - prompt-toolkit=3.0.48=pyha770c72_1 + - psutil=6.1.0=py312h66e93f0_0 + - pthread-stubs=0.4=hb9d3cd8_1002 + - ptyprocess=0.7.0=pyhd8ed1ab_1 + - pure_eval=0.2.3=pyhd8ed1ab_1 + - pycparser=2.22=pyh29332c3_1 + - pygments=2.18.0=pyhd8ed1ab_1 + - pyparsing=3.2.0=pyhd8ed1ab_2 + - pyproject-metadata=0.9.0=pyhd8ed1ab_1 + - pyside6=6.8.1=py312h91f0f75_0 + - pysocks=1.7.1=pyha55dd90_7 + - pytest=8.3.4=pyhd8ed1ab_1 + - pytest-xdist=3.6.1=pyhd8ed1ab_1 + - python=3.12.8=h9e4cc4f_1_cpython + - python-dateutil=2.9.0.post0=pyhff2d567_1 + - python-lrcalc=2.1=py312h2ec8cdc_7 + - python_abi=3.12=5_cp312 + - pytz=2024.2=pyhd8ed1ab_1 + - pyzmq=26.2.0=py312hbf22597_3 + - qd=2.3.22=h2cc385e_1004 + - qhull=2020.2=h434a139_5 + - qt6-main=6.8.1=h9d28a51_0 + - readline=8.2=h8228510_1 + - requests=2.32.3=pyhd8ed1ab_1 + - rw=0.9=hd590300_2 + - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 + - sagemath-db-graphs=20210214=hd8ed1ab_0 + - sagemath-db-polytopes=20170220=1 + - scipy=1.14.1=py312h62794b6_2 + - setuptools=75.6.0=pyhff2d567_1 + - singular=4.4.0=hc910cb2_1 + - six=1.17.0=pyhd8ed1ab_0 + - snowballstemmer=2.2.0=pyhd8ed1ab_0 + - soupsieve=2.5=pyhd8ed1ab_1 + - sphinx=8.1.3=pyhd8ed1ab_1 + - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_2 + - sphinx-inline-tabs=2023.4.21=pyhd8ed1ab_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_1 + - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 + - sqlite=3.47.2=h9eae976_0 + - stack_data=0.6.3=pyhd8ed1ab_1 + - symmetrica=3.0.1=hcb278e6_0 + - sympow=2.023.6=hc6ab17c_3 + - sympy=1.13.3=pyh2585a3b_104 + - sysroot_linux-64=2.17=h4a8ded7_18 + - tachyon=0.99b6=hba7d16a_1002 + - tk=8.6.13=noxft_h4845f30_101 + - tomli=2.2.1=pyhd8ed1ab_1 + - tornado=6.4.2=py312h66e93f0_0 + - traitlets=5.14.3=pyhd8ed1ab_1 + - typing_extensions=4.12.2=pyha770c72_1 + - tzdata=2024b=hc8b5060_0 + - unicodedata2=15.1.0=py312h66e93f0_1 + - urllib3=2.2.3=pyhd8ed1ab_1 + - wayland=1.23.1=h3e06ad9_0 + - wcwidth=0.2.13=pyhd8ed1ab_1 + - wheel=0.45.1=pyhd8ed1ab_1 + - widgetsnbextension=4.0.13=pyhd8ed1ab_1 + - xcb-util=0.4.1=hb711507_2 + - xcb-util-cursor=0.1.5=hb9d3cd8_0 + - xcb-util-image=0.4.0=hb711507_2 + - xcb-util-keysyms=0.4.1=hb711507_0 + - xcb-util-renderutil=0.3.10=hb711507_0 + - xcb-util-wm=0.4.2=hb711507_0 + - xkeyboard-config=2.43=hb9d3cd8_0 + - xorg-libice=1.1.2=hb9d3cd8_0 + - xorg-libsm=1.2.5=he73a12e_0 + - xorg-libx11=1.8.10=h4f16b4b_1 + - xorg-libxau=1.0.12=hb9d3cd8_0 + - xorg-libxcomposite=0.4.6=hb9d3cd8_2 + - xorg-libxcursor=1.2.3=hb9d3cd8_0 + - xorg-libxdamage=1.1.6=hb9d3cd8_0 + - xorg-libxdmcp=1.1.5=hb9d3cd8_0 + - xorg-libxext=1.3.6=hb9d3cd8_0 + - xorg-libxfixes=6.0.1=hb9d3cd8_0 + - xorg-libxi=1.8.2=hb9d3cd8_0 + - xorg-libxrandr=1.5.4=hb9d3cd8_0 + - xorg-libxrender=0.9.12=hb9d3cd8_0 + - xorg-libxtst=1.2.5=hb9d3cd8_3 + - xorg-libxxf86vm=1.1.6=hb9d3cd8_0 + - xz=5.6.3=hbcc6ac9_1 + - xz-gpl-tools=5.6.3=hbcc6ac9_1 + - xz-tools=5.6.3=hb9d3cd8_1 + - zeromq=4.3.5=h3b0a872_7 + - zipp=3.21.0=pyhd8ed1ab_1 + - zlib=1.3.1=hb9d3cd8_2 + - zstandard=0.23.0=py312hef9b889_1 + - zstd=1.5.6=ha6fb4c9_0 diff --git a/environment-3.12-macos-x86_64.yml b/environment-3.12-macos-x86_64.yml new file mode 100644 index 00000000000..4fccaefb570 --- /dev/null +++ b/environment-3.12-macos-x86_64.yml @@ -0,0 +1,292 @@ +name: sage-dev +# Generated by conda-lock. +# platform: osx-64 +# input_hash: 5888a68a5088012ad0dffd6db00812a4e3c24a060219dc73fd975f246c404337 + +channels: + - conda-forge +dependencies: + - alabaster=1.0.0=pyhd8ed1ab_1 + - appnope=0.1.4=pyhd8ed1ab_1 + - arpack=3.9.1=nompi_hf81eadf_101 + - asttokens=3.0.0=pyhd8ed1ab_1 + - autoconf=2.71=pl5321hed12c24_1 + - automake=1.17=pl5321h694c41f_0 + - babel=2.16.0=pyhd8ed1ab_1 + - bdw-gc=8.0.6=h940c156_0 + - beautifulsoup4=4.12.3=pyha770c72_1 + - blas=2.126=openblas + - blas-devel=3.9.0=26_osx64_openblas + - boost-cpp=1.85.0=hfcd56d9_4 + - brial=1.2.12=pyh694c41f_3 + - brotli=1.1.0=h00291cd_2 + - brotli-bin=1.1.0=h00291cd_2 + - brotli-python=1.1.0=py312h5861a67_2 + - bzip2=1.0.8=hfdf4475_7 + - c-ares=1.34.4=hf13058a_0 + - c-compiler=1.8.0=hfc4bf79_1 + - ca-certificates=2024.12.14=h8857fd0_0 + - cctools=1010.6=h5b2de21_2 + - cctools_osx-64=1010.6=hea4301f_2 + - cddlib=1!0.94m=h0f52abe_0 + - certifi=2024.12.14=pyhd8ed1ab_0 + - cffi=1.17.1=py312hf857d28_0 + - charset-normalizer=3.4.0=pyhd8ed1ab_1 + - clang=17.0.6=default_he371ed4_7 + - clang-17=17.0.6=default_hb173f14_7 + - clang_impl_osx-64=17.0.6=h1af8efd_23 + - clang_osx-64=17.0.6=h7e5c614_23 + - clangxx=17.0.6=default_he371ed4_7 + - clangxx_impl_osx-64=17.0.6=hc3430b7_23 + - clangxx_osx-64=17.0.6=h7e5c614_23 + - cliquer=1.22=h10d778d_1 + - colorama=0.4.6=pyhd8ed1ab_1 + - comm=0.2.2=pyhd8ed1ab_1 + - compiler-rt=17.0.6=h1020d70_2 + - compiler-rt_osx-64=17.0.6=hf2b8a54_2 + - contourpy=1.3.1=py312hc47a885_0 + - conway-polynomials=0.10=pyhd8ed1ab_0 + - coverage=7.6.9=py312h3520af0_0 + - cpython=3.12.8=py312hd8ed1ab_1 + - cxx-compiler=1.8.0=h385f146_1 + - cycler=0.12.1=pyhd8ed1ab_1 + - cypari2=2.1.5=py312h88009e3_0 + - cysignals=1.11.2=py312h0c1623b_3 + - cython=3.0.11=py312h6891801_3 + - debugpy=1.8.11=py312haafddd8_0 + - decorator=5.1.1=pyhd8ed1ab_1 + - docutils=0.21.2=pyhd8ed1ab_1 + - ecl=24.5.10=h56bac16_0 + - eclib=20231212=h960c116_1 + - ecm=7.0.5=h4f6b447_0 + - exceptiongroup=1.2.2=pyhd8ed1ab_1 + - execnet=2.1.1=pyhd8ed1ab_1 + - executing=2.1.0=pyhd8ed1ab_1 + - expat=2.6.4=h240833e_0 + - fflas-ffpack=2.5.0=h5898d61_0 + - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 + - font-ttf-inconsolata=3.000=h77eed37_0 + - font-ttf-source-code-pro=2.038=h77eed37_0 + - font-ttf-ubuntu=0.83=h77eed37_3 + - fontconfig=2.15.0=h37eeddb_1 + - fonts-conda-ecosystem=1=0 + - fonts-conda-forge=1=0 + - fonttools=4.55.3=py312h3520af0_0 + - fortran-compiler=1.8.0=h33d1f46_1 + - fplll=5.4.5=hb7981ad_0 + - fpylll=0.6.1=py312ha9f3631_0 + - freetype=2.12.1=h60636b9_2 + - furo=2024.8.6=pyhd8ed1ab_1 + - gap-core=4.14.0=hb9686a1_1 + - gap-defaults=4.14.0=h694c41f_1 + - gettext=0.22.5=hdfe23c8_3 + - gettext-tools=0.22.5=hdfe23c8_3 + - gf2x=1.3.0=h35ac7d9_3 + - gfan=0.6.2=hd793b56_1003 + - gfortran=13.2.0=h2c809b3_1 + - gfortran_impl_osx-64=13.2.0=h2bc304d_3 + - gfortran_osx-64=13.2.0=h18f7dce_1 + - giac=1.9.0.21=h92f3f65_1 + - givaro=4.2.0=h1b3d6f7_0 + - glpk=5.0=h3cb5acd_0 + - gmp=6.3.0=hf036a51_2 + - gmpy2=2.1.5=py312h068713c_3 + - gsl=2.7=h93259b0_0 + - h2=4.1.0=pyhd8ed1ab_1 + - hpack=4.0.0=pyhd8ed1ab_1 + - hyperframe=6.0.1=pyhd8ed1ab_1 + - icu=75.1=h120a0e1_0 + - idna=3.10=pyhd8ed1ab_1 + - igraph=0.10.15=h5479cbe_1 + - imagesize=1.4.1=pyhd8ed1ab_0 + - iml=1.0.5=h61918c1_1004 + - importlib-metadata=8.5.0=pyha770c72_1 + - iniconfig=2.0.0=pyhd8ed1ab_1 + - ipykernel=6.29.5=pyh57ce528_0 + - ipython=8.30.0=pyh707e725_0 + - ipywidgets=8.1.5=pyhd8ed1ab_1 + - isl=0.26=imath32_h2e86a7b_101 + - jedi=0.19.2=pyhd8ed1ab_1 + - jinja2=3.1.4=pyhd8ed1ab_1 + - jupyter_client=8.6.3=pyhd8ed1ab_1 + - jupyter_core=5.7.2=pyh31011fe_1 + - jupyterlab_widgets=3.0.13=pyhd8ed1ab_1 + - kiwisolver=1.4.7=py312hc5c4d5f_0 + - krb5=1.21.3=h37d8d59_0 + - lcalc=2.0.5=h547a6ed_2 + - lcms2=2.16=ha2f27b4_0 + - ld64=951.9=h0a3eb4e_2 + - ld64_osx-64=951.9=h5ffbe8e_2 + - lerc=4.0.0=hb486fe8_0 + - libasprintf=0.22.5=hdfe23c8_3 + - libasprintf-devel=0.22.5=hdfe23c8_3 + - libblas=3.9.0=26_osx64_openblas + - libboost=1.85.0=hcca3243_4 + - libboost-devel=1.85.0=h2b186f8_4 + - libboost-headers=1.85.0=h694c41f_4 + - libbraiding=1.3=h240833e_0 + - libbrial=1.2.12=h81e9653_3 + - libbrotlicommon=1.1.0=h00291cd_2 + - libbrotlidec=1.1.0=h00291cd_2 + - libbrotlienc=1.1.0=h00291cd_2 + - libcblas=3.9.0=26_osx64_openblas + - libclang-cpp17=17.0.6=default_hb173f14_7 + - libcurl=8.11.1=h5dec5d8_0 + - libcxx=19.1.6=hf95d169_1 + - libcxx-devel=17.0.6=h8f8a49f_6 + - libdeflate=1.23=he65b83e_0 + - libedit=3.1.20191231=h0678c8f_2 + - libev=4.33=h10d778d_2 + - libexpat=2.6.4=h240833e_0 + - libffi=3.4.2=h0d85af4_5 + - libflint=3.1.2=h1d27844_101 + - libgd=2.3.3=h2e77e4f_10 + - libgettextpo=0.22.5=hdfe23c8_3 + - libgettextpo-devel=0.22.5=hdfe23c8_3 + - libgfortran=5.0.0=13_2_0_h97931a8_3 + - libgfortran-devel_osx-64=13.2.0=h80d4556_3 + - libgfortran5=13.2.0=h2873a65_3 + - libhomfly=1.02r6=h10d778d_1 + - libiconv=1.17=hd75f5a5_2 + - libintl=0.22.5=hdfe23c8_3 + - libintl-devel=0.22.5=hdfe23c8_3 + - libjpeg-turbo=3.0.0=h0dc2134_1 + - liblapack=3.9.0=26_osx64_openblas + - liblapacke=3.9.0=26_osx64_openblas + - libllvm17=17.0.6=hbedff68_1 + - liblzma=5.6.3=hd471939_1 + - liblzma-devel=5.6.3=hd471939_1 + - libnghttp2=1.64.0=hc7306c3_0 + - libopenblas=0.3.28=openmp_hbf64a52_1 + - libpng=1.6.44=h4b8f8c9_0 + - libsodium=1.0.20=hfdf4475_0 + - libsqlite=3.47.2=hdb6dae5_0 + - libssh2=1.11.1=h3dc7d44_0 + - libtiff=4.7.0=hb77a491_3 + - libwebp-base=1.4.0=h10d778d_0 + - libxcb=1.17.0=hf1f96e2_0 + - libxml2=2.13.5=hebb159f_1 + - libzlib=1.3.1=hd23fc13_2 + - linbox=1.7.0=h9325161_1 + - llvm-openmp=19.1.6=ha54dae1_0 + - llvm-tools=17.0.6=hbedff68_1 + - lrcalc=2.1=hac325c4_7 + - m4=1.4.18=haf1e3a3_1001 + - m4ri=20140914=hd82a5f3_1006 + - m4rie=20200125=hd82a5f3_0 + - markupsafe=3.0.2=py312h3520af0_1 + - matplotlib=3.10.0=py312hb401068_0 + - matplotlib-base=3.10.0=py312h535dea3_0 + - matplotlib-inline=0.1.7=pyhd8ed1ab_1 + - maxima=5.47.0=h3080a4d_3 + - memory-allocator=0.1.3=py312hb553811_1 + - meson=1.6.1=pyhd8ed1ab_0 + - meson-python=0.17.1=pyh70fd9c4_1 + - mpc=1.3.1=h9d8efa1_1 + - mpfi=1.5.4=h52b28e3_1001 + - mpfr=4.2.1=haed47dc_3 + - mpmath=1.3.0=pyhd8ed1ab_1 + - munkres=1.1.4=pyh9f0ad1d_0 + - nauty=2.8.8=h10d778d_1 + - ncurses=6.5=hf036a51_1 + - nest-asyncio=1.6.0=pyhd8ed1ab_1 + - networkx=3.4.2=pyh267e887_2 + - ninja=1.12.1=h3c5361c_0 + - ntl=11.4.3=h0ab3c2f_1 + - numpy=1.26.4=py312he3a82b2_0 + - openblas=0.3.28=openmp_h30af337_1 + - openjpeg=2.5.3=h7fd6d84_0 + - openssl=3.4.0=hd471939_0 + - packaging=24.2=pyhd8ed1ab_2 + - palp=2.20=hbcb3906_0 + - pari=2.15.5=h7ba67ff_2_pthread + - pari-elldata=0.0.20161017=0 + - pari-galdata=0.0.20180411=0 + - pari-seadata=0.0.20090618=0 + - pari-seadata-small=0.0.20090618=0 + - parso=0.8.4=pyhd8ed1ab_1 + - perl=5.32.1=7_h10d778d_perl5 + - pexpect=4.9.0=pyhd8ed1ab_1 + - pickleshare=0.7.5=pyhd8ed1ab_1004 + - pillow=11.0.0=py312h66fe14f_0 + - pip=24.3.1=pyh8b19718_2 + - pkg-config=0.29.2=hf7e621a_1009 + - pkgconfig=1.5.5=pyhd8ed1ab_5 + - planarity=3.0.2.0=h10d778d_0 + - platformdirs=4.3.6=pyhd8ed1ab_1 + - pluggy=1.5.0=pyhd8ed1ab_1 + - ppl=1.2=ha60d53e_1006 + - pplpy=0.8.9=py312hb4417ad_1 + - primecount=7.6=ha894c9a_0 + - primecountpy=0.1.0=py312h49ebfd2_4 + - primesieve=11.0=hf0c8a7f_0 + - prompt-toolkit=3.0.48=pyha770c72_1 + - psutil=6.1.0=py312h3d0f464_0 + - pthread-stubs=0.4=h00291cd_1002 + - ptyprocess=0.7.0=pyhd8ed1ab_1 + - pure_eval=0.2.3=pyhd8ed1ab_1 + - pycparser=2.22=pyh29332c3_1 + - pygments=2.18.0=pyhd8ed1ab_1 + - pyparsing=3.2.0=pyhd8ed1ab_2 + - pyproject-metadata=0.9.0=pyhd8ed1ab_1 + - pysocks=1.7.1=pyha55dd90_7 + - pytest=8.3.4=pyhd8ed1ab_1 + - pytest-xdist=3.6.1=pyhd8ed1ab_1 + - python=3.12.8=h9ccd52b_1_cpython + - python-dateutil=2.9.0.post0=pyhff2d567_1 + - python-lrcalc=2.1=py312h5861a67_7 + - python_abi=3.12=5_cp312 + - pytz=2024.2=pyhd8ed1ab_1 + - pyzmq=26.2.0=py312h1060d5c_3 + - qd=2.3.22=h2beb688_1004 + - qhull=2020.2=h3c5361c_5 + - readline=8.2=h9e318b2_1 + - requests=2.32.3=pyhd8ed1ab_1 + - rw=0.9=h10d778d_2 + - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 + - sagemath-db-graphs=20210214=hd8ed1ab_0 + - sagemath-db-polytopes=20170220=1 + - scipy=1.14.1=py312h3b0f538_2 + - setuptools=75.6.0=pyhff2d567_1 + - sigtool=0.1.3=h88f4db0_0 + - singular=4.4.0=h604985e_1 + - six=1.17.0=pyhd8ed1ab_0 + - snowballstemmer=2.2.0=pyhd8ed1ab_0 + - soupsieve=2.5=pyhd8ed1ab_1 + - sphinx=8.1.3=pyhd8ed1ab_1 + - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_2 + - sphinx-inline-tabs=2023.4.21=pyhd8ed1ab_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_1 + - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 + - sqlite=3.47.2=h2e4c9dc_0 + - stack_data=0.6.3=pyhd8ed1ab_1 + - symmetrica=3.0.1=hf0c8a7f_0 + - sympow=2.023.6=h115ba6a_3 + - sympy=1.13.3=pyh2585a3b_104 + - tachyon=0.99b6=h3a1d103_1002 + - tapi=1300.6.5=h390ca13_0 + - tk=8.6.13=h1abcd95_1 + - tomli=2.2.1=pyhd8ed1ab_1 + - tornado=6.4.2=py312h01d7ebd_0 + - traitlets=5.14.3=pyhd8ed1ab_1 + - typing_extensions=4.12.2=pyha770c72_1 + - tzdata=2024b=hc8b5060_0 + - unicodedata2=15.1.0=py312h3d0f464_1 + - urllib3=2.2.3=pyhd8ed1ab_1 + - wcwidth=0.2.13=pyhd8ed1ab_1 + - wheel=0.45.1=pyhd8ed1ab_1 + - widgetsnbextension=4.0.13=pyhd8ed1ab_1 + - xorg-libxau=1.0.12=h6e16a3a_0 + - xorg-libxdmcp=1.1.5=h00291cd_0 + - xz=5.6.3=h357f2ed_1 + - xz-gpl-tools=5.6.3=h357f2ed_1 + - xz-tools=5.6.3=hd471939_1 + - zeromq=4.3.5=h7130eaa_7 + - zipp=3.21.0=pyhd8ed1ab_1 + - zlib=1.3.1=hd23fc13_2 + - zstandard=0.23.0=py312h7122b0e_1 + - zstd=1.5.6=h915ae27_0 diff --git a/environment-3.12-macos.yml b/environment-3.12-macos.yml new file mode 100644 index 00000000000..957da365df9 --- /dev/null +++ b/environment-3.12-macos.yml @@ -0,0 +1,294 @@ +name: sage-dev +# Generated by conda-lock. +# platform: osx-arm64 +# input_hash: 0c152106e1e870088723e57e0bd27be66ce0a8f2488067475849ebf869659bbe + +channels: + - conda-forge +dependencies: + - alabaster=1.0.0=pyhd8ed1ab_1 + - appnope=0.1.4=pyhd8ed1ab_1 + - arpack=3.9.1=nompi_h593882a_101 + - asttokens=3.0.0=pyhd8ed1ab_1 + - autoconf=2.71=pl5321hcd07c0c_1 + - automake=1.17=pl5321hce30654_0 + - babel=2.16.0=pyhd8ed1ab_1 + - bdw-gc=8.0.6=hc021e02_0 + - beautifulsoup4=4.12.3=pyha770c72_1 + - blas=2.126=openblas + - blas-devel=3.9.0=26_osxarm64_openblas + - boost-cpp=1.85.0=h103c1d6_4 + - brial=1.2.12=pyh694c41f_3 + - brotli=1.1.0=hd74edd7_2 + - brotli-bin=1.1.0=hd74edd7_2 + - brotli-python=1.1.0=py312hde4cb15_2 + - bzip2=1.0.8=h99b78c6_7 + - c-ares=1.34.4=h5505292_0 + - c-compiler=1.8.0=hf48404e_1 + - ca-certificates=2024.12.14=hf0a4a13_0 + - cctools=1010.6=hf67d63f_2 + - cctools_osx-arm64=1010.6=h623e0ac_2 + - cddlib=1!0.94m=h6d7a090_0 + - certifi=2024.12.14=pyhd8ed1ab_0 + - cffi=1.17.1=py312h0fad829_0 + - charset-normalizer=3.4.0=pyhd8ed1ab_1 + - clang=17.0.6=default_h360f5da_7 + - clang-17=17.0.6=default_h146c034_7 + - clang_impl_osx-arm64=17.0.6=he47c785_23 + - clang_osx-arm64=17.0.6=h07b0088_23 + - clangxx=17.0.6=default_h360f5da_7 + - clangxx_impl_osx-arm64=17.0.6=h50f59cd_23 + - clangxx_osx-arm64=17.0.6=h07b0088_23 + - cliquer=1.22=h93a5062_1 + - colorama=0.4.6=pyhd8ed1ab_1 + - comm=0.2.2=pyhd8ed1ab_1 + - compiler-rt=17.0.6=h856b3c1_2 + - compiler-rt_osx-arm64=17.0.6=h832e737_2 + - contourpy=1.3.1=py312hb23fbb9_0 + - conway-polynomials=0.10=pyhd8ed1ab_0 + - coverage=7.6.9=py312h998013c_0 + - cpython=3.12.8=py312hd8ed1ab_1 + - cxx-compiler=1.8.0=h18dbf2f_1 + - cycler=0.12.1=pyhd8ed1ab_1 + - cypari2=2.1.5=py312h2da97d0_0 + - cysignals=1.11.2=py312heab4d4f_3 + - cython=3.0.11=py312hde4cb15_2 + - debugpy=1.8.11=py312hd8f9ff3_0 + - decorator=5.1.1=pyhd8ed1ab_1 + - docutils=0.21.2=pyhd8ed1ab_1 + - ecl=23.9.9=h1d9728a_0 + - eclib=20231212=h3d50bd9_1 + - ecm=7.0.5=h41d338b_0 + - exceptiongroup=1.2.2=pyhd8ed1ab_1 + - execnet=2.1.1=pyhd8ed1ab_1 + - executing=2.1.0=pyhd8ed1ab_1 + - expat=2.6.4=h286801f_0 + - fflas-ffpack=2.5.0=h4bc3318_0 + - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 + - font-ttf-inconsolata=3.000=h77eed37_0 + - font-ttf-source-code-pro=2.038=h77eed37_0 + - font-ttf-ubuntu=0.83=h77eed37_3 + - fontconfig=2.15.0=h1383a14_1 + - fonts-conda-ecosystem=1=0 + - fonts-conda-forge=1=0 + - fonttools=4.55.3=py312h998013c_0 + - fortran-compiler=1.8.0=hc3477c4_1 + - fplll=5.4.5=hb7d509d_0 + - fpylll=0.6.1=py312h381bdd1_0 + - freetype=2.12.1=hadb7bae_2 + - furo=2024.8.6=pyhd8ed1ab_1 + - gap-core=4.14.0=h25f1785_1 + - gap-defaults=4.14.0=hce30654_1 + - gettext=0.22.5=h8414b35_3 + - gettext-tools=0.22.5=h8414b35_3 + - gf2x=1.3.0=hf8f8af4_3 + - gfan=0.6.2=hec08f5c_1003 + - gfortran=13.2.0=h1ca8e4b_1 + - gfortran_impl_osx-arm64=13.2.0=h252ada1_3 + - gfortran_osx-arm64=13.2.0=h57527a5_1 + - giac=1.9.0.21=h1c96721_1 + - givaro=4.2.0=h018886a_0 + - glpk=5.0=h6d7a090_0 + - gmp=6.3.0=h7bae524_2 + - gmpy2=2.1.5=py312h524cf62_3 + - gsl=2.7=h6e638da_0 + - h2=4.1.0=pyhd8ed1ab_1 + - hpack=4.0.0=pyhd8ed1ab_1 + - hyperframe=6.0.1=pyhd8ed1ab_1 + - icu=75.1=hfee45f7_0 + - idna=3.10=pyhd8ed1ab_1 + - igraph=0.10.15=h3fe6531_1 + - imagesize=1.4.1=pyhd8ed1ab_0 + - iml=1.0.5=hd73f12c_1004 + - importlib-metadata=8.5.0=pyha770c72_1 + - iniconfig=2.0.0=pyhd8ed1ab_1 + - ipykernel=6.29.5=pyh57ce528_0 + - ipython=8.30.0=pyh707e725_0 + - ipywidgets=8.1.5=pyhd8ed1ab_1 + - isl=0.26=imath32_h347afa1_101 + - jedi=0.19.2=pyhd8ed1ab_1 + - jinja2=3.1.4=pyhd8ed1ab_1 + - jupyter_client=8.6.3=pyhd8ed1ab_1 + - jupyter_core=5.7.2=pyh31011fe_1 + - jupyterlab_widgets=3.0.13=pyhd8ed1ab_1 + - kiwisolver=1.4.7=py312h6142ec9_0 + - krb5=1.21.3=h237132a_0 + - lcalc=2.0.5=h4a402bc_2 + - lcms2=2.16=ha0e7c42_0 + - ld64=951.9=h39a299f_2 + - ld64_osx-arm64=951.9=h3f9b568_2 + - lerc=4.0.0=h9a09cb3_0 + - libasprintf=0.22.5=h8414b35_3 + - libasprintf-devel=0.22.5=h8414b35_3 + - libblas=3.9.0=26_osxarm64_openblas + - libboost=1.85.0=hf763ba5_4 + - libboost-devel=1.85.0=hf450f58_4 + - libboost-headers=1.85.0=hce30654_4 + - libbraiding=1.3=h286801f_0 + - libbrial=1.2.12=h56a29cd_3 + - libbrotlicommon=1.1.0=hd74edd7_2 + - libbrotlidec=1.1.0=hd74edd7_2 + - libbrotlienc=1.1.0=hd74edd7_2 + - libcblas=3.9.0=26_osxarm64_openblas + - libclang-cpp17=17.0.6=default_h146c034_7 + - libcurl=8.11.1=h73640d1_0 + - libcxx=19.1.6=ha82da77_1 + - libcxx-devel=17.0.6=h86353a2_6 + - libdeflate=1.23=hec38601_0 + - libedit=3.1.20191231=hc8eb9b7_2 + - libev=4.33=h93a5062_2 + - libexpat=2.6.4=h286801f_0 + - libffi=3.4.2=h3422bc3_5 + - libflint=3.1.2=he28cf6d_101 + - libgd=2.3.3=hac1b3a8_10 + - libgettextpo=0.22.5=h8414b35_3 + - libgettextpo-devel=0.22.5=h8414b35_3 + - libgfortran=5.0.0=13_2_0_hd922786_3 + - libgfortran-devel_osx-arm64=13.2.0=h5d7a38c_3 + - libgfortran5=13.2.0=hf226fd6_3 + - libglib=2.82.2=h07bd6cf_0 + - libhomfly=1.02r6=h93a5062_1 + - libiconv=1.17=h0d3ecfb_2 + - libintl=0.22.5=h8414b35_3 + - libintl-devel=0.22.5=h8414b35_3 + - libjpeg-turbo=3.0.0=hb547adb_1 + - liblapack=3.9.0=26_osxarm64_openblas + - liblapacke=3.9.0=26_osxarm64_openblas + - libllvm17=17.0.6=h5090b49_2 + - liblzma=5.6.3=h39f12f2_1 + - liblzma-devel=5.6.3=h39f12f2_1 + - libnghttp2=1.64.0=h6d7220d_0 + - libopenblas=0.3.28=openmp_hf332438_1 + - libpng=1.6.44=hc14010f_0 + - libsodium=1.0.20=h99b78c6_0 + - libsqlite=3.47.2=h3f77e49_0 + - libssh2=1.11.1=h9cc3647_0 + - libtiff=4.7.0=h551f018_3 + - libwebp-base=1.4.0=h93a5062_0 + - libxcb=1.17.0=hdb1d25a_0 + - libxml2=2.13.5=h178c5d8_1 + - libzlib=1.3.1=h8359307_2 + - linbox=1.7.0=h9da6ecd_1 + - llvm-openmp=19.1.6=hdb05f8b_0 + - llvm-tools=17.0.6=h5090b49_2 + - lrcalc=2.1=hf9b8971_7 + - m4=1.4.18=h642e427_1001 + - m4ri=20140914=hc97c1ff_1006 + - m4rie=20200125=hc97c1ff_0 + - markupsafe=3.0.2=py312h998013c_1 + - matplotlib=3.10.0=py312h1f38498_0 + - matplotlib-base=3.10.0=py312hdbc7e53_0 + - matplotlib-inline=0.1.7=pyhd8ed1ab_1 + - maxima=5.47.0=h2bbcd85_2 + - memory-allocator=0.1.3=py312h024a12e_1 + - meson=1.6.1=pyhd8ed1ab_0 + - meson-python=0.17.1=pyh70fd9c4_1 + - mpc=1.3.1=h8f1351a_1 + - mpfi=1.5.4=hbde5f5b_1001 + - mpfr=4.2.1=hb693164_3 + - mpmath=1.3.0=pyhd8ed1ab_1 + - munkres=1.1.4=pyh9f0ad1d_0 + - nauty=2.8.8=h93a5062_1 + - ncurses=6.5=h7bae524_1 + - nest-asyncio=1.6.0=pyhd8ed1ab_1 + - networkx=3.4.2=pyh267e887_2 + - ninja=1.12.1=h420ef59_0 + - ntl=11.4.3=hbb3f309_1 + - numpy=1.26.4=py312h8442bc7_0 + - openblas=0.3.28=openmp_hea878ba_1 + - openjpeg=2.5.3=h8a3d83b_0 + - openssl=3.4.0=h39f12f2_0 + - packaging=24.2=pyhd8ed1ab_2 + - palp=2.20=h27ca646_0 + - pari=2.15.5=h4f2304c_2_pthread + - pari-elldata=0.0.20161017=0 + - pari-galdata=0.0.20180411=0 + - pari-seadata=0.0.20090618=0 + - pari-seadata-small=0.0.20090618=0 + - parso=0.8.4=pyhd8ed1ab_1 + - pcre2=10.44=h297a79d_2 + - perl=5.32.1=7_h4614cfb_perl5 + - pexpect=4.9.0=pyhd8ed1ab_1 + - pickleshare=0.7.5=pyhd8ed1ab_1004 + - pillow=11.0.0=py312haf37ca6_0 + - pip=24.3.1=pyh8b19718_2 + - pkg-config=0.29.2=hde07d2e_1009 + - pkgconfig=1.5.5=pyhd8ed1ab_5 + - planarity=3.0.2.0=h93a5062_0 + - platformdirs=4.3.6=pyhd8ed1ab_1 + - pluggy=1.5.0=pyhd8ed1ab_1 + - ppl=1.2=h8b147cf_1006 + - pplpy=0.8.9=py312h35b16b8_1 + - primecount=7.6=hb6e4faa_0 + - primecountpy=0.1.0=py312h389731b_4 + - primesieve=11.0=hb7217d7_0 + - prompt-toolkit=3.0.48=pyha770c72_1 + - psutil=6.1.0=py312h0bf5046_0 + - pthread-stubs=0.4=hd74edd7_1002 + - ptyprocess=0.7.0=pyhd8ed1ab_1 + - pure_eval=0.2.3=pyhd8ed1ab_1 + - pycparser=2.22=pyh29332c3_1 + - pygments=2.18.0=pyhd8ed1ab_1 + - pyparsing=3.2.0=pyhd8ed1ab_2 + - pyproject-metadata=0.9.0=pyhd8ed1ab_1 + - pysocks=1.7.1=pyha55dd90_7 + - pytest=8.3.4=pyhd8ed1ab_1 + - pytest-xdist=3.6.1=pyhd8ed1ab_1 + - python=3.12.8=hc22306f_1_cpython + - python-dateutil=2.9.0.post0=pyhff2d567_1 + - python-lrcalc=2.1=py312hde4cb15_7 + - python_abi=3.12=5_cp312 + - pytz=2024.2=pyhd8ed1ab_1 + - pyzmq=26.2.0=py312hf8a1cbd_3 + - qd=2.3.22=hbec66e7_1004 + - qhull=2020.2=h420ef59_5 + - readline=8.2=h92ec313_1 + - requests=2.32.3=pyhd8ed1ab_1 + - rw=0.9=h93a5062_2 + - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 + - sagemath-db-graphs=20210214=hd8ed1ab_0 + - sagemath-db-polytopes=20170220=1 + - scipy=1.14.1=py312h6bb24ec_2 + - setuptools=75.6.0=pyhff2d567_1 + - sigtool=0.1.3=h44b9a77_0 + - singular=4.4.0=h5a8969a_1 + - six=1.17.0=pyhd8ed1ab_0 + - snowballstemmer=2.2.0=pyhd8ed1ab_0 + - soupsieve=2.5=pyhd8ed1ab_1 + - sphinx=8.1.3=pyhd8ed1ab_1 + - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_2 + - sphinx-inline-tabs=2023.4.21=pyhd8ed1ab_0 + - sphinxcontrib-applehelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-devhelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-htmlhelp=2.1.0=pyhd8ed1ab_1 + - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_1 + - sphinxcontrib-qthelp=2.0.0=pyhd8ed1ab_1 + - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_1 + - sqlite=3.47.2=hd7222ec_0 + - stack_data=0.6.3=pyhd8ed1ab_1 + - symmetrica=3.0.1=hb7217d7_0 + - sympow=2.023.6=hb0babe8_3 + - sympy=1.13.3=pyh2585a3b_104 + - tachyon=0.99b6=hb8a568e_1002 + - tapi=1300.6.5=h03f4b80_0 + - tk=8.6.13=h5083fa2_1 + - tomli=2.2.1=pyhd8ed1ab_1 + - tornado=6.4.2=py312hea69d52_0 + - traitlets=5.14.3=pyhd8ed1ab_1 + - typing_extensions=4.12.2=pyha770c72_1 + - tzdata=2024b=hc8b5060_0 + - unicodedata2=15.1.0=py312h0bf5046_1 + - urllib3=2.2.3=pyhd8ed1ab_1 + - wcwidth=0.2.13=pyhd8ed1ab_1 + - wheel=0.45.1=pyhd8ed1ab_1 + - widgetsnbextension=4.0.13=pyhd8ed1ab_1 + - xorg-libxau=1.0.12=h5505292_0 + - xorg-libxdmcp=1.1.5=hd74edd7_0 + - xz=5.6.3=h9a6d368_1 + - xz-gpl-tools=5.6.3=h9a6d368_1 + - xz-tools=5.6.3=h39f12f2_1 + - zeromq=4.3.5=hc1bb282_7 + - zipp=3.21.0=pyhd8ed1ab_1 + - zlib=1.3.1=h8359307_2 + - zstandard=0.23.0=py312h15fbf35_1 + - zstd=1.5.6=hb46c0d2_0 diff --git a/environment-3.9-linux-aarch64.yml b/environment-3.9-linux-aarch64.yml deleted file mode 100644 index 97c6b302ce6..00000000000 --- a/environment-3.9-linux-aarch64.yml +++ /dev/null @@ -1,436 +0,0 @@ -name: sage -# Generated by conda-lock. -# platform: linux-aarch64 -# input_hash: ff1dc47da14265a884b6d8aae2cde457456f547babfa735ad39ad330bb83aa6a - -channels: - - conda-forge -dependencies: - - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - _sysroot_linux-aarch64_curr_repodata_hack=4=h57d6b7b_14 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.11=h31becfc_1 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py39h898b7ef_4 - - arpack=3.9.1=nompi_hd363cd0_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321h2148fe1_1 - - automake=1.16.5=pl5321h8af1aa0_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=hf897c2e_0 - - bdw-gc=8.0.6=hd62202e_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=hf1166c9_7 - - binutils_impl_linux-aarch64=2.40=hf54a868_7 - - binutils_linux-aarch64=2.40=h1f91aba_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linuxaarch64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=ha990451_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h31becfc_1 - - brotli-bin=1.1.0=h31becfc_1 - - brotli-python=1.1.0=py39h387a81e_1 - - bwidget=1.9.14=h8af1aa0_1 - - bzip2=1.0.8=h31becfc_5 - - c-ares=1.28.1=h31becfc_0 - - c-compiler=1.7.0=h31becfc_1 - - ca-certificates=2024.6.2=hcefe29a_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=h5c54ea9_2 - - cddlib=1!0.94m=h719063d_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py39hdf53b9e_0 - - chardet=5.2.0=py39ha65689a_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - cliquer=1.22=h31becfc_1 - - cmake=3.29.6=h7042e5d_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py39h4420490_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=h8af1aa0_1 - - contourpy=1.2.1=py39hd16970a_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=h7daf2e0_0 - - cvxopt=1.3.2=py39h093dae0_2 - - cxx-compiler=1.7.0=h2a328a1_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py39h532d932_0 - - cysignals=1.11.2=py39hfa81392_3 - - cython=3.0.10=py39h387a81e_0 - - debugpy=1.8.1=py39h387a81e_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hb12102e_1203 - - ecl=23.9.9=h6475f26_0 - - eclib=20231212=he26bab5_0 - - ecm=7.0.5=ha2d0fc4_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h2f0025b_0 - - fflas-ffpack=2.5.0=h503e619_0 - - fftw=3.3.10=nompi_h020dacd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=ha9a116f_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py39he257ee7_0 - - fortran-compiler=1.7.0=h7048d53_1 - - fplll=5.4.5=hb3a790e_0 - - fpylll=0.6.1=py39h97065f7_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=hf0a5ef3_2 - - fribidi=1.0.10=hb9de7d4_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=h597289e_3 - - gap-defaults=4.12.2=h8af1aa0_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=hdb0cc85_13 - - gcc_impl_linux-aarch64=12.3.0=h3d98823_13 - - gcc_linux-aarch64=12.3.0=ha52a6ea_9 - - gengetopt=2.23=h01db608_0 - - gf2x=1.3.0=h1b3b3a3_2 - - gfan=0.6.2=h5f589ec_1003 - - gfortran=12.3.0=hdb0cc85_13 - - gfortran_impl_linux-aarch64=12.3.0=h97ebfd2_13 - - gfortran_linux-aarch64=12.3.0=ha7b8e4b_9 - - giac=1.9.0.21=h04922a4_1 - - giflib=5.2.2=h31becfc_0 - - givaro=4.2.0=h364d21b_0 - - glpk=5.0=h66325d0_0 - - gmp=6.3.0=h0a1ffab_2 - - gmpy2=2.1.5=py39hcc1b389_1 - - graphite2=1.3.13=h2f0025b_1003 - - gsl=2.7=h294027d_0 - - gxx=12.3.0=hdb0cc85_13 - - gxx_impl_linux-aarch64=12.3.0=hba91e99_13 - - gxx_linux-aarch64=12.3.0=h9d1f256_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h9812418_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h787c7f5_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h197073e_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h15043fe_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.18.1=pyh707e725_3 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=h8af1aa0_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py39h4420490_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py39h4420490_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-aarch64=4.18.0=h5b4a56d_14 - - keyutils=1.6.1=h4e544f5_0 - - kiwisolver=1.4.5=py39had2cf8c_1 - - krb5=1.21.2=hc419048_0 - - lcalc=2.0.5=he588f68_2 - - lcms2=2.16=h922389a_0 - - ld_impl_linux-aarch64=2.40=h9fc2d93_7 - - lerc=4.0.0=h4de3ea5_0 - - libatomic_ops=7.6.14=h4e544f5_0 - - libblas=3.9.0=20_linuxaarch64_openblas - - libboost=1.85.0=hb41fec8_2 - - libboost-devel=1.85.0=h37bb5a9_2 - - libboost-headers=1.85.0=h8af1aa0_2 - - libbraiding=1.2=hd600fc2_0 - - libbrial=1.2.12=h9429f74_3 - - libbrotlicommon=1.1.0=h31becfc_1 - - libbrotlidec=1.1.0=h31becfc_1 - - libbrotlienc=1.1.0=h31becfc_1 - - libcblas=3.9.0=20_linuxaarch64_openblas - - libcups=2.3.3=h405e4a8_4 - - libcurl=8.8.0=h4e8248e_0 - - libdeflate=1.20=h31becfc_0 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=h31becfc_2 - - libexpat=2.6.2=h2f0025b_0 - - libffi=3.4.2=h3557bc0_5 - - libflint=3.0.1=hc392af7_ntl_100 - - libgcc-devel_linux-aarch64=12.3.0=h6144e03_113 - - libgcc-ng=13.2.0=he277a41_13 - - libgd=2.3.3=hcd22fd5_9 - - libgfortran-ng=13.2.0=he9431aa_13 - - libgfortran5=13.2.0=h2af0866_13 - - libglib=2.80.2=haee52c6_1 - - libgomp=13.2.0=he277a41_13 - - libhomfly=1.02r6=h31becfc_1 - - libhwloc=2.10.0=default_h3030c0e_1001 - - libiconv=1.17=h31becfc_2 - - libjpeg-turbo=3.0.0=h31becfc_1 - - liblapack=3.9.0=20_linuxaarch64_openblas - - liblapacke=3.9.0=20_linuxaarch64_openblas - - libnghttp2=1.58.0=hb0e430d_1 - - libnsl=2.0.1=h31becfc_0 - - libopenblas=0.3.25=pthreads_h5a5ec62_0 - - libpng=1.6.43=h194ca79_0 - - libsanitizer=12.3.0=h57e2e72_13 - - libsodium=1.0.18=hb9de7d4_1 - - libsqlite=3.46.0=hf51ef55_0 - - libssh2=1.11.0=h492db2e_0 - - libstdcxx-devel_linux-aarch64=12.3.0=h6144e03_113 - - libstdcxx-ng=13.2.0=h3f4de04_13 - - libtiff=4.6.0=hf980d43_3 - - libtool=2.4.7=h4de3ea5_0 - - libuuid=2.38.1=hb4cce97_0 - - libuv=1.48.0=h31becfc_0 - - libwebp=1.4.0=h8b4e01b_0 - - libwebp-base=1.4.0=h31becfc_0 - - libxcb=1.16=h7935292_0 - - libxcrypt=4.4.36=h31becfc_1 - - libxml2=2.12.7=h49dc7a2_1 - - libzlib=1.3.1=h68df207_1 - - linbox=1.7.0=h681a5ee_0 - - llvm-openmp=18.1.8=hb063fc5_0 - - lrcalc=2.1=h2f0025b_6 - - m4=1.4.18=h516909a_1001 - - m4ri=20140914=hedfd65a_1006 - - m4rie=20150908=hf0a5ef3_1002 - - make=4.3=h309ac5b_1 - - markupsafe=2.1.5=py39h7cc1d5f_0 - - mathjax=3.2.2=h8af1aa0_0 - - matplotlib=3.8.4=py39ha65689a_2 - - matplotlib-base=3.8.4=py39hf44f4b6_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h6475f26_2 - - memory-allocator=0.1.3=py39h898b7ef_0 - - metis=5.1.0=h2f0025b_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=hf4c8f4c_0 - - mpfi=1.5.4=h846f343_1001 - - mpfr=4.2.1=ha2d0fc4_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h31becfc_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h0425590_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h70be974_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=h0d7519b_1 - - numpy=1.26.4=py39h91c28bb_0 - - openblas=0.3.25=pthreads_h339cbfa_0 - - openjdk=22.0.1=h3d4cd67_0 - - openjpeg=2.5.2=h0d9d63b_0 - - openssl=3.3.1=h68df207_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=hb9de7d4_0 - - pandoc=3.2.1=h8af1aa0_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h399c48b_0 - - pari=2.15.5=h169c2a7_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=hf897c2e_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h070dd5b_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h31becfc_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py39h4a8821f_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h2f0025b_0 - - pkg-config=0.29.2=hb9de7d4_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h31becfc_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h984aac9_1006 - - pplpy=0.8.9=py39hf652505_1 - - primecount=7.6=hd600fc2_0 - - primecountpy=0.1.0=py39hd16970a_3 - - primesieve=11.0=hd600fc2_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py39he257ee7_0 - - pthread-stubs=0.4=hb9de7d4_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py39hd16970a_0 - - pybind11-global=2.12.0=py39hd16970a_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py39h7cc1d5f_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.9.19=h4ac3b42_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py39h387a81e_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.9=4_cp39 - - pythran=0.15.0=py39hc2250db_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py39h4420490_4 - - pyyaml=6.0.1=py39h898b7ef_1 - - pyzmq=26.0.3=py39h866fef3_0 - - qd=2.3.22=h05efe27_1004 - - qhull=2020.2=hd62202e_2 - - r-base=4.3.3=h7f20121_3 - - r-lattice=0.22_6=r43h25e906a_0 - - readline=8.2=h8fc344f_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h31becfc_0 - - rpds-py=0.18.1=py39hb8f4057_0 - - rpy2=3.5.11=py39r43h1ae4408_3 - - rw=0.9=h31becfc_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.3=py39h91c28bb_1 - - sed=4.8=ha0d5d3d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hbe76a8a_1 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=hdc7ab3c_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=h3944111_1 - - symmetrica=3.0.1=hd600fc2_0 - - sympow=2.023.6=h157afb5_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-aarch64=2.17=h5b4a56d_14 - - tachyon=0.99b6=ha0bfc61_1002 - - tar=1.34=h048efde_0 - - tbb=2021.12.0=h70be974_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h17f021e_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h194ca79_0 - - tktable=2.10=h52f7bd3_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py39ha3e8b56_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py39h4420490_0 - - unicodedata2=15.1.0=py39h898b7ef_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-fixesproto=5.0=h3557bc0_1002 - - xorg-inputproto=2.3.2=h3557bc0_1002 - - xorg-kbproto=1.0.7=h3557bc0_1002 - - xorg-libice=1.1.1=h7935292_0 - - xorg-libsm=1.2.4=h5a01bc2_0 - - xorg-libx11=1.8.9=h08be655_1 - - xorg-libxau=1.0.11=h31becfc_0 - - xorg-libxdmcp=1.1.3=h3557bc0_0 - - xorg-libxext=1.3.4=h2a766a3_2 - - xorg-libxfixes=5.0.3=h3557bc0_1004 - - xorg-libxi=1.7.10=h3557bc0_0 - - xorg-libxrender=0.9.11=h7935292_0 - - xorg-libxt=1.3.0=h7935292_1 - - xorg-libxtst=1.2.3=hf897c2e_1002 - - xorg-recordproto=1.14.2=hf897c2e_1002 - - xorg-renderproto=0.11.1=h3557bc0_1002 - - xorg-xextproto=7.3.0=h2a766a3_1003 - - xorg-xproto=7.0.31=h3557bc0_1007 - - xz=5.2.6=h9cdd2b7_0 - - yaml=0.2.5=hf897c2e_2 - - zeromq=4.3.5=h28faeed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h68df207_1 - - zstd=1.5.6=h02f22dd_0 diff --git a/environment-3.9-linux.yml b/environment-3.9-linux.yml deleted file mode 100644 index 7099a1eb01d..00000000000 --- a/environment-3.9-linux.yml +++ /dev/null @@ -1,484 +0,0 @@ -name: sage -# Generated by conda-lock. -# platform: linux-64 -# input_hash: e864996ba609c3a06f1c78376812e9f6180653730f5c2e60df67268b3e2fb7d6 - -channels: - - conda-forge -dependencies: - - _libgcc_mutex=0.1=conda_forge - - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.12=h4ab18f5_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py39hd1e30aa_4 - - arpack=3.9.1=nompi_h77f6705_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attr=2.5.1=h166bdaf_1 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321h2b4cb7a_1 - - automake=1.16.5=pl5321ha770c72_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=h7f98852_0 - - bdw-gc=8.0.6=h4bd325d_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=h4852527_7 - - binutils_impl_linux-64=2.40=ha1999f0_7 - - binutils_linux-64=2.40=hb3c18ed_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linux64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h44aadfe_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hd590300_1 - - brotli-bin=1.1.0=hd590300_1 - - brotli-python=1.1.0=py39h3d6467e_1 - - bwidget=1.9.14=ha770c72_1 - - bzip2=1.0.8=hd590300_5 - - c-ares=1.28.1=hd590300_0 - - c-compiler=1.7.0=hd590300_1 - - ca-certificates=2024.6.2=hbcca054_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=hbb29018_2 - - cddlib=1!0.94m=h9202a9a_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py39h7a31438_0 - - chardet=5.2.0=py39hf3d152e_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - cliquer=1.22=hd590300_1 - - cmake=3.29.6=hcafd917_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py39hf3d152e_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=ha770c72_1 - - contourpy=1.2.1=py39h7633fee_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=he654da7_0 - - cvxopt=1.3.2=py39h640215f_2 - - cxx-compiler=1.7.0=h00ab1b0_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py39h1698a45_0 - - cysignals=1.11.2=py39h1ce0973_3 - - cython=3.0.10=py39h3d6467e_0 - - dbus=1.13.6=h5008d03_3 - - debugpy=1.8.1=py39h3d6467e_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hd9d9efa_1203 - - ecl=23.9.9=hed6455c_0 - - eclib=20231212=h96f522a_0 - - ecm=7.0.5=h9458935_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h59595ed_0 - - fflas-ffpack=2.5.0=h4f9960b_0 - - fftw=3.3.10=nompi_hf1063bd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h14ed4e7_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py39hd3abc70_0 - - fortran-compiler=1.7.0=heb67821_1 - - fplll=5.4.5=h384768b_0 - - fpylll=0.6.1=py39h2525e16_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=h267a509_2 - - fribidi=1.0.10=h36c2ea0_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he9a28a4_3 - - gap-defaults=4.12.2=ha770c72_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=h915e2ae_13 - - gcc_impl_linux-64=12.3.0=h58ffeeb_13 - - gcc_linux-64=12.3.0=h9528a6a_9 - - gengetopt=2.23=h9c3ff4c_0 - - gettext=0.22.5=h59595ed_2 - - gettext-tools=0.22.5=h59595ed_2 - - gf2x=1.3.0=ha476b99_2 - - gfan=0.6.2=hb86e20a_1003 - - gfortran=12.3.0=h915e2ae_13 - - gfortran_impl_linux-64=12.3.0=h8f2110c_13 - - gfortran_linux-64=12.3.0=h5877db1_9 - - giac=1.9.0.21=h673759e_1 - - giflib=5.2.2=hd590300_0 - - givaro=4.2.0=hb789bce_0 - - glib=2.80.2=h8a4344b_1 - - glib-tools=2.80.2=h73ef956_1 - - glpk=5.0=h445213a_0 - - gmp=6.3.0=hac33072_2 - - gmpy2=2.1.5=py39h048c657_1 - - graphite2=1.3.13=h59595ed_1003 - - gsl=2.7=he838d99_0 - - gst-plugins-base=1.24.5=hbaaba92_0 - - gstreamer=1.24.5=haf2f30d_0 - - gxx=12.3.0=h915e2ae_13 - - gxx_impl_linux-64=12.3.0=h2a574ab_13 - - gxx_linux-64=12.3.0=ha28b414_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=hfac3d4d_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h59595ed_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hef0740d_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h623f65a_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.18.1=pyh707e725_3 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=ha770c72_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py39hf3d152e_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py39hf3d152e_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-64=2.6.32=he073ed8_17 - - keyutils=1.6.1=h166bdaf_0 - - kiwisolver=1.4.5=py39h7633fee_1 - - krb5=1.21.2=h659d440_0 - - lame=3.100=h166bdaf_1003 - - lcalc=2.0.5=h5aac1b6_2 - - lcms2=2.16=hb7c19ff_0 - - ld_impl_linux-64=2.40=hf3520f5_7 - - lerc=4.0.0=h27087fc_0 - - libasprintf=0.22.5=h661eb56_2 - - libasprintf-devel=0.22.5=h661eb56_2 - - libatomic_ops=7.6.14=h166bdaf_0 - - libblas=3.9.0=20_linux64_openblas - - libboost=1.85.0=hba137d9_2 - - libboost-devel=1.85.0=h00ab1b0_2 - - libboost-headers=1.85.0=ha770c72_2 - - libbraiding=1.2=hcb278e6_0 - - libbrial=1.2.12=h76af697_3 - - libbrotlicommon=1.1.0=hd590300_1 - - libbrotlidec=1.1.0=hd590300_1 - - libbrotlienc=1.1.0=hd590300_1 - - libcap=2.69=h0f662aa_0 - - libcblas=3.9.0=20_linux64_openblas - - libclang-cpp15=15.0.7=default_h127d8a8_5 - - libclang13=18.1.8=default_h6ae225f_0 - - libcups=2.3.3=h4637d8d_4 - - libcurl=8.8.0=hca28451_0 - - libdeflate=1.20=hd590300_0 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=hd590300_2 - - libevent=2.1.12=hf998b51_1 - - libexpat=2.6.2=h59595ed_0 - - libffi=3.4.2=h7f98852_5 - - libflac=1.4.3=h59595ed_0 - - libflint=3.0.1=h5f2e117_ntl_100 - - libgcc-devel_linux-64=12.3.0=h6b66f73_113 - - libgcc-ng=13.2.0=h77fa898_13 - - libgcrypt=1.10.3=hd590300_0 - - libgd=2.3.3=h119a65a_9 - - libgettextpo=0.22.5=h59595ed_2 - - libgettextpo-devel=0.22.5=h59595ed_2 - - libgfortran-ng=13.2.0=h69a702a_13 - - libgfortran5=13.2.0=h3d2ce59_13 - - libglib=2.80.2=h8a4344b_1 - - libgomp=13.2.0=h77fa898_13 - - libgpg-error=1.49=h4f305b6_0 - - libhomfly=1.02r6=hd590300_1 - - libhwloc=2.10.0=default_h5622ce7_1001 - - libiconv=1.17=hd590300_2 - - libjpeg-turbo=3.0.0=hd590300_1 - - liblapack=3.9.0=20_linux64_openblas - - liblapacke=3.9.0=20_linux64_openblas - - libllvm15=15.0.7=hb3ce162_4 - - libllvm18=18.1.8=hc9dba70_0 - - libnghttp2=1.58.0=h47da74e_1 - - libnsl=2.0.1=hd590300_0 - - libogg=1.3.5=h4ab18f5_0 - - libopenblas=0.3.25=pthreads_h413a1c8_0 - - libopus=1.3.1=h7f98852_1 - - libpng=1.6.43=h2797004_0 - - libpq=16.3=ha72fbe1_0 - - libsanitizer=12.3.0=hb8811af_13 - - libsndfile=1.2.2=hc60ed4a_1 - - libsodium=1.0.18=h36c2ea0_1 - - libsqlite=3.46.0=hde9e2c9_0 - - libssh2=1.11.0=h0841786_0 - - libstdcxx-devel_linux-64=12.3.0=h6b66f73_113 - - libstdcxx-ng=13.2.0=hc0a3c3a_13 - - libsystemd0=255=h3516f8a_1 - - libtiff=4.6.0=h1dd3fc0_3 - - libtool=2.4.7=h27087fc_0 - - libuuid=2.38.1=h0b41bf4_0 - - libuv=1.48.0=hd590300_0 - - libvorbis=1.3.7=h9c3ff4c_0 - - libwebp=1.4.0=h2c329e2_0 - - libwebp-base=1.4.0=hd590300_0 - - libxcb=1.16=hd590300_0 - - libxcrypt=4.4.36=hd590300_1 - - libxkbcommon=1.7.0=h2c5496b_1 - - libxml2=2.12.7=hc051c1a_1 - - libzlib=1.3.1=h4ab18f5_1 - - linbox=1.7.0=ha329b40_0 - - llvm-openmp=18.1.8=hf5423f3_0 - - lrcalc=2.1=h59595ed_6 - - lz4-c=1.9.4=hcb278e6_0 - - m4=1.4.18=h516909a_1001 - - m4ri=20140914=hae5d5c5_1006 - - m4rie=20150908=h267a509_1002 - - make=4.3=hd18ef5c_1 - - markupsafe=2.1.5=py39hd1e30aa_0 - - mathjax=3.2.2=ha770c72_0 - - matplotlib=3.8.4=py39hf3d152e_2 - - matplotlib-base=3.8.4=py39h10d1fc8_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=hed6455c_2 - - memory-allocator=0.1.3=py39hd1e30aa_0 - - metis=5.1.0=h59595ed_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=hfe3b2da_0 - - mpfi=1.5.4=h9f54685_1001 - - mpfr=4.2.1=h9458935_1 - - mpg123=1.32.6=h59595ed_0 - - mpmath=1.3.0=pyhd8ed1ab_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - mysql-common=8.3.0=hf1915f5_4 - - mysql-libs=8.3.0=hca2cd23_4 - - nauty=2.8.8=hd590300_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h59595ed_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h297d8ca_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - nspr=4.35=h27087fc_0 - - nss=3.101=h593d115_0 - - ntl=11.4.3=hef3c4d3_1 - - numpy=1.26.4=py39h474f0d3_0 - - openblas=0.3.25=pthreads_h7a3da1a_0 - - openjdk=21.0.2=haa376d0_0 - - openjpeg=2.5.2=h488ebb8_0 - - openssl=3.3.1=h4ab18f5_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=h36c2ea0_0 - - pandoc=3.2.1=ha770c72_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h84a9a3c_0 - - pari=2.15.5=h4d4ae9b_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=h7f98852_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h0f59acf_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_hd590300_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py39h16a7006_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.2=h59595ed_0 - - pkg-config=0.29.2=h36c2ea0_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=hd590300_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h6ec01c2_1006 - - pplpy=0.8.9=py39h9e9cb73_1 - - primecount=7.9=hcb278e6_0 - - primecountpy=0.1.0=py39h7633fee_4 - - primesieve=11.1=h59595ed_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py39hd3abc70_0 - - pthread-stubs=0.4=h36c2ea0_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pulseaudio-client=17.0=hb77b528_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py39h7633fee_0 - - pybind11-global=2.12.0=py39h7633fee_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyqt=5.15.9=py39h52134e7_5 - - pyqt5-sip=12.12.2=py39h3d6467e_5 - - pyrsistent=0.20.0=py39hd1e30aa_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.9.19=h0755675_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py39h3d6467e_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.9=4_cp39 - - pythran=0.15.0=py39hda80f44_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py39hf3d152e_4 - - pyyaml=6.0.1=py39hd1e30aa_1 - - pyzmq=26.0.3=py39ha1047a2_0 - - qd=2.3.22=h2cc385e_1004 - - qhull=2020.2=h4bd325d_2 - - qt-main=5.15.8=ha2b5568_22 - - r-base=4.3.3=he2d9a6e_3 - - r-lattice=0.22_6=r43h57805ef_0 - - readline=8.2=h8228510_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hd590300_0 - - rpds-py=0.18.1=py39ha68c5e3_0 - - rpy2=3.5.11=py39r43h44dd56e_3 - - rw=0.9=hd590300_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py39h474f0d3_0 - - sed=4.8=he412f7d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h33f5c3f_1 - - sip=6.7.12=py39h3d6467e_0 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h6d4b2fc_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf4753ba_1 - - symmetrica=3.0.1=hcb278e6_0 - - sympow=2.023.6=hc6ab17c_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-64=2.12=he073ed8_17 - - tachyon=0.99b6=hba7d16a_1002 - - tar=1.34=hb2e2bae_1 - - tbb=2021.12.0=h297d8ca_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h0f457ee_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=noxft_h4845f30_101 - - tktable=2.10=h8bc8fbc_6 - - toml=0.10.2=pyhd8ed1ab_0 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py39hd3abc70_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py39hf3d152e_0 - - unicodedata2=15.1.0=py39hd1e30aa_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xcb-util=0.4.1=hb711507_2 - - xcb-util-image=0.4.0=hb711507_2 - - xcb-util-keysyms=0.4.1=hb711507_0 - - xcb-util-renderutil=0.3.10=hb711507_0 - - xcb-util-wm=0.4.2=hb711507_0 - - xkeyboard-config=2.42=h4ab18f5_0 - - xorg-fixesproto=5.0=h7f98852_1002 - - xorg-inputproto=2.3.2=h7f98852_1002 - - xorg-kbproto=1.0.7=h7f98852_1002 - - xorg-libice=1.1.1=hd590300_0 - - xorg-libsm=1.2.4=h7391055_0 - - xorg-libx11=1.8.9=hb711507_1 - - xorg-libxau=1.0.11=hd590300_0 - - xorg-libxdmcp=1.1.3=h7f98852_0 - - xorg-libxext=1.3.4=h0b41bf4_2 - - xorg-libxfixes=5.0.3=h7f98852_1004 - - xorg-libxi=1.7.10=h7f98852_0 - - xorg-libxrender=0.9.11=hd590300_0 - - xorg-libxt=1.3.0=hd590300_1 - - xorg-libxtst=1.2.3=h7f98852_1002 - - xorg-recordproto=1.14.2=h7f98852_1002 - - xorg-renderproto=0.11.1=h7f98852_1002 - - xorg-xextproto=7.3.0=h0b41bf4_1003 - - xorg-xf86vidmodeproto=2.3.1=h7f98852_1002 - - xorg-xproto=7.0.31=h7f98852_1007 - - xz=5.2.6=h166bdaf_0 - - yaml=0.2.5=h7f98852_2 - - zeromq=4.3.5=h75354e8_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h4ab18f5_1 - - zstd=1.5.6=ha6fb4c9_0 diff --git a/environment-3.9-macos-x86_64.yml b/environment-3.9-macos-x86_64.yml deleted file mode 100644 index de8df57d291..00000000000 --- a/environment-3.9-macos-x86_64.yml +++ /dev/null @@ -1,424 +0,0 @@ -name: sage -# Generated by conda-lock. -# platform: osx-64 -# input_hash: 7b973134e4e44170c953a71c99253450b079227c08993b2a49ae3ddd14d93fdb - -channels: - - conda-forge -dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py39hdc70f33_4 - - arpack=3.9.1=nompi_hf81eadf_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321hed12c24_1 - - automake=1.16.5=pl5321h694c41f_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=h0d85af4_0 - - bdw-gc=8.0.6=h940c156_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osx64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h07eb623_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h0dc2134_1 - - brotli-bin=1.1.0=h0dc2134_1 - - brotli-python=1.1.0=py39h840bb9f_1 - - bwidget=1.9.14=h694c41f_1 - - bzip2=1.0.8=h10d778d_5 - - c-ares=1.28.1=h10d778d_0 - - c-compiler=1.7.0=h282daa2_1 - - ca-certificates=2024.6.2=h8857fd0_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=h9f650ed_2 - - cctools=986=h40f6528_0 - - cctools_osx-64=986=ha1c5b94_0 - - cddlib=1!0.94m=h0f52abe_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py39h18ef598_0 - - chardet=5.2.0=py39h6e9494a_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_ha3b9224_8 - - clang-16=16.0.6=default_h4c8afb6_8 - - clang_impl_osx-64=16.0.6=h8787910_16 - - clang_osx-64=16.0.6=hb91bd55_16 - - clangxx=16.0.6=default_ha3b9224_8 - - clangxx_impl_osx-64=16.0.6=h6d92fbe_16 - - clangxx_osx-64=16.0.6=hb91bd55_16 - - cliquer=1.22=h10d778d_1 - - cmake=3.29.6=h749d262_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py39h6e9494a_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=ha38d28d_2 - - compiler-rt_osx-64=16.0.6=ha38d28d_2 - - compilers=1.7.0=h694c41f_1 - - contourpy=1.2.1=py39h0ca7971_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=hea67d85_0 - - cvxopt=1.3.2=py39hd66cc7a_2 - - cxx-compiler=1.7.0=h7728843_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py39hc0d7317_0 - - cysignals=1.11.2=py39hf6ae30e_3 - - cython=3.0.10=py39hd253f6c_0 - - debugpy=1.8.1=py39hd253f6c_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h6e329d1_1203 - - ecl=23.9.9=h2b27fa8_0 - - eclib=20231212=h02435c3_0 - - ecm=7.0.5=h4f6b447_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h73e2aa4_0 - - fflas-ffpack=2.5.0=h5898d61_0 - - fftw=3.3.10=nompi_h292e606_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h5bb23bf_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py39hded5825_0 - - fortran-compiler=1.7.0=h6c2ab21_1 - - fplll=5.4.5=hb7981ad_0 - - fpylll=0.6.1=py39h3b3ffec_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=h60636b9_2 - - fribidi=1.0.10=hbcb3906_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=hc16eb5f_3 - - gap-defaults=4.12.2=h694c41f_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=he49afe7_0 - - gettext=0.22.5=h5ff76d1_2 - - gettext-tools=0.22.5=h5ff76d1_2 - - gf2x=1.3.0=hb2a7efb_2 - - gfan=0.6.2=hd793b56_1003 - - gfortran=12.3.0=h2c809b3_1 - - gfortran_impl_osx-64=12.3.0=hc328e78_3 - - gfortran_osx-64=12.3.0=h18f7dce_1 - - giac=1.9.0.21=h92f3f65_1 - - giflib=5.2.2=h10d778d_0 - - givaro=4.2.0=h1b3d6f7_0 - - glpk=5.0=h3cb5acd_0 - - gmp=6.3.0=hf036a51_2 - - gmpy2=2.1.5=py39h87b48b1_1 - - graphite2=1.3.13=h73e2aa4_1003 - - gsl=2.7=h93259b0_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h053f038_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hf5e326d_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hde4452d_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h61918c1_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.18.1=pyh707e725_3 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isl=0.26=imath32_h2e86a7b_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.9=h694c41f_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py39h6e9494a_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.1=py39h6e9494a_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kiwisolver=1.4.5=py39h8ee36c8_1 - - krb5=1.21.2=hb884880_0 - - lcalc=2.0.5=h547a6ed_2 - - lcms2=2.16=ha2f27b4_0 - - ld64=711=ha02d983_0 - - ld64_osx-64=711=ha20a434_0 - - lerc=4.0.0=hb486fe8_0 - - libasprintf=0.22.5=h5ff76d1_2 - - libasprintf-devel=0.22.5=h5ff76d1_2 - - libatomic_ops=7.6.14=hb7f2c08_0 - - libblas=3.9.0=20_osx64_openblas - - libboost=1.85.0=h739af76_2 - - libboost-devel=1.85.0=h2b186f8_2 - - libboost-headers=1.85.0=h694c41f_2 - - libbraiding=1.2=hf0c8a7f_0 - - libbrial=1.2.12=h81e9653_3 - - libbrotlicommon=1.1.0=h0dc2134_1 - - libbrotlidec=1.1.0=h0dc2134_1 - - libbrotlienc=1.1.0=h0dc2134_1 - - libcblas=3.9.0=20_osx64_openblas - - libclang-cpp16=16.0.6=default_h4c8afb6_8 - - libcurl=8.8.0=hf9fcc65_0 - - libcxx=17.0.6=h88467a6_0 - - libdeflate=1.20=h49d49c5_0 - - libedit=3.1.20191231=h0678c8f_2 - - libev=4.33=h10d778d_2 - - libexpat=2.6.2=h73e2aa4_0 - - libffi=3.4.2=h0d85af4_5 - - libflint=3.0.1=h5d15de0_ntl_100 - - libgd=2.3.3=h0dceb68_9 - - libgettextpo=0.22.5=h5ff76d1_2 - - libgettextpo-devel=0.22.5=h5ff76d1_2 - - libgfortran=5.0.0=13_2_0_h97931a8_3 - - libgfortran-devel_osx-64=12.3.0=h0b6f5ec_3 - - libgfortran5=13.2.0=h2873a65_3 - - libglib=2.80.2=h736d271_1 - - libhomfly=1.02r6=h10d778d_1 - - libhwloc=2.10.0=default_h456cccd_1001 - - libiconv=1.17=hd75f5a5_2 - - libintl=0.22.5=h5ff76d1_2 - - libintl-devel=0.22.5=h5ff76d1_2 - - libjpeg-turbo=3.0.0=h0dc2134_1 - - liblapack=3.9.0=20_osx64_openblas - - liblapacke=3.9.0=20_osx64_openblas - - libllvm16=16.0.6=hbedff68_3 - - libnghttp2=1.58.0=h64cf6d3_1 - - libopenblas=0.3.25=openmp_hfef2a42_0 - - libpng=1.6.43=h92b6c6a_0 - - libsodium=1.0.18=hbcb3906_1 - - libsqlite=3.46.0=h1b8f9f3_0 - - libssh2=1.11.0=hd019ec5_0 - - libtiff=4.6.0=h129831d_3 - - libtool=2.4.7=hf0c8a7f_0 - - libuv=1.48.0=h67532ce_0 - - libwebp=1.4.0=hc207709_0 - - libwebp-base=1.4.0=h10d778d_0 - - libxcb=1.16=h0dc2134_0 - - libxml2=2.12.7=h3e169fe_1 - - libzlib=1.3.1=h87427d6_1 - - linbox=1.7.0=h7061c92_0 - - llvm-openmp=18.1.8=h15ab845_0 - - llvm-tools=16.0.6=hbedff68_3 - - lrcalc=2.1=h73e2aa4_6 - - m4=1.4.18=haf1e3a3_1001 - - m4ri=20140914=hd82a5f3_1006 - - m4rie=20150908=hc616cfc_1002 - - make=4.3=h22f3db7_1 - - markupsafe=2.1.5=py39ha09f3b3_0 - - mathjax=3.2.2=h694c41f_0 - - matplotlib=3.8.4=py39h6e9494a_2 - - matplotlib-base=3.8.4=py39hfca4cae_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2b27fa8_2 - - memory-allocator=0.1.3=py39hdc70f33_0 - - metis=5.1.0=he965462_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=h81bd1dd_0 - - mpfi=1.5.4=h52b28e3_1001 - - mpfr=4.2.1=h4f6b447_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h10d778d_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h5846eda_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h3c5361c_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=h0ab3c2f_1 - - numpy=1.26.4=py39h28c39a1_0 - - openblas=0.3.25=openmp_h6794695_0 - - openjdk=22.0.1=h2d185b6_0 - - openjpeg=2.5.2=h7310d3a_0 - - openssl=3.3.1=h87427d6_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=hbcb3906_0 - - pandoc=3.2.1=h694c41f_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h880b76c_0 - - pari=2.15.5=h7ba67ff_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=hbcf498f_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h7634a1b_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h10d778d_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py39hc3a33ae_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h73e2aa4_0 - - pkg-config=0.29.2=ha3d46e9_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h10d778d_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=ha60d53e_1006 - - pplpy=0.8.9=py39hc385998_1 - - primecount=7.6=ha894c9a_0 - - primecountpy=0.1.0=py39h8ee36c8_4 - - primesieve=11.0=hf0c8a7f_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py39hded5825_0 - - pthread-stubs=0.4=hc929b4f_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py39h0ca7971_0 - - pybind11-global=2.12.0=py39h0ca7971_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py39hf8f43b1_0 - - pyobjc-framework-cocoa=10.3.1=py39hf8f43b1_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py39ha09f3b3_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.9.19=h7a9c478_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py39hd253f6c_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.9=4_cp39 - - pythran=0.15.0=py39h5d0c61a_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py39h6e9494a_4 - - pyyaml=6.0.1=py39hdc70f33_1 - - pyzmq=26.0.3=py39h304b177_0 - - qd=2.3.22=h2beb688_1004 - - qhull=2020.2=h940c156_2 - - r-base=4.3.3=h4648a1f_3 - - r-lattice=0.22_6=r43hb2c329c_0 - - readline=8.2=h9e318b2_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h0dc2134_0 - - rpds-py=0.18.1=py39hf59063a_0 - - rpy2=3.5.11=py39r43hd01001f_3 - - rw=0.9=h10d778d_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py39ha321857_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - sigtool=0.1.3=h88f4db0_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h0d51a9f_1 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h28673e1_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hd2b2131_1 - - symmetrica=3.0.1=hf0c8a7f_0 - - sympow=2.023.6=h115ba6a_3 - - sympy=1.12.1=pypyh2585a3b_103 - - tachyon=0.99b6=h3a1d103_1002 - - tapi=1100.0.11=h9ce4665_0 - - tar=1.34=hcb2f6ea_1 - - tbb=2021.12.0=h3c5361c_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321hc47821c_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h1abcd95_1 - - tktable=2.10=hba9d6f1_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py39hded5825_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py39h6e9494a_0 - - unicodedata2=15.1.0=py39hdc70f33_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=h0dc2134_0 - - xorg-libxdmcp=1.1.3=h35c211d_0 - - xz=5.2.6=h775f41a_0 - - yaml=0.2.5=h0d85af4_2 - - zeromq=4.3.5=hde137ed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h87427d6_1 - - zstd=1.5.6=h915ae27_0 diff --git a/environment-3.9-macos.yml b/environment-3.9-macos.yml deleted file mode 100644 index 612b41003c9..00000000000 --- a/environment-3.9-macos.yml +++ /dev/null @@ -1,424 +0,0 @@ -name: sage -# Generated by conda-lock. -# platform: osx-arm64 -# input_hash: c72df9df3a2c7c120e9ff1ca936ae3527692a0de782793536087f2041f57d700 - -channels: - - conda-forge -dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py39h0f82c59_4 - - arpack=3.9.1=nompi_h593882a_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321hcd07c0c_1 - - automake=1.16.5=pl5321hce30654_0 - - babel=2.14.0=pyhd8ed1ab_0 - - bc=1.07.1=h3422bc3_0 - - bdw-gc=8.0.6=hc021e02_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osxarm64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=hca5e981_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hb547adb_1 - - brotli-bin=1.1.0=hb547adb_1 - - brotli-python=1.1.0=py39hb198ff7_1 - - bwidget=1.9.14=hce30654_1 - - bzip2=1.0.8=h93a5062_5 - - c-ares=1.28.1=h93a5062_0 - - c-compiler=1.7.0=h6aa9301_1 - - ca-certificates=2024.6.2=hf0a4a13_0 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cairo=1.18.0=hc6c324b_2 - - cctools=986=h4faf515_0 - - cctools_osx-arm64=986=h62378fb_0 - - cddlib=1!0.94m=h6d7a090_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py39he153c15_0 - - chardet=5.2.0=py39h2804cbe_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_h095aff0_8 - - clang-16=16.0.6=default_hb63da90_8 - - clang_impl_osx-arm64=16.0.6=hc421ffc_16 - - clang_osx-arm64=16.0.6=h54d7cd3_16 - - clangxx=16.0.6=default_h095aff0_8 - - clangxx_impl_osx-arm64=16.0.6=hcd7bac0_16 - - clangxx_osx-arm64=16.0.6=h54d7cd3_16 - - cliquer=1.22=h93a5062_1 - - cmake=3.29.6=had79d8f_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py39h2804cbe_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=h3808999_2 - - compiler-rt_osx-arm64=16.0.6=h3808999_2 - - compilers=1.7.0=hce30654_1 - - contourpy=1.2.1=py39h48c5dd5_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - curl=8.8.0=h653d890_0 - - cvxopt=1.3.2=py39hf9e8641_2 - - cxx-compiler=1.7.0=h2ffa867_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py39h070b2a8_0 - - cysignals=1.11.2=py39h65fc70a_3 - - cython=3.0.10=py39hf3050f2_0 - - debugpy=1.8.1=py39hf3050f2_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h9397a75_1203 - - ecl=23.9.9=h1d9728a_0 - - eclib=20231212=h7f07de4_0 - - ecm=7.0.5=h41d338b_0 - - editables=0.5=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=hebf3989_0 - - fflas-ffpack=2.5.0=h4bc3318_0 - - fftw=3.3.10=nompi_h6637ab6_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h82840c6_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py39hfea33bf_0 - - fortran-compiler=1.7.0=hafb19e3_1 - - fplll=5.4.5=hb7d509d_0 - - fpylll=0.6.1=py39h2eadeda_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=hadb7bae_2 - - fribidi=1.0.10=h27ca646_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he8f4e70_3 - - gap-defaults=4.12.2=hce30654_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=hbdafb3b_0 - - gettext=0.22.5=h8fbad5d_2 - - gettext-tools=0.22.5=h8fbad5d_2 - - gf2x=1.3.0=hdaa854c_2 - - gfan=0.6.2=hec08f5c_1003 - - gfortran=12.3.0=h1ca8e4b_1 - - gfortran_impl_osx-arm64=12.3.0=h53ed385_3 - - gfortran_osx-arm64=12.3.0=h57527a5_1 - - giac=1.9.0.21=h1c96721_1 - - giflib=5.2.2=h93a5062_0 - - givaro=4.2.0=h018886a_0 - - glpk=5.0=h6d7a090_0 - - gmp=6.3.0=h7bae524_2 - - gmpy2=2.1.5=py39h9bb7c0c_1 - - graphite2=1.3.13=hebf3989_1003 - - gsl=2.7=h6e638da_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h1836168_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hc8870d7_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h762ac30_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=hd73f12c_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.18.1=pyh707e725_3 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isl=0.26=imath32_h347afa1_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=hce30654_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py39h2804cbe_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py39h2804cbe_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kiwisolver=1.4.5=py39hbd775c9_1 - - krb5=1.21.2=h92f50d5_0 - - lcalc=2.0.5=h4a402bc_2 - - lcms2=2.16=ha0e7c42_0 - - ld64=711=h634c8be_0 - - ld64_osx-arm64=711=ha4bd21c_0 - - lerc=4.0.0=h9a09cb3_0 - - libasprintf=0.22.5=h8fbad5d_2 - - libasprintf-devel=0.22.5=h8fbad5d_2 - - libatomic_ops=7.6.14=h1a8c8d9_0 - - libblas=3.9.0=20_osxarm64_openblas - - libboost=1.85.0=h17eb2be_2 - - libboost-devel=1.85.0=hf450f58_2 - - libboost-headers=1.85.0=hce30654_2 - - libbraiding=1.2=hb7217d7_0 - - libbrial=1.2.12=h56a29cd_3 - - libbrotlicommon=1.1.0=hb547adb_1 - - libbrotlidec=1.1.0=hb547adb_1 - - libbrotlienc=1.1.0=hb547adb_1 - - libcblas=3.9.0=20_osxarm64_openblas - - libclang-cpp16=16.0.6=default_hb63da90_8 - - libcurl=8.8.0=h7b6f9a7_0 - - libcxx=17.0.6=h5f092b4_0 - - libdeflate=1.20=h93a5062_0 - - libedit=3.1.20191231=hc8eb9b7_2 - - libev=4.33=h93a5062_2 - - libexpat=2.6.2=hebf3989_0 - - libffi=3.4.2=h3422bc3_5 - - libflint=3.0.1=h28749a5_ntl_100 - - libgd=2.3.3=hfdf3952_9 - - libgettextpo=0.22.5=h8fbad5d_2 - - libgettextpo-devel=0.22.5=h8fbad5d_2 - - libgfortran=5.0.0=13_2_0_hd922786_3 - - libgfortran-devel_osx-arm64=12.3.0=hc62be1c_3 - - libgfortran5=13.2.0=hf226fd6_3 - - libglib=2.80.2=h59d46d9_1 - - libhomfly=1.02r6=h93a5062_1 - - libhwloc=2.10.0=default_h7685b71_1001 - - libiconv=1.17=h0d3ecfb_2 - - libintl=0.22.5=h8fbad5d_2 - - libintl-devel=0.22.5=h8fbad5d_2 - - libjpeg-turbo=3.0.0=hb547adb_1 - - liblapack=3.9.0=20_osxarm64_openblas - - liblapacke=3.9.0=20_osxarm64_openblas - - libllvm16=16.0.6=haab561b_3 - - libnghttp2=1.58.0=ha4dd798_1 - - libopenblas=0.3.25=openmp_h6c19121_0 - - libpng=1.6.43=h091b4b1_0 - - libsodium=1.0.18=h27ca646_1 - - libsqlite=3.46.0=hfb93653_0 - - libssh2=1.11.0=h7a5bd25_0 - - libtiff=4.6.0=h07db509_3 - - libtool=2.4.7=hb7217d7_0 - - libuv=1.48.0=h93a5062_0 - - libwebp=1.4.0=h54798ee_0 - - libwebp-base=1.4.0=h93a5062_0 - - libxcb=1.16=hf2054a2_0 - - libxml2=2.12.7=ha661575_1 - - libzlib=1.3.1=hfb2fe0b_1 - - linbox=1.7.0=h3afee3a_0 - - llvm-openmp=18.1.8=hde57baf_0 - - llvm-tools=16.0.6=haab561b_3 - - lrcalc=2.1=hebf3989_6 - - m4=1.4.18=h642e427_1001 - - m4ri=20140914=hc97c1ff_1006 - - m4rie=20150908=h22b9e9d_1002 - - make=4.3=he57ea6c_1 - - markupsafe=2.1.5=py39h17cfd9d_0 - - mathjax=3.2.2=hce30654_0 - - matplotlib=3.8.4=py39hdf13c20_2 - - matplotlib-base=3.8.4=py39h15359f4_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2bbcd85_2 - - memory-allocator=0.1.3=py39h0f82c59_0 - - metis=5.1.0=h13dd4ca_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - mpc=1.3.1=h91ba8db_0 - - mpfi=1.5.4=hbde5f5b_1001 - - mpfr=4.2.1=h41d338b_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h93a5062_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=hb89a1cb_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h420ef59_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=hbb3f309_1 - - numpy=1.26.4=py39h7aa2656_0 - - openblas=0.3.25=openmp_h55c453e_0 - - openjdk=22.0.1=hbeb2e11_0 - - openjpeg=2.5.2=h9f1df11_0 - - openssl=3.3.1=hfb2fe0b_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=h27ca646_0 - - pandoc=3.2.1=hce30654_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h5cb9fbc_0 - - pari=2.15.5=h4f2304c_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - patch=2.7.6=h27ca646_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h297a79d_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h4614cfb_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py39h3baf582_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=hebf3989_0 - - pkg-config=0.29.2=hab62308_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h93a5062_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h8b147cf_1006 - - pplpy=0.8.9=py39ha497ee3_1 - - primecount=7.6=hb6e4faa_0 - - primecountpy=0.1.0=py39hbd775c9_4 - - primesieve=11.0=hb7217d7_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py39hfea33bf_0 - - pthread-stubs=0.4=h27ca646_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py39h48c5dd5_0 - - pybind11-global=2.12.0=py39h48c5dd5_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py39h336d860_0 - - pyobjc-framework-cocoa=10.3.1=py39h336d860_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py39h17cfd9d_0 - - pysocks=1.7.1=pyha2e5f31_6 - - python=3.9.19=hd7ebdb9_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py39hf3050f2_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.9=4_cp39 - - pythran=0.15.0=py39h1261dcd_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py39h2804cbe_4 - - pyyaml=6.0.1=py39h0f82c59_1 - - pyzmq=26.0.3=py39he7f0319_0 - - qd=2.3.22=hbec66e7_1004 - - qhull=2020.2=hc021e02_2 - - r-base=4.3.3=h8112bfe_3 - - r-lattice=0.22_6=r43hd2d937b_0 - - readline=8.2=h92ec313_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hb547adb_0 - - rpds-py=0.18.1=py39h0019b8a_0 - - rpy2=3.5.11=py39r43hf4a74a7_3 - - rw=0.9=h93a5062_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py39h36c428d_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - sigtool=0.1.3=h44b9a77_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hb460b52_1 - - six=1.16.0=pyh6c4a22f_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h5838104_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf6fcff2_1 - - symmetrica=3.0.1=hb7217d7_0 - - sympow=2.023.6=hb0babe8_3 - - sympy=1.12.1=pypyh2585a3b_103 - - tachyon=0.99b6=hb8a568e_1002 - - tapi=1100.0.11=he4954df_0 - - tar=1.34=h7cb298e_1 - - tbb=2021.12.0=h420ef59_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321h9ea1dce_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h5083fa2_1 - - tktable=2.10=h1e387b8_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tornado=6.4.1=py39hfea33bf_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py39h2804cbe_0 - - unicodedata2=15.1.0=py39h0f82c59_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=2.2.2=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=hb547adb_0 - - xorg-libxdmcp=1.1.3=h27ca646_0 - - xz=5.2.6=h57fd34a_0 - - yaml=0.2.5=h3422bc3_2 - - zeromq=4.3.5=hcc0f68c_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=hfb2fe0b_1 - - zstd=1.5.6=hb46c0d2_0 diff --git a/environment-dev-3.10-linux-aarch64.yml b/environment-dev-3.10-linux-aarch64.yml deleted file mode 100644 index 111950c3a42..00000000000 --- a/environment-dev-3.10-linux-aarch64.yml +++ /dev/null @@ -1,489 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: linux-aarch64 -# input_hash: d36865ba776427275c808ea91ee0d71d1f653f57bf83e81fbb92003fd5db575e - -channels: - - conda-forge -dependencies: - - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - _sysroot_linux-aarch64_curr_repodata_hack=4=h57d6b7b_14 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.11=h31becfc_1 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py310hb299538_4 - - arpack=3.9.1=nompi_hd363cd0_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attr=2.5.1=h4e544f5_1 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321h2148fe1_1 - - automake=1.16.5=pl5321h8af1aa0_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=hf897c2e_0 - - bdw-gc=8.0.6=hd62202e_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=hf1166c9_7 - - binutils_impl_linux-aarch64=2.40=hf54a868_7 - - binutils_linux-aarch64=2.40=h1f91aba_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linuxaarch64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=ha990451_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h31becfc_1 - - brotli-bin=1.1.0=h31becfc_1 - - brotli-python=1.1.0=py310hbb3657e_1 - - bwidget=1.9.14=h8af1aa0_1 - - bzip2=1.0.8=h31becfc_5 - - c-ares=1.28.1=h31becfc_0 - - c-compiler=1.7.0=h31becfc_1 - - ca-certificates=2024.6.2=hcefe29a_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=h5c54ea9_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cddlib=1!0.94m=h719063d_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py310hce94938_0 - - chardet=5.2.0=py310hbbe02a8_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=h31becfc_1 - - cmake=3.29.6=h7042e5d_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py310h4c7bcd0_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=h8af1aa0_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py310h586407a_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - cryptography=42.0.8=py310hf601767_0 - - curl=8.8.0=h7daf2e0_0 - - cvxopt=1.3.2=py310he29a27f_2 - - cxx-compiler=1.7.0=h2a328a1_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py310h4cbba44_0 - - cysignals=1.11.2=py310h485802a_3 - - cython=3.0.10=py310hbb3657e_0 - - dbus=1.13.6=h12b9eeb_3 - - debugpy=1.8.1=py310hbb3657e_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hb12102e_1203 - - ecl=23.9.9=h6475f26_0 - - eclib=20231212=he26bab5_0 - - ecm=7.0.5=ha2d0fc4_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h2f0025b_0 - - fflas-ffpack=2.5.0=h503e619_0 - - fftw=3.3.10=nompi_h020dacd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=ha9a116f_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py310hb52b2da_0 - - fortran-compiler=1.7.0=h7048d53_1 - - fplll=5.4.5=hb3a790e_0 - - fpylll=0.6.1=py310hfdbf2a6_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=hf0a5ef3_2 - - fribidi=1.0.10=hb9de7d4_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=h597289e_3 - - gap-defaults=4.12.2=h8af1aa0_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=hdb0cc85_13 - - gcc_impl_linux-aarch64=12.3.0=h3d98823_13 - - gcc_linux-aarch64=12.3.0=ha52a6ea_9 - - gengetopt=2.23=h01db608_0 - - gf2x=1.3.0=h1b3b3a3_2 - - gfan=0.6.2=h5f589ec_1003 - - gfortran=12.3.0=hdb0cc85_13 - - gfortran_impl_linux-aarch64=12.3.0=h97ebfd2_13 - - gfortran_linux-aarch64=12.3.0=ha7b8e4b_9 - - gh=2.46.0=h652cbe9_0 - - giac=1.9.0.21=h04922a4_1 - - giflib=5.2.2=h31becfc_0 - - git=2.45.2=pl5321h011b5c6_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=h364d21b_0 - - glpk=5.0=h66325d0_0 - - gmp=6.3.0=h0a1ffab_2 - - gmpy2=2.1.5=py310h05bcf56_1 - - graphite2=1.3.13=h2f0025b_1003 - - gsl=2.7=h294027d_0 - - gxx=12.3.0=hdb0cc85_13 - - gxx_impl_linux-aarch64=12.3.0=hba91e99_13 - - gxx_linux-aarch64=12.3.0=h9d1f256_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h9812418_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h787c7f5_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h197073e_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h15043fe_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jeepney=0.8.0=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=h8af1aa0_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py310h4c7bcd0_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py310h4c7bcd0_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-aarch64=4.18.0=h5b4a56d_14 - - keyring=25.2.1=pyha804496_0 - - keyutils=1.6.1=h4e544f5_0 - - kiwisolver=1.4.5=py310he290b8a_1 - - krb5=1.21.2=hc419048_0 - - lcalc=2.0.5=he588f68_2 - - lcms2=2.16=h922389a_0 - - ld_impl_linux-aarch64=2.40=h9fc2d93_7 - - lerc=4.0.0=h4de3ea5_0 - - libatomic_ops=7.6.14=h4e544f5_0 - - libblas=3.9.0=20_linuxaarch64_openblas - - libboost=1.85.0=hb41fec8_2 - - libboost-devel=1.85.0=h37bb5a9_2 - - libboost-headers=1.85.0=h8af1aa0_2 - - libbraiding=1.2=hd600fc2_0 - - libbrial=1.2.12=h9429f74_3 - - libbrotlicommon=1.1.0=h31becfc_1 - - libbrotlidec=1.1.0=h31becfc_1 - - libbrotlienc=1.1.0=h31becfc_1 - - libcap=2.69=h883460d_0 - - libcblas=3.9.0=20_linuxaarch64_openblas - - libcbor=0.9.0=h01db608_0 - - libcups=2.3.3=h405e4a8_4 - - libcurl=8.8.0=h4e8248e_0 - - libdeflate=1.20=h31becfc_0 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=h31becfc_2 - - libexpat=2.6.2=h2f0025b_0 - - libffi=3.4.2=h3557bc0_5 - - libfido2=1.15.0=hab05c5e_0 - - libflint=3.0.1=hc392af7_ntl_100 - - libgcc-devel_linux-aarch64=12.3.0=h6144e03_113 - - libgcc-ng=13.2.0=he277a41_13 - - libgd=2.3.3=hcd22fd5_9 - - libgfortran-ng=13.2.0=he9431aa_13 - - libgfortran5=13.2.0=h2af0866_13 - - libglib=2.80.2=haee52c6_1 - - libgomp=13.2.0=he277a41_13 - - libhomfly=1.02r6=h31becfc_1 - - libhwloc=2.10.0=default_h3030c0e_1001 - - libiconv=1.17=h31becfc_2 - - libjpeg-turbo=3.0.0=h31becfc_1 - - liblapack=3.9.0=20_linuxaarch64_openblas - - liblapacke=3.9.0=20_linuxaarch64_openblas - - libnghttp2=1.58.0=hb0e430d_1 - - libnsl=2.0.1=h31becfc_0 - - libopenblas=0.3.25=pthreads_h5a5ec62_0 - - libpng=1.6.43=h194ca79_0 - - libsanitizer=12.3.0=h57e2e72_13 - - libsodium=1.0.18=hb9de7d4_1 - - libsqlite=3.46.0=hf51ef55_0 - - libssh2=1.11.0=h492db2e_0 - - libstdcxx-devel_linux-aarch64=12.3.0=h6144e03_113 - - libstdcxx-ng=13.2.0=h3f4de04_13 - - libtiff=4.6.0=hf980d43_3 - - libtool=2.4.7=h4de3ea5_0 - - libudev1=255=h31becfc_1 - - libuuid=2.38.1=hb4cce97_0 - - libuv=1.48.0=h31becfc_0 - - libwebp=1.4.0=h8b4e01b_0 - - libwebp-base=1.4.0=h31becfc_0 - - libxcb=1.16=h7935292_0 - - libxcrypt=4.4.36=h31becfc_1 - - libxml2=2.12.7=h49dc7a2_1 - - libzlib=1.3.1=h68df207_1 - - linbox=1.7.0=h681a5ee_0 - - llvm-openmp=18.1.8=hb063fc5_0 - - lrcalc=2.1=h2f0025b_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - m4=1.4.18=h516909a_1001 - - m4ri=20140914=hedfd65a_1006 - - m4rie=20150908=hf0a5ef3_1002 - - make=4.3=h309ac5b_1 - - markupsafe=2.1.5=py310h7c1f4a2_0 - - mathjax=3.2.2=h8af1aa0_0 - - matplotlib=3.8.4=py310hbbe02a8_2 - - matplotlib-base=3.8.4=py310h84f21c1_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h6475f26_2 - - memory-allocator=0.1.3=py310hb299538_0 - - metis=5.1.0=h2f0025b_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=hf4c8f4c_0 - - mpfi=1.5.4=h846f343_1001 - - mpfr=4.2.1=ha2d0fc4_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py310h6cd5c4a_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h31becfc_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h0425590_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h70be974_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=h0d7519b_1 - - numpy=1.26.4=py310hcbab775_0 - - openblas=0.3.25=pthreads_h339cbfa_0 - - openjdk=22.0.1=h3d4cd67_0 - - openjpeg=2.5.2=h0d9d63b_0 - - openssh=9.6p1=h04b8c23_0 - - openssl=3.3.1=h68df207_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=hb9de7d4_0 - - pandoc=3.2.1=h8af1aa0_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h399c48b_0 - - pari=2.15.5=h169c2a7_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=hf897c2e_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h070dd5b_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h31becfc_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py310h611336f_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h2f0025b_0 - - pkg-config=0.29.2=hb9de7d4_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h31becfc_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h984aac9_1006 - - pplpy=0.8.9=py310h6665419_1 - - primecount=7.9=hd600fc2_0 - - primecountpy=0.1.0=py310h586407a_4 - - primesieve=11.1=h2f0025b_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py310hb52b2da_0 - - pthread-stubs=0.4=hb9de7d4_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py310h586407a_0 - - pybind11-global=2.12.0=py310h586407a_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py310h4719f56_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py310h7c1f4a2_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.10.14=hbbe8eec_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py310hbb3657e_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.10=4_cp310 - - pythran=0.15.0=py310h5e48e15_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py310h4c7bcd0_4 - - pyyaml=6.0.1=py310hb299538_1 - - pyzmq=26.0.3=py310he875deb_0 - - qd=2.3.22=h05efe27_1004 - - qhull=2020.2=hd62202e_2 - - r-base=4.3.3=h7f20121_3 - - r-lattice=0.22_6=r43h25e906a_0 - - readline=8.2=h8fc344f_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h31becfc_0 - - rpds-py=0.18.1=py310h59d1b7a_0 - - rpy2=3.5.11=py310r43h8b6b5fc_3 - - ruamel.yaml=0.18.6=py310hb299538_0 - - ruamel.yaml.clib=0.2.8=py310hb299538_0 - - rw=0.9=h31becfc_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.3=py310hcbab775_1 - - secretstorage=3.3.3=py310hbbe02a8_2 - - sed=4.8=ha0d5d3d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hbe76a8a_1 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=hdc7ab3c_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=h3944111_1 - - symmetrica=3.0.1=hd600fc2_0 - - sympow=2.023.6=h157afb5_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-aarch64=2.17=h5b4a56d_14 - - tachyon=0.99b6=ha0bfc61_1002 - - tar=1.34=h048efde_0 - - tbb=2021.12.0=h70be974_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h17f021e_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h194ca79_0 - - tktable=2.10=h52f7bd3_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py310h03727f4_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py310h4c7bcd0_0 - - unicodedata2=15.1.0=py310hb299538_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-fixesproto=5.0=h3557bc0_1002 - - xorg-inputproto=2.3.2=h3557bc0_1002 - - xorg-kbproto=1.0.7=h3557bc0_1002 - - xorg-libice=1.1.1=h7935292_0 - - xorg-libsm=1.2.4=h5a01bc2_0 - - xorg-libx11=1.8.9=h08be655_1 - - xorg-libxau=1.0.11=h31becfc_0 - - xorg-libxdmcp=1.1.3=h3557bc0_0 - - xorg-libxext=1.3.4=h2a766a3_2 - - xorg-libxfixes=5.0.3=h3557bc0_1004 - - xorg-libxi=1.7.10=h3557bc0_0 - - xorg-libxrender=0.9.11=h7935292_0 - - xorg-libxt=1.3.0=h7935292_1 - - xorg-libxtst=1.2.3=hf897c2e_1002 - - xorg-recordproto=1.14.2=hf897c2e_1002 - - xorg-renderproto=0.11.1=h3557bc0_1002 - - xorg-xextproto=7.3.0=h2a766a3_1003 - - xorg-xproto=7.0.31=h3557bc0_1007 - - xz=5.2.6=h9cdd2b7_0 - - yaml=0.2.5=hf897c2e_2 - - zeromq=4.3.5=h28faeed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h68df207_1 - - zstd=1.5.6=h02f22dd_0 diff --git a/environment-dev-3.10-linux.yml b/environment-dev-3.10-linux.yml deleted file mode 100644 index 4e35ec5d152..00000000000 --- a/environment-dev-3.10-linux.yml +++ /dev/null @@ -1,536 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: linux-64 -# input_hash: f5ac6bc66f134451e0ec73f0a00b8da508df8c7c642f57231ab559a7c63f8ee0 - -channels: - - conda-forge -dependencies: - - _libgcc_mutex=0.1=conda_forge - - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.12=h4ab18f5_0 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py310h2372a71_4 - - arpack=3.9.1=nompi_h77f6705_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attr=2.5.1=h166bdaf_1 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321h2b4cb7a_1 - - automake=1.16.5=pl5321ha770c72_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=h7f98852_0 - - bdw-gc=8.0.6=h4bd325d_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=h4852527_7 - - binutils_impl_linux-64=2.40=ha1999f0_7 - - binutils_linux-64=2.40=hb3c18ed_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linux64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h44aadfe_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hd590300_1 - - brotli-bin=1.1.0=hd590300_1 - - brotli-python=1.1.0=py310hc6cd4ac_1 - - bwidget=1.9.14=ha770c72_1 - - bzip2=1.0.8=hd590300_5 - - c-ares=1.28.1=hd590300_0 - - c-compiler=1.7.0=hd590300_1 - - ca-certificates=2024.6.2=hbcca054_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=hbb29018_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cddlib=1!0.94m=h9202a9a_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py310h2fee648_0 - - chardet=5.2.0=py310hff52083_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=hd590300_1 - - cmake=3.29.6=hcafd917_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py310hff52083_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=ha770c72_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py310hd41b1e2_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - cryptography=42.0.8=py310hb1bd9d3_0 - - curl=8.8.0=he654da7_0 - - cvxopt=1.3.2=py310h7b0674a_2 - - cxx-compiler=1.7.0=h00ab1b0_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py310h14ed79e_0 - - cysignals=1.11.2=py310h945e7c7_3 - - cython=3.0.10=py310hc6cd4ac_0 - - dbus=1.13.6=h5008d03_3 - - debugpy=1.8.1=py310hc6cd4ac_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hd9d9efa_1203 - - ecl=23.9.9=hed6455c_0 - - eclib=20231212=h96f522a_0 - - ecm=7.0.5=h9458935_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h59595ed_0 - - fflas-ffpack=2.5.0=h4f9960b_0 - - fftw=3.3.10=nompi_hf1063bd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h14ed4e7_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py310hc51659f_0 - - fortran-compiler=1.7.0=heb67821_1 - - fplll=5.4.5=h384768b_0 - - fpylll=0.6.1=py310h7e26f94_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=h267a509_2 - - fribidi=1.0.10=h36c2ea0_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he9a28a4_3 - - gap-defaults=4.12.2=ha770c72_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=h915e2ae_13 - - gcc_impl_linux-64=12.3.0=h58ffeeb_13 - - gcc_linux-64=12.3.0=h9528a6a_9 - - gengetopt=2.23=h9c3ff4c_0 - - gettext=0.22.5=h59595ed_2 - - gettext-tools=0.22.5=h59595ed_2 - - gf2x=1.3.0=ha476b99_2 - - gfan=0.6.2=hb86e20a_1003 - - gfortran=12.3.0=h915e2ae_13 - - gfortran_impl_linux-64=12.3.0=h8f2110c_13 - - gfortran_linux-64=12.3.0=h5877db1_9 - - gh=2.52.0=he0e2781_0 - - giac=1.9.0.21=h673759e_1 - - giflib=5.2.2=hd590300_0 - - git=2.45.2=pl5321ha099dd3_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=hb789bce_0 - - glib=2.80.2=h8a4344b_1 - - glib-tools=2.80.2=h73ef956_1 - - glpk=5.0=h445213a_0 - - gmp=6.3.0=hac33072_2 - - gmpy2=2.1.5=py310hc7909c9_1 - - graphite2=1.3.13=h59595ed_1003 - - gsl=2.7=he838d99_0 - - gst-plugins-base=1.24.5=hbaaba92_0 - - gstreamer=1.24.5=haf2f30d_0 - - gxx=12.3.0=h915e2ae_13 - - gxx_impl_linux-64=12.3.0=h2a574ab_13 - - gxx_linux-64=12.3.0=ha28b414_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=hfac3d4d_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h59595ed_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hef0740d_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h623f65a_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jeepney=0.8.0=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=ha770c72_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py310hff52083_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py310hff52083_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-64=2.6.32=he073ed8_17 - - keyring=25.2.1=pyha804496_0 - - keyutils=1.6.1=h166bdaf_0 - - kiwisolver=1.4.5=py310hd41b1e2_1 - - krb5=1.21.2=h659d440_0 - - lame=3.100=h166bdaf_1003 - - lcalc=2.0.5=h5aac1b6_2 - - lcms2=2.16=hb7c19ff_0 - - ld_impl_linux-64=2.40=hf3520f5_7 - - lerc=4.0.0=h27087fc_0 - - libasprintf=0.22.5=h661eb56_2 - - libasprintf-devel=0.22.5=h661eb56_2 - - libatomic_ops=7.6.14=h166bdaf_0 - - libblas=3.9.0=20_linux64_openblas - - libboost=1.85.0=hba137d9_2 - - libboost-devel=1.85.0=h00ab1b0_2 - - libboost-headers=1.85.0=ha770c72_2 - - libbraiding=1.2=hcb278e6_0 - - libbrial=1.2.12=h76af697_3 - - libbrotlicommon=1.1.0=hd590300_1 - - libbrotlidec=1.1.0=hd590300_1 - - libbrotlienc=1.1.0=hd590300_1 - - libcap=2.69=h0f662aa_0 - - libcblas=3.9.0=20_linux64_openblas - - libcbor=0.10.2=hcb278e6_0 - - libclang-cpp15=15.0.7=default_h127d8a8_5 - - libclang13=18.1.8=default_h6ae225f_0 - - libcups=2.3.3=h4637d8d_4 - - libcurl=8.8.0=hca28451_0 - - libdeflate=1.20=hd590300_0 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=hd590300_2 - - libevent=2.1.12=hf998b51_1 - - libexpat=2.6.2=h59595ed_0 - - libffi=3.4.2=h7f98852_5 - - libfido2=1.15.0=hdd1f21f_0 - - libflac=1.4.3=h59595ed_0 - - libflint=3.0.1=h5f2e117_ntl_100 - - libgcc-devel_linux-64=12.3.0=h6b66f73_113 - - libgcc-ng=13.2.0=h77fa898_13 - - libgcrypt=1.10.3=hd590300_0 - - libgd=2.3.3=h119a65a_9 - - libgettextpo=0.22.5=h59595ed_2 - - libgettextpo-devel=0.22.5=h59595ed_2 - - libgfortran-ng=13.2.0=h69a702a_13 - - libgfortran5=13.2.0=h3d2ce59_13 - - libglib=2.80.2=h8a4344b_1 - - libgomp=13.2.0=h77fa898_13 - - libgpg-error=1.49=h4f305b6_0 - - libhomfly=1.02r6=hd590300_1 - - libhwloc=2.10.0=default_h5622ce7_1001 - - libiconv=1.17=hd590300_2 - - libjpeg-turbo=3.0.0=hd590300_1 - - liblapack=3.9.0=20_linux64_openblas - - liblapacke=3.9.0=20_linux64_openblas - - libllvm15=15.0.7=hb3ce162_4 - - libllvm18=18.1.8=hc9dba70_0 - - libnghttp2=1.58.0=h47da74e_1 - - libnsl=2.0.1=hd590300_0 - - libogg=1.3.5=h4ab18f5_0 - - libopenblas=0.3.25=pthreads_h413a1c8_0 - - libopus=1.3.1=h7f98852_1 - - libpng=1.6.43=h2797004_0 - - libpq=16.3=ha72fbe1_0 - - libsanitizer=12.3.0=hb8811af_13 - - libsndfile=1.2.2=hc60ed4a_1 - - libsodium=1.0.18=h36c2ea0_1 - - libsqlite=3.46.0=hde9e2c9_0 - - libssh2=1.11.0=h0841786_0 - - libstdcxx-devel_linux-64=12.3.0=h6b66f73_113 - - libstdcxx-ng=13.2.0=hc0a3c3a_13 - - libsystemd0=255=h3516f8a_1 - - libtiff=4.6.0=h1dd3fc0_3 - - libtool=2.4.7=h27087fc_0 - - libudev1=255=h3f72095_1 - - libuuid=2.38.1=h0b41bf4_0 - - libuv=1.48.0=hd590300_0 - - libvorbis=1.3.7=h9c3ff4c_0 - - libwebp=1.4.0=h2c329e2_0 - - libwebp-base=1.4.0=hd590300_0 - - libxcb=1.16=hd590300_0 - - libxcrypt=4.4.36=hd590300_1 - - libxkbcommon=1.7.0=h2c5496b_1 - - libxml2=2.12.7=hc051c1a_1 - - libzlib=1.3.1=h4ab18f5_1 - - linbox=1.7.0=ha329b40_0 - - llvm-openmp=18.1.8=hf5423f3_0 - - lrcalc=2.1=h59595ed_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - lz4-c=1.9.4=hcb278e6_0 - - m4=1.4.18=h516909a_1001 - - m4ri=20140914=hae5d5c5_1006 - - m4rie=20150908=h267a509_1002 - - make=4.3=hd18ef5c_1 - - markupsafe=2.1.5=py310h2372a71_0 - - mathjax=3.2.2=ha770c72_0 - - matplotlib=3.8.4=py310hff52083_2 - - matplotlib-base=3.8.4=py310hef631a5_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=hed6455c_2 - - memory-allocator=0.1.3=py310h2372a71_0 - - meson=1.5.2=pyhd8ed1ab_0 - - meson-python=0.15.0=pyh0c530f3_0 - - metis=5.1.0=h59595ed_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=hfe3b2da_0 - - mpfi=1.5.4=h9f54685_1001 - - mpfr=4.2.1=h9458935_1 - - mpg123=1.32.6=h59595ed_0 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py310h25c7140_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - mysql-common=8.3.0=hf1915f5_4 - - mysql-libs=8.3.0=hca2cd23_4 - - nauty=2.8.8=hd590300_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h59595ed_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h297d8ca_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - nspr=4.35=h27087fc_0 - - nss=3.101=h593d115_0 - - ntl=11.4.3=hef3c4d3_1 - - numpy=1.26.4=py310hb13e2d6_0 - - openblas=0.3.25=pthreads_h7a3da1a_0 - - openjdk=21.0.2=haa376d0_0 - - openjpeg=2.5.2=h488ebb8_0 - - openssh=9.6p1=h2d3b35a_0 - - openssl=3.3.1=h4ab18f5_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=h36c2ea0_0 - - pandoc=3.2.1=ha770c72_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h84a9a3c_0 - - pari=2.15.5=h4d4ae9b_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=h7f98852_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h0f59acf_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_hd590300_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py310hebfe307_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.2=h59595ed_0 - - pkg-config=0.29.2=h36c2ea0_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=hd590300_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h6ec01c2_1006 - - pplpy=0.8.9=py310h18554fa_1 - - primecount=7.9=hcb278e6_0 - - primecountpy=0.1.0=py310hd41b1e2_4 - - primesieve=11.1=h59595ed_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py310hc51659f_0 - - pthread-stubs=0.4=h36c2ea0_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pulseaudio-client=17.0=hb77b528_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py310hd41b1e2_0 - - pybind11-global=2.12.0=py310hd41b1e2_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py310he421c4c_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyqt=5.15.9=py310h04931ad_5 - - pyqt5-sip=12.12.2=py310hc6cd4ac_5 - - pyrsistent=0.20.0=py310h2372a71_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.10.14=hd12c33a_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py310hc6cd4ac_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.10=4_cp310 - - pythran=0.15.0=py310hcb52e73_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py310hff52083_4 - - pyyaml=6.0.1=py310h2372a71_1 - - pyzmq=26.0.3=py310h6883aea_0 - - qd=2.3.22=h2cc385e_1004 - - qhull=2020.2=h4bd325d_2 - - qt-main=5.15.8=ha2b5568_22 - - r-base=4.3.3=he2d9a6e_3 - - r-lattice=0.22_6=r43h57805ef_0 - - readline=8.2=h8228510_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hd590300_0 - - rpds-py=0.18.1=py310he421c4c_0 - - rpy2=3.5.11=py310r43h1f7b6fc_3 - - ruamel.yaml=0.18.6=py310h2372a71_0 - - ruamel.yaml.clib=0.2.8=py310h2372a71_0 - - rw=0.9=hd590300_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py310hb13e2d6_0 - - secretstorage=3.3.3=py310hff52083_2 - - sed=4.8=he412f7d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h33f5c3f_1 - - sip=6.7.12=py310hc6cd4ac_0 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h6d4b2fc_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf4753ba_1 - - symmetrica=3.0.1=hcb278e6_0 - - sympow=2.023.6=hc6ab17c_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-64=2.12=he073ed8_17 - - tachyon=0.99b6=hba7d16a_1002 - - tar=1.34=hb2e2bae_1 - - tbb=2021.12.0=h297d8ca_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h0f457ee_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=noxft_h4845f30_101 - - tktable=2.10=h8bc8fbc_6 - - toml=0.10.2=pyhd8ed1ab_0 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py310hc51659f_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py310hff52083_0 - - unicodedata2=15.1.0=py310h2372a71_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xcb-util=0.4.1=hb711507_2 - - xcb-util-image=0.4.0=hb711507_2 - - xcb-util-keysyms=0.4.1=hb711507_0 - - xcb-util-renderutil=0.3.10=hb711507_0 - - xcb-util-wm=0.4.2=hb711507_0 - - xkeyboard-config=2.42=h4ab18f5_0 - - xorg-fixesproto=5.0=h7f98852_1002 - - xorg-inputproto=2.3.2=h7f98852_1002 - - xorg-kbproto=1.0.7=h7f98852_1002 - - xorg-libice=1.1.1=hd590300_0 - - xorg-libsm=1.2.4=h7391055_0 - - xorg-libx11=1.8.9=hb711507_1 - - xorg-libxau=1.0.11=hd590300_0 - - xorg-libxdmcp=1.1.3=h7f98852_0 - - xorg-libxext=1.3.4=h0b41bf4_2 - - xorg-libxfixes=5.0.3=h7f98852_1004 - - xorg-libxi=1.7.10=h7f98852_0 - - xorg-libxrender=0.9.11=hd590300_0 - - xorg-libxt=1.3.0=hd590300_1 - - xorg-libxtst=1.2.3=h7f98852_1002 - - xorg-recordproto=1.14.2=h7f98852_1002 - - xorg-renderproto=0.11.1=h7f98852_1002 - - xorg-xextproto=7.3.0=h0b41bf4_1003 - - xorg-xf86vidmodeproto=2.3.1=h7f98852_1002 - - xorg-xproto=7.0.31=h7f98852_1007 - - xz=5.2.6=h166bdaf_0 - - yaml=0.2.5=h7f98852_2 - - zeromq=4.3.5=h75354e8_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h4ab18f5_1 - - zstd=1.5.6=ha6fb4c9_0 diff --git a/environment-dev-3.10-macos-x86_64.yml b/environment-dev-3.10-macos-x86_64.yml deleted file mode 100644 index c3f4696d491..00000000000 --- a/environment-dev-3.10-macos-x86_64.yml +++ /dev/null @@ -1,470 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: osx-64 -# input_hash: 6f780a484a3cb4f5357ae4fc25f621ccf74f1cb625cb47cbd49f37ed9e7d3f46 - -channels: - - conda-forge -dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py310h6729b98_4 - - arpack=3.9.1=nompi_hf81eadf_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321hed12c24_1 - - automake=1.16.5=pl5321h694c41f_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=h0d85af4_0 - - bdw-gc=8.0.6=h940c156_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osx64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h07eb623_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h0dc2134_1 - - brotli-bin=1.1.0=h0dc2134_1 - - brotli-python=1.1.0=py310h9e9d8ca_1 - - bwidget=1.9.14=h694c41f_1 - - bzip2=1.0.8=h10d778d_5 - - c-ares=1.28.1=h10d778d_0 - - c-compiler=1.7.0=h282daa2_1 - - ca-certificates=2024.6.2=h8857fd0_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=h9f650ed_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cctools=986=h40f6528_0 - - cctools_osx-64=986=ha1c5b94_0 - - cddlib=1!0.94m=h0f52abe_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py310hdca579f_0 - - chardet=5.2.0=py310h2ec42d9_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_ha3b9224_8 - - clang-16=16.0.6=default_h4c8afb6_8 - - clang_impl_osx-64=16.0.6=h8787910_16 - - clang_osx-64=16.0.6=hb91bd55_16 - - clangxx=16.0.6=default_ha3b9224_8 - - clangxx_impl_osx-64=16.0.6=h6d92fbe_16 - - clangxx_osx-64=16.0.6=hb91bd55_16 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=h10d778d_1 - - cmake=3.29.6=h749d262_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py310h2ec42d9_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=ha38d28d_2 - - compiler-rt_osx-64=16.0.6=ha38d28d_2 - - compilers=1.7.0=h694c41f_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py310hb3b189b_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - curl=8.8.0=hea67d85_0 - - cvxopt=1.3.2=py310h1fac3e1_2 - - cxx-compiler=1.7.0=h7728843_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py310hc7df965_0 - - cysignals=1.11.2=py310h8c82e65_3 - - cython=3.0.10=py310h5daac23_0 - - debugpy=1.8.1=py310h5daac23_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h6e329d1_1203 - - ecl=23.9.9=h2b27fa8_0 - - eclib=20231212=h02435c3_0 - - ecm=7.0.5=h4f6b447_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h73e2aa4_0 - - fflas-ffpack=2.5.0=h5898d61_0 - - fftw=3.3.10=nompi_h292e606_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h5bb23bf_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py310h936d840_0 - - fortran-compiler=1.7.0=h6c2ab21_1 - - fplll=5.4.5=hb7981ad_0 - - fpylll=0.6.1=py310h65a3d7e_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=h60636b9_2 - - fribidi=1.0.10=hbcb3906_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=hc16eb5f_3 - - gap-defaults=4.12.2=h694c41f_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=he49afe7_0 - - gettext=0.22.5=h5ff76d1_2 - - gettext-tools=0.22.5=h5ff76d1_2 - - gf2x=1.3.0=hb2a7efb_2 - - gfan=0.6.2=hd793b56_1003 - - gfortran=12.3.0=h2c809b3_1 - - gfortran_impl_osx-64=12.3.0=hc328e78_3 - - gfortran_osx-64=12.3.0=h18f7dce_1 - - gh=2.52.0=he13f2d6_0 - - giac=1.9.0.21=h92f3f65_1 - - giflib=5.2.2=h10d778d_0 - - git=2.45.2=pl5321hb0c6a96_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=h1b3d6f7_0 - - glpk=5.0=h3cb5acd_0 - - gmp=6.3.0=hf036a51_2 - - gmpy2=2.1.5=py310h0310db1_1 - - graphite2=1.3.13=h73e2aa4_1003 - - gsl=2.7=h93259b0_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h053f038_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hf5e326d_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hde4452d_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h61918c1_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isl=0.26=imath32_h2e86a7b_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.9=h694c41f_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py310h2ec42d9_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py310h2ec42d9_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - keyring=25.2.1=pyh534df25_0 - - kiwisolver=1.4.5=py310h88cfcbd_1 - - krb5=1.21.2=hb884880_0 - - lcalc=2.0.5=h547a6ed_2 - - lcms2=2.16=ha2f27b4_0 - - ld64=711=ha02d983_0 - - ld64_osx-64=711=ha20a434_0 - - lerc=4.0.0=hb486fe8_0 - - libasprintf=0.22.5=h5ff76d1_2 - - libasprintf-devel=0.22.5=h5ff76d1_2 - - libatomic_ops=7.6.14=hb7f2c08_0 - - libblas=3.9.0=20_osx64_openblas - - libboost=1.85.0=h739af76_2 - - libboost-devel=1.85.0=h2b186f8_2 - - libboost-headers=1.85.0=h694c41f_2 - - libbraiding=1.2=hf0c8a7f_0 - - libbrial=1.2.12=h81e9653_3 - - libbrotlicommon=1.1.0=h0dc2134_1 - - libbrotlidec=1.1.0=h0dc2134_1 - - libbrotlienc=1.1.0=h0dc2134_1 - - libcblas=3.9.0=20_osx64_openblas - - libcbor=0.10.2=hf0c8a7f_0 - - libclang-cpp16=16.0.6=default_h4c8afb6_8 - - libcurl=8.8.0=hf9fcc65_0 - - libcxx=17.0.6=h88467a6_0 - - libdeflate=1.20=h49d49c5_0 - - libedit=3.1.20191231=h0678c8f_2 - - libev=4.33=h10d778d_2 - - libexpat=2.6.2=h73e2aa4_0 - - libffi=3.4.2=h0d85af4_5 - - libfido2=1.15.0=h41b28d8_0 - - libflint=3.0.1=h5d15de0_ntl_100 - - libgd=2.3.3=h0dceb68_9 - - libgettextpo=0.22.5=h5ff76d1_2 - - libgettextpo-devel=0.22.5=h5ff76d1_2 - - libgfortran=5.0.0=13_2_0_h97931a8_3 - - libgfortran-devel_osx-64=12.3.0=h0b6f5ec_3 - - libgfortran5=13.2.0=h2873a65_3 - - libglib=2.80.2=h736d271_1 - - libhomfly=1.02r6=h10d778d_1 - - libhwloc=2.10.0=default_h456cccd_1001 - - libiconv=1.17=hd75f5a5_2 - - libintl=0.22.5=h5ff76d1_2 - - libintl-devel=0.22.5=h5ff76d1_2 - - libjpeg-turbo=3.0.0=h0dc2134_1 - - liblapack=3.9.0=20_osx64_openblas - - liblapacke=3.9.0=20_osx64_openblas - - libllvm16=16.0.6=hbedff68_3 - - libnghttp2=1.58.0=h64cf6d3_1 - - libopenblas=0.3.25=openmp_hfef2a42_0 - - libpng=1.6.43=h92b6c6a_0 - - libsodium=1.0.18=hbcb3906_1 - - libsqlite=3.46.0=h1b8f9f3_0 - - libssh2=1.11.0=hd019ec5_0 - - libtiff=4.6.0=h129831d_3 - - libtool=2.4.7=hf0c8a7f_0 - - libuv=1.48.0=h67532ce_0 - - libwebp=1.4.0=hc207709_0 - - libwebp-base=1.4.0=h10d778d_0 - - libxcb=1.16=h0dc2134_0 - - libxml2=2.12.7=h3e169fe_1 - - libzlib=1.3.1=h87427d6_1 - - linbox=1.7.0=h7061c92_0 - - llvm-openmp=18.1.8=h15ab845_0 - - llvm-tools=16.0.6=hbedff68_3 - - lrcalc=2.1=h73e2aa4_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - m4=1.4.18=haf1e3a3_1001 - - m4ri=20140914=hd82a5f3_1006 - - m4rie=20150908=hc616cfc_1002 - - make=4.3=h22f3db7_1 - - markupsafe=2.1.5=py310hb372a2b_0 - - mathjax=3.2.2=h694c41f_0 - - matplotlib=3.8.4=py310h2ec42d9_2 - - matplotlib-base=3.8.4=py310h7ea1ff3_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2b27fa8_2 - - memory-allocator=0.1.3=py310h6729b98_0 - - metis=5.1.0=he965462_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=h81bd1dd_0 - - mpfi=1.5.4=h52b28e3_1001 - - mpfr=4.2.1=h4f6b447_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py310h5334dd0_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h10d778d_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h5846eda_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h3c5361c_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=h0ab3c2f_1 - - numpy=1.26.4=py310h4bfa8fc_0 - - openblas=0.3.25=openmp_h6794695_0 - - openjdk=22.0.1=h2d185b6_0 - - openjpeg=2.5.2=h7310d3a_0 - - openssh=9.6p1=h6dd4ff7_0 - - openssl=3.3.1=h87427d6_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=hbcb3906_0 - - pandoc=3.2.1=h694c41f_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h880b76c_0 - - pari=2.15.5=h7ba67ff_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=hbcf498f_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h7634a1b_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h10d778d_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py310h2fdc51f_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h73e2aa4_0 - - pkg-config=0.29.2=ha3d46e9_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h10d778d_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=ha60d53e_1006 - - pplpy=0.8.9=py310hbe8aec3_1 - - primecount=7.6=ha894c9a_0 - - primecountpy=0.1.0=py310h88cfcbd_4 - - primesieve=11.0=hf0c8a7f_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py310h936d840_0 - - pthread-stubs=0.4=hc929b4f_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py310hb3b189b_0 - - pybind11-global=2.12.0=py310hb3b189b_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py310h12a1ced_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py310h445dc1f_0 - - pyobjc-framework-cocoa=10.3.1=py310h445dc1f_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py310hb372a2b_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.10.14=h00d2728_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py310h5daac23_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.10=4_cp310 - - pythran=0.15.0=py310h076e4b7_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py310h2ec42d9_4 - - pyyaml=6.0.1=py310h6729b98_1 - - pyzmq=26.0.3=py310he0bbd50_0 - - qd=2.3.22=h2beb688_1004 - - qhull=2020.2=h940c156_2 - - r-base=4.3.3=h4648a1f_3 - - r-lattice=0.22_6=r43hb2c329c_0 - - readline=8.2=h9e318b2_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h0dc2134_0 - - rpds-py=0.18.1=py310h12a1ced_0 - - rpy2=3.5.11=py310r43hf0b6da5_3 - - ruamel.yaml=0.18.6=py310hb372a2b_0 - - ruamel.yaml.clib=0.2.8=py310hb372a2b_0 - - rw=0.9=h10d778d_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py310h3f1db6d_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - sigtool=0.1.3=h88f4db0_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h0d51a9f_1 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h28673e1_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hd2b2131_1 - - symmetrica=3.0.1=hf0c8a7f_0 - - sympow=2.023.6=h115ba6a_3 - - sympy=1.12.1=pypyh2585a3b_103 - - tachyon=0.99b6=h3a1d103_1002 - - tapi=1100.0.11=h9ce4665_0 - - tar=1.34=hcb2f6ea_1 - - tbb=2021.12.0=h3c5361c_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321hc47821c_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h1abcd95_1 - - tktable=2.10=hba9d6f1_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py310h936d840_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py310h2ec42d9_0 - - unicodedata2=15.1.0=py310h6729b98_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=h0dc2134_0 - - xorg-libxdmcp=1.1.3=h35c211d_0 - - xz=5.2.6=h775f41a_0 - - yaml=0.2.5=h0d85af4_2 - - zeromq=4.3.5=hde137ed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h87427d6_1 - - zstd=1.5.6=h915ae27_0 diff --git a/environment-dev-3.10-macos.yml b/environment-dev-3.10-macos.yml deleted file mode 100644 index 097508c3f6f..00000000000 --- a/environment-dev-3.10-macos.yml +++ /dev/null @@ -1,472 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: osx-arm64 -# input_hash: c03964bb63187e8dea2adbfa9332f08fbdb1b89d359248a94c39f3af0db26d90 - -channels: - - conda-forge -dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py310h2aa6e3c_4 - - arpack=3.9.1=nompi_h593882a_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321hcd07c0c_1 - - automake=1.16.5=pl5321hce30654_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=h3422bc3_0 - - bdw-gc=8.0.6=hc021e02_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osxarm64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=hca5e981_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hb547adb_1 - - brotli-bin=1.1.0=hb547adb_1 - - brotli-python=1.1.0=py310h1253130_1 - - bwidget=1.9.14=hce30654_1 - - bzip2=1.0.8=h93a5062_5 - - c-ares=1.28.1=h93a5062_0 - - c-compiler=1.7.0=h6aa9301_1 - - ca-certificates=2024.6.2=hf0a4a13_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=hc6c324b_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cctools=986=h4faf515_0 - - cctools_osx-arm64=986=h62378fb_0 - - cddlib=1!0.94m=h6d7a090_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py310hdcd7c05_0 - - chardet=5.2.0=py310hbe9552e_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_h095aff0_8 - - clang-16=16.0.6=default_hb63da90_8 - - clang_impl_osx-arm64=16.0.6=hc421ffc_16 - - clang_osx-arm64=16.0.6=h54d7cd3_16 - - clangxx=16.0.6=default_h095aff0_8 - - clangxx_impl_osx-arm64=16.0.6=hcd7bac0_16 - - clangxx_osx-arm64=16.0.6=h54d7cd3_16 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=h93a5062_1 - - cmake=3.29.6=had79d8f_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py310hbe9552e_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=h3808999_2 - - compiler-rt_osx-arm64=16.0.6=h3808999_2 - - compilers=1.7.0=hce30654_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py310h21239e6_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - curl=8.8.0=h653d890_0 - - cvxopt=1.3.2=py310h7e4e7d1_2 - - cxx-compiler=1.7.0=h2ffa867_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py310h5e3d6bc_0 - - cysignals=1.11.2=py310hfd3b3fe_3 - - cython=3.0.10=py310h692a8b6_0 - - debugpy=1.8.1=py310h692a8b6_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h9397a75_1203 - - ecl=23.9.9=h1d9728a_0 - - eclib=20231212=h7f07de4_0 - - ecm=7.0.5=h41d338b_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=hebf3989_0 - - fflas-ffpack=2.5.0=h4bc3318_0 - - fftw=3.3.10=nompi_h6637ab6_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h82840c6_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py310ha6dd24b_0 - - fortran-compiler=1.7.0=hafb19e3_1 - - fplll=5.4.5=hb7d509d_0 - - fpylll=0.6.1=py310hd9be144_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=hadb7bae_2 - - fribidi=1.0.10=h27ca646_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he8f4e70_3 - - gap-defaults=4.12.2=hce30654_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=hbdafb3b_0 - - gettext=0.22.5=h8fbad5d_2 - - gettext-tools=0.22.5=h8fbad5d_2 - - gf2x=1.3.0=hdaa854c_2 - - gfan=0.6.2=hec08f5c_1003 - - gfortran=12.3.0=h1ca8e4b_1 - - gfortran_impl_osx-arm64=12.3.0=h53ed385_3 - - gfortran_osx-arm64=12.3.0=h57527a5_1 - - gh=2.52.0=h163aea0_0 - - giac=1.9.0.21=h1c96721_1 - - giflib=5.2.2=h93a5062_0 - - git=2.45.2=pl5321h41514c7_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=h018886a_0 - - glpk=5.0=h6d7a090_0 - - gmp=6.3.0=h7bae524_2 - - gmpy2=2.1.5=py310h3bc658a_1 - - graphite2=1.3.13=hebf3989_1003 - - gsl=2.7=h6e638da_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h1836168_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hc8870d7_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h762ac30_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=hd73f12c_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isl=0.26=imath32_h347afa1_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=hce30654_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py310hbe9552e_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py310hbe9552e_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - keyring=25.2.1=pyh534df25_0 - - kiwisolver=1.4.5=py310h38f39d4_1 - - krb5=1.21.2=h92f50d5_0 - - lcalc=2.0.5=h4a402bc_2 - - lcms2=2.16=ha0e7c42_0 - - ld64=711=h634c8be_0 - - ld64_osx-arm64=711=ha4bd21c_0 - - lerc=4.0.0=h9a09cb3_0 - - libasprintf=0.22.5=h8fbad5d_2 - - libasprintf-devel=0.22.5=h8fbad5d_2 - - libatomic_ops=7.6.14=h1a8c8d9_0 - - libblas=3.9.0=20_osxarm64_openblas - - libboost=1.85.0=h17eb2be_2 - - libboost-devel=1.85.0=hf450f58_2 - - libboost-headers=1.85.0=hce30654_2 - - libbraiding=1.2=hb7217d7_0 - - libbrial=1.2.12=h56a29cd_3 - - libbrotlicommon=1.1.0=hb547adb_1 - - libbrotlidec=1.1.0=hb547adb_1 - - libbrotlienc=1.1.0=hb547adb_1 - - libcblas=3.9.0=20_osxarm64_openblas - - libcbor=0.10.2=hb7217d7_0 - - libclang-cpp16=16.0.6=default_hb63da90_8 - - libcurl=8.8.0=h7b6f9a7_0 - - libcxx=17.0.6=h5f092b4_0 - - libdeflate=1.20=h93a5062_0 - - libedit=3.1.20191231=hc8eb9b7_2 - - libev=4.33=h93a5062_2 - - libexpat=2.6.2=hebf3989_0 - - libffi=3.4.2=h3422bc3_5 - - libfido2=1.15.0=h9d74d49_0 - - libflint=3.0.1=h28749a5_ntl_100 - - libgd=2.3.3=hfdf3952_9 - - libgettextpo=0.22.5=h8fbad5d_2 - - libgettextpo-devel=0.22.5=h8fbad5d_2 - - libgfortran=5.0.0=13_2_0_hd922786_3 - - libgfortran-devel_osx-arm64=12.3.0=hc62be1c_3 - - libgfortran5=13.2.0=hf226fd6_3 - - libglib=2.80.2=h59d46d9_1 - - libhomfly=1.02r6=h93a5062_1 - - libhwloc=2.10.0=default_h7685b71_1001 - - libiconv=1.17=h0d3ecfb_2 - - libintl=0.22.5=h8fbad5d_2 - - libintl-devel=0.22.5=h8fbad5d_2 - - libjpeg-turbo=3.0.0=hb547adb_1 - - liblapack=3.9.0=20_osxarm64_openblas - - liblapacke=3.9.0=20_osxarm64_openblas - - libllvm16=16.0.6=haab561b_3 - - libnghttp2=1.58.0=ha4dd798_1 - - libopenblas=0.3.25=openmp_h6c19121_0 - - libpng=1.6.43=h091b4b1_0 - - libsodium=1.0.18=h27ca646_1 - - libsqlite=3.46.0=hfb93653_0 - - libssh2=1.11.0=h7a5bd25_0 - - libtiff=4.6.0=h07db509_3 - - libtool=2.4.7=hb7217d7_0 - - libuv=1.48.0=h93a5062_0 - - libwebp=1.4.0=h54798ee_0 - - libwebp-base=1.4.0=h93a5062_0 - - libxcb=1.16=hf2054a2_0 - - libxml2=2.12.7=ha661575_1 - - libzlib=1.3.1=hfb2fe0b_1 - - linbox=1.7.0=h3afee3a_0 - - llvm-openmp=18.1.8=hde57baf_0 - - llvm-tools=16.0.6=haab561b_3 - - lrcalc=2.1=hebf3989_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - m4=1.4.18=h642e427_1001 - - m4ri=20140914=hc97c1ff_1006 - - m4rie=20150908=h22b9e9d_1002 - - make=4.3=he57ea6c_1 - - markupsafe=2.1.5=py310hd125d64_0 - - mathjax=3.2.2=hce30654_0 - - matplotlib=3.8.4=py310hb6292c7_2 - - matplotlib-base=3.8.4=py310hedb7998_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2bbcd85_2 - - memory-allocator=0.1.3=py310h2aa6e3c_0 - - meson=1.5.2=pyhd8ed1ab_0 - - meson-python=0.15.0=pyh0c530f3_0 - - metis=5.1.0=h13dd4ca_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=h91ba8db_0 - - mpfi=1.5.4=hbde5f5b_1001 - - mpfr=4.2.1=h41d338b_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py310he1a186f_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h93a5062_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=hb89a1cb_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h420ef59_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=hbb3f309_1 - - numpy=1.26.4=py310hd45542a_0 - - openblas=0.3.25=openmp_h55c453e_0 - - openjdk=22.0.1=hbeb2e11_0 - - openjpeg=2.5.2=h9f1df11_0 - - openssh=9.6p1=hd435d45_0 - - openssl=3.3.1=hfb2fe0b_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=h27ca646_0 - - pandoc=3.2.1=hce30654_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h5cb9fbc_0 - - pari=2.15.5=h4f2304c_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=h27ca646_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h297a79d_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h4614cfb_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py310h01af8b1_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=hebf3989_0 - - pkg-config=0.29.2=hab62308_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h93a5062_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h8b147cf_1006 - - pplpy=0.8.9=py310hc3af9bb_1 - - primecount=7.6=hb6e4faa_0 - - primecountpy=0.1.0=py310h38f39d4_4 - - primesieve=11.0=hb7217d7_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py310ha6dd24b_0 - - pthread-stubs=0.4=h27ca646_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py310h21239e6_0 - - pybind11-global=2.12.0=py310h21239e6_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py310h947b723_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py310h4b7648a_0 - - pyobjc-framework-cocoa=10.3.1=py310h4b7648a_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py310hd125d64_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.10.14=h2469fbe_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py310h692a8b6_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.10=4_cp310 - - pythran=0.15.0=py310h1359cc7_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py310hbe9552e_4 - - pyyaml=6.0.1=py310h2aa6e3c_1 - - pyzmq=26.0.3=py310h16e08c9_0 - - qd=2.3.22=hbec66e7_1004 - - qhull=2020.2=hc021e02_2 - - r-base=4.3.3=h8112bfe_3 - - r-lattice=0.22_6=r43hd2d937b_0 - - readline=8.2=h92ec313_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hb547adb_0 - - rpds-py=0.18.1=py310h947b723_0 - - rpy2=3.5.11=py310r43h280b8fa_3 - - ruamel.yaml=0.18.6=py310hd125d64_0 - - ruamel.yaml.clib=0.2.8=py310hd125d64_0 - - rw=0.9=h93a5062_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py310h2b794db_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - sigtool=0.1.3=h44b9a77_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hb460b52_1 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h5838104_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf6fcff2_1 - - symmetrica=3.0.1=hb7217d7_0 - - sympow=2.023.6=hb0babe8_3 - - sympy=1.12.1=pypyh2585a3b_103 - - tachyon=0.99b6=hb8a568e_1002 - - tapi=1100.0.11=he4954df_0 - - tar=1.34=h7cb298e_1 - - tbb=2021.12.0=h420ef59_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321h9ea1dce_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h5083fa2_1 - - tktable=2.10=h1e387b8_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py310ha6dd24b_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py310hbe9552e_0 - - unicodedata2=15.1.0=py310h2aa6e3c_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=hb547adb_0 - - xorg-libxdmcp=1.1.3=h27ca646_0 - - xz=5.2.6=h57fd34a_0 - - yaml=0.2.5=h3422bc3_2 - - zeromq=4.3.5=hcc0f68c_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=hfb2fe0b_1 - - zstd=1.5.6=hb46c0d2_0 diff --git a/environment-dev-3.11-linux-aarch64.yml b/environment-dev-3.11-linux-aarch64.yml deleted file mode 100644 index d02836fc39b..00000000000 --- a/environment-dev-3.11-linux-aarch64.yml +++ /dev/null @@ -1,488 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: linux-aarch64 -# input_hash: 66aaaed1c1f4084624510fb4e264813007a23f0c2a3526f277199a0ebc059af4 - -channels: - - conda-forge -dependencies: - - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - _sysroot_linux-aarch64_curr_repodata_hack=4=h57d6b7b_14 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.11=h31becfc_1 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py311hcd402e7_4 - - arpack=3.9.1=nompi_hd363cd0_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attr=2.5.1=h4e544f5_1 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321h2148fe1_1 - - automake=1.16.5=pl5321h8af1aa0_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=hf897c2e_0 - - bdw-gc=8.0.6=hd62202e_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=hf1166c9_7 - - binutils_impl_linux-aarch64=2.40=hf54a868_7 - - binutils_linux-aarch64=2.40=h1f91aba_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linuxaarch64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=ha990451_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h31becfc_1 - - brotli-bin=1.1.0=h31becfc_1 - - brotli-python=1.1.0=py311h8715677_1 - - bwidget=1.9.14=h8af1aa0_1 - - bzip2=1.0.8=h31becfc_5 - - c-ares=1.28.1=h31becfc_0 - - c-compiler=1.7.0=h31becfc_1 - - ca-certificates=2024.6.2=hcefe29a_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=h5c54ea9_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cddlib=1!0.94m=h719063d_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py311h7963103_0 - - chardet=5.2.0=py311hfecb2dc_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=h31becfc_1 - - cmake=3.29.6=h7042e5d_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py311hec3470c_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=h8af1aa0_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py311h098ece5_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - cryptography=42.0.8=py311h0290c5f_0 - - curl=8.8.0=h7daf2e0_0 - - cvxopt=1.3.2=py311ha095bbf_2 - - cxx-compiler=1.7.0=h2a328a1_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py311h5ab95f0_0 - - cysignals=1.11.2=py311h644d908_3 - - cython=3.0.10=py311h8715677_0 - - dbus=1.13.6=h12b9eeb_3 - - debugpy=1.8.1=py311h8715677_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hb12102e_1203 - - ecl=23.9.9=h6475f26_0 - - eclib=20231212=he26bab5_0 - - ecm=7.0.5=ha2d0fc4_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h2f0025b_0 - - fflas-ffpack=2.5.0=h503e619_0 - - fftw=3.3.10=nompi_h020dacd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=ha9a116f_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py311hf4892ed_0 - - fortran-compiler=1.7.0=h7048d53_1 - - fplll=5.4.5=hb3a790e_0 - - fpylll=0.6.1=py311h5d3d69a_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=hf0a5ef3_2 - - fribidi=1.0.10=hb9de7d4_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=h597289e_3 - - gap-defaults=4.12.2=h8af1aa0_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=hdb0cc85_13 - - gcc_impl_linux-aarch64=12.3.0=h3d98823_13 - - gcc_linux-aarch64=12.3.0=ha52a6ea_9 - - gengetopt=2.23=h01db608_0 - - gf2x=1.3.0=h1b3b3a3_2 - - gfan=0.6.2=h5f589ec_1003 - - gfortran=12.3.0=hdb0cc85_13 - - gfortran_impl_linux-aarch64=12.3.0=h97ebfd2_13 - - gfortran_linux-aarch64=12.3.0=ha7b8e4b_9 - - gh=2.46.0=h652cbe9_0 - - giac=1.9.0.21=h04922a4_1 - - giflib=5.2.2=h31becfc_0 - - git=2.45.2=pl5321h011b5c6_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=h364d21b_0 - - glpk=5.0=h66325d0_0 - - gmp=6.3.0=h0a1ffab_2 - - gmpy2=2.1.5=py311h3c136a7_1 - - graphite2=1.3.13=h2f0025b_1003 - - gsl=2.7=h294027d_0 - - gxx=12.3.0=hdb0cc85_13 - - gxx_impl_linux-aarch64=12.3.0=hba91e99_13 - - gxx_linux-aarch64=12.3.0=h9d1f256_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h9812418_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h787c7f5_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h197073e_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h15043fe_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jeepney=0.8.0=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=h8af1aa0_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py311hec3470c_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py311hec3470c_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-aarch64=4.18.0=h5b4a56d_14 - - keyring=25.2.1=pyha804496_0 - - keyutils=1.6.1=h4e544f5_0 - - kiwisolver=1.4.5=py311h0d5d7b0_1 - - krb5=1.21.2=hc419048_0 - - lcalc=2.0.5=he588f68_2 - - lcms2=2.16=h922389a_0 - - ld_impl_linux-aarch64=2.40=h9fc2d93_7 - - lerc=4.0.0=h4de3ea5_0 - - libatomic_ops=7.6.14=h4e544f5_0 - - libblas=3.9.0=20_linuxaarch64_openblas - - libboost=1.85.0=hb41fec8_2 - - libboost-devel=1.85.0=h37bb5a9_2 - - libboost-headers=1.85.0=h8af1aa0_2 - - libbraiding=1.2=hd600fc2_0 - - libbrial=1.2.12=h9429f74_3 - - libbrotlicommon=1.1.0=h31becfc_1 - - libbrotlidec=1.1.0=h31becfc_1 - - libbrotlienc=1.1.0=h31becfc_1 - - libcap=2.69=h883460d_0 - - libcblas=3.9.0=20_linuxaarch64_openblas - - libcbor=0.9.0=h01db608_0 - - libcups=2.3.3=h405e4a8_4 - - libcurl=8.8.0=h4e8248e_0 - - libdeflate=1.20=h31becfc_0 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=h31becfc_2 - - libexpat=2.6.2=h2f0025b_0 - - libffi=3.4.2=h3557bc0_5 - - libfido2=1.15.0=hab05c5e_0 - - libflint=3.0.1=hc392af7_ntl_100 - - libgcc-devel_linux-aarch64=12.3.0=h6144e03_113 - - libgcc-ng=13.2.0=he277a41_13 - - libgd=2.3.3=hcd22fd5_9 - - libgfortran-ng=13.2.0=he9431aa_13 - - libgfortran5=13.2.0=h2af0866_13 - - libglib=2.80.2=haee52c6_1 - - libgomp=13.2.0=he277a41_13 - - libhomfly=1.02r6=h31becfc_1 - - libhwloc=2.10.0=default_h3030c0e_1001 - - libiconv=1.17=h31becfc_2 - - libjpeg-turbo=3.0.0=h31becfc_1 - - liblapack=3.9.0=20_linuxaarch64_openblas - - liblapacke=3.9.0=20_linuxaarch64_openblas - - libnghttp2=1.58.0=hb0e430d_1 - - libnsl=2.0.1=h31becfc_0 - - libopenblas=0.3.25=pthreads_h5a5ec62_0 - - libpng=1.6.43=h194ca79_0 - - libsanitizer=12.3.0=h57e2e72_13 - - libsodium=1.0.18=hb9de7d4_1 - - libsqlite=3.46.0=hf51ef55_0 - - libssh2=1.11.0=h492db2e_0 - - libstdcxx-devel_linux-aarch64=12.3.0=h6144e03_113 - - libstdcxx-ng=13.2.0=h3f4de04_13 - - libtiff=4.6.0=hf980d43_3 - - libtool=2.4.7=h4de3ea5_0 - - libudev1=255=h31becfc_1 - - libuuid=2.38.1=hb4cce97_0 - - libuv=1.48.0=h31becfc_0 - - libwebp=1.4.0=h8b4e01b_0 - - libwebp-base=1.4.0=h31becfc_0 - - libxcb=1.16=h7935292_0 - - libxcrypt=4.4.36=h31becfc_1 - - libxml2=2.12.7=h49dc7a2_1 - - libzlib=1.3.1=h68df207_1 - - linbox=1.7.0=h681a5ee_0 - - llvm-openmp=18.1.8=hb063fc5_0 - - lrcalc=2.1=h2f0025b_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - m4=1.4.18=h516909a_1001 - - m4ri=20140914=hedfd65a_1006 - - m4rie=20150908=hf0a5ef3_1002 - - make=4.3=h309ac5b_1 - - markupsafe=2.1.5=py311hc8f2f60_0 - - mathjax=3.2.2=h8af1aa0_0 - - matplotlib=3.8.4=py311hfecb2dc_2 - - matplotlib-base=3.8.4=py311h55059f0_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h6475f26_2 - - memory-allocator=0.1.3=py311hcd402e7_0 - - metis=5.1.0=h2f0025b_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=hf4c8f4c_0 - - mpfi=1.5.4=h846f343_1001 - - mpfr=4.2.1=ha2d0fc4_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py311hdc7ef93_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h31becfc_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h0425590_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h70be974_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=h0d7519b_1 - - numpy=1.26.4=py311h69ead2a_0 - - openblas=0.3.25=pthreads_h339cbfa_0 - - openjdk=22.0.1=h3d4cd67_0 - - openjpeg=2.5.2=h0d9d63b_0 - - openssh=9.6p1=h04b8c23_0 - - openssl=3.3.1=h68df207_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=hb9de7d4_0 - - pandoc=3.2.1=h8af1aa0_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h399c48b_0 - - pari=2.15.5=h169c2a7_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=hf897c2e_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h070dd5b_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h31becfc_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py311h54289d1_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h2f0025b_0 - - pkg-config=0.29.2=hb9de7d4_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h31becfc_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h984aac9_1006 - - pplpy=0.8.9=py311ha3770eb_1 - - primecount=7.9=hd600fc2_0 - - primecountpy=0.1.0=py311h098ece5_4 - - primesieve=11.1=h2f0025b_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py311hf4892ed_0 - - pthread-stubs=0.4=hb9de7d4_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py311h098ece5_0 - - pybind11-global=2.12.0=py311h098ece5_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py311h4713408_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py311hc8f2f60_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.11.9=hddfb980_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py311h8715677_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.11=4_cp311 - - pythran=0.15.0=py311hec5c23b_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py311hec3470c_4 - - pyyaml=6.0.1=py311hcd402e7_1 - - pyzmq=26.0.3=py311hb8d4657_0 - - qd=2.3.22=h05efe27_1004 - - qhull=2020.2=hd62202e_2 - - r-base=4.3.3=h7f20121_3 - - r-lattice=0.22_6=r43h25e906a_0 - - readline=8.2=h8fc344f_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h31becfc_0 - - rpds-py=0.18.1=py311h949f54a_0 - - rpy2=3.5.11=py311r43hf13da56_3 - - ruamel.yaml=0.18.6=py311hcd402e7_0 - - ruamel.yaml.clib=0.2.8=py311hcd402e7_0 - - rw=0.9=h31becfc_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.3=py311h69ead2a_1 - - secretstorage=3.3.3=py311hfecb2dc_2 - - sed=4.8=ha0d5d3d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hbe76a8a_1 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=hdc7ab3c_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=h3944111_1 - - symmetrica=3.0.1=hd600fc2_0 - - sympow=2.023.6=h157afb5_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-aarch64=2.17=h5b4a56d_14 - - tachyon=0.99b6=ha0bfc61_1002 - - tar=1.34=h048efde_0 - - tbb=2021.12.0=h70be974_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h17f021e_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h194ca79_0 - - tktable=2.10=h52f7bd3_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py311h323e239_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py311hec3470c_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-fixesproto=5.0=h3557bc0_1002 - - xorg-inputproto=2.3.2=h3557bc0_1002 - - xorg-kbproto=1.0.7=h3557bc0_1002 - - xorg-libice=1.1.1=h7935292_0 - - xorg-libsm=1.2.4=h5a01bc2_0 - - xorg-libx11=1.8.9=h08be655_1 - - xorg-libxau=1.0.11=h31becfc_0 - - xorg-libxdmcp=1.1.3=h3557bc0_0 - - xorg-libxext=1.3.4=h2a766a3_2 - - xorg-libxfixes=5.0.3=h3557bc0_1004 - - xorg-libxi=1.7.10=h3557bc0_0 - - xorg-libxrender=0.9.11=h7935292_0 - - xorg-libxt=1.3.0=h7935292_1 - - xorg-libxtst=1.2.3=hf897c2e_1002 - - xorg-recordproto=1.14.2=hf897c2e_1002 - - xorg-renderproto=0.11.1=h3557bc0_1002 - - xorg-xextproto=7.3.0=h2a766a3_1003 - - xorg-xproto=7.0.31=h3557bc0_1007 - - xz=5.2.6=h9cdd2b7_0 - - yaml=0.2.5=hf897c2e_2 - - zeromq=4.3.5=h28faeed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h68df207_1 - - zstd=1.5.6=h02f22dd_0 diff --git a/environment-dev-3.11-linux.yml b/environment-dev-3.11-linux.yml deleted file mode 100644 index 786c2190d71..00000000000 --- a/environment-dev-3.11-linux.yml +++ /dev/null @@ -1,535 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: linux-64 -# input_hash: f63cac647504bbd824a745f50b79ed9af0d2c491bf359361fdaa0624827c7f36 - -channels: - - conda-forge -dependencies: - - _libgcc_mutex=0.1=conda_forge - - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.12=h4ab18f5_0 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py311h459d7ec_4 - - arpack=3.9.1=nompi_h77f6705_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attr=2.5.1=h166bdaf_1 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321h2b4cb7a_1 - - automake=1.16.5=pl5321ha770c72_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=h7f98852_0 - - bdw-gc=8.0.6=h4bd325d_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=h4852527_7 - - binutils_impl_linux-64=2.40=ha1999f0_7 - - binutils_linux-64=2.40=hb3c18ed_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linux64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h44aadfe_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hd590300_1 - - brotli-bin=1.1.0=hd590300_1 - - brotli-python=1.1.0=py311hb755f60_1 - - bwidget=1.9.14=ha770c72_1 - - bzip2=1.0.8=hd590300_5 - - c-ares=1.28.1=hd590300_0 - - c-compiler=1.7.0=hd590300_1 - - ca-certificates=2024.6.2=hbcca054_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=hbb29018_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cddlib=1!0.94m=h9202a9a_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py311hb3a22ac_0 - - chardet=5.2.0=py311h38be061_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=hd590300_1 - - cmake=3.29.6=hcafd917_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py311h38be061_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=ha770c72_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py311h9547e67_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - cryptography=42.0.8=py311h4a61cc7_0 - - curl=8.8.0=he654da7_0 - - cvxopt=1.3.2=py311hec6cc1f_2 - - cxx-compiler=1.7.0=h00ab1b0_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py311hd2352ae_0 - - cysignals=1.11.2=py311h82528dc_3 - - cython=3.0.10=py311hb755f60_0 - - dbus=1.13.6=h5008d03_3 - - debugpy=1.8.1=py311hb755f60_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hd9d9efa_1203 - - ecl=23.9.9=hed6455c_0 - - eclib=20231212=h96f522a_0 - - ecm=7.0.5=h9458935_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h59595ed_0 - - fflas-ffpack=2.5.0=h4f9960b_0 - - fftw=3.3.10=nompi_hf1063bd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h14ed4e7_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py311h331c9d8_0 - - fortran-compiler=1.7.0=heb67821_1 - - fplll=5.4.5=h384768b_0 - - fpylll=0.6.1=py311hcfae7cf_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=h267a509_2 - - fribidi=1.0.10=h36c2ea0_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he9a28a4_3 - - gap-defaults=4.12.2=ha770c72_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=h915e2ae_13 - - gcc_impl_linux-64=12.3.0=h58ffeeb_13 - - gcc_linux-64=12.3.0=h9528a6a_9 - - gengetopt=2.23=h9c3ff4c_0 - - gettext=0.22.5=h59595ed_2 - - gettext-tools=0.22.5=h59595ed_2 - - gf2x=1.3.0=ha476b99_2 - - gfan=0.6.2=hb86e20a_1003 - - gfortran=12.3.0=h915e2ae_13 - - gfortran_impl_linux-64=12.3.0=h8f2110c_13 - - gfortran_linux-64=12.3.0=h5877db1_9 - - gh=2.52.0=he0e2781_0 - - giac=1.9.0.21=h673759e_1 - - giflib=5.2.2=hd590300_0 - - git=2.45.2=pl5321ha099dd3_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=hb789bce_0 - - glib=2.80.2=h8a4344b_1 - - glib-tools=2.80.2=h73ef956_1 - - glpk=5.0=h445213a_0 - - gmp=6.3.0=hac33072_2 - - gmpy2=2.1.5=py311hc4f1f91_1 - - graphite2=1.3.13=h59595ed_1003 - - gsl=2.7=he838d99_0 - - gst-plugins-base=1.24.5=hbaaba92_0 - - gstreamer=1.24.5=haf2f30d_0 - - gxx=12.3.0=h915e2ae_13 - - gxx_impl_linux-64=12.3.0=h2a574ab_13 - - gxx_linux-64=12.3.0=ha28b414_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=hfac3d4d_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h59595ed_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hef0740d_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h623f65a_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jeepney=0.8.0=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=ha770c72_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py311h38be061_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py311h38be061_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-64=2.6.32=he073ed8_17 - - keyring=25.2.1=pyha804496_0 - - keyutils=1.6.1=h166bdaf_0 - - kiwisolver=1.4.5=py311h9547e67_1 - - krb5=1.21.2=h659d440_0 - - lame=3.100=h166bdaf_1003 - - lcalc=2.0.5=h5aac1b6_2 - - lcms2=2.16=hb7c19ff_0 - - ld_impl_linux-64=2.40=hf3520f5_7 - - lerc=4.0.0=h27087fc_0 - - libasprintf=0.22.5=h661eb56_2 - - libasprintf-devel=0.22.5=h661eb56_2 - - libatomic_ops=7.6.14=h166bdaf_0 - - libblas=3.9.0=20_linux64_openblas - - libboost=1.85.0=hba137d9_2 - - libboost-devel=1.85.0=h00ab1b0_2 - - libboost-headers=1.85.0=ha770c72_2 - - libbraiding=1.2=hcb278e6_0 - - libbrial=1.2.12=h76af697_3 - - libbrotlicommon=1.1.0=hd590300_1 - - libbrotlidec=1.1.0=hd590300_1 - - libbrotlienc=1.1.0=hd590300_1 - - libcap=2.69=h0f662aa_0 - - libcblas=3.9.0=20_linux64_openblas - - libcbor=0.10.2=hcb278e6_0 - - libclang-cpp15=15.0.7=default_h127d8a8_5 - - libclang13=18.1.8=default_h6ae225f_0 - - libcups=2.3.3=h4637d8d_4 - - libcurl=8.8.0=hca28451_0 - - libdeflate=1.20=hd590300_0 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=hd590300_2 - - libevent=2.1.12=hf998b51_1 - - libexpat=2.6.2=h59595ed_0 - - libffi=3.4.2=h7f98852_5 - - libfido2=1.15.0=hdd1f21f_0 - - libflac=1.4.3=h59595ed_0 - - libflint=3.0.1=h5f2e117_ntl_100 - - libgcc-devel_linux-64=12.3.0=h6b66f73_113 - - libgcc-ng=13.2.0=h77fa898_13 - - libgcrypt=1.10.3=hd590300_0 - - libgd=2.3.3=h119a65a_9 - - libgettextpo=0.22.5=h59595ed_2 - - libgettextpo-devel=0.22.5=h59595ed_2 - - libgfortran-ng=13.2.0=h69a702a_13 - - libgfortran5=13.2.0=h3d2ce59_13 - - libglib=2.80.2=h8a4344b_1 - - libgomp=13.2.0=h77fa898_13 - - libgpg-error=1.49=h4f305b6_0 - - libhomfly=1.02r6=hd590300_1 - - libhwloc=2.10.0=default_h5622ce7_1001 - - libiconv=1.17=hd590300_2 - - libjpeg-turbo=3.0.0=hd590300_1 - - liblapack=3.9.0=20_linux64_openblas - - liblapacke=3.9.0=20_linux64_openblas - - libllvm15=15.0.7=hb3ce162_4 - - libllvm18=18.1.8=hc9dba70_0 - - libnghttp2=1.58.0=h47da74e_1 - - libnsl=2.0.1=hd590300_0 - - libogg=1.3.5=h4ab18f5_0 - - libopenblas=0.3.25=pthreads_h413a1c8_0 - - libopus=1.3.1=h7f98852_1 - - libpng=1.6.43=h2797004_0 - - libpq=16.3=ha72fbe1_0 - - libsanitizer=12.3.0=hb8811af_13 - - libsndfile=1.2.2=hc60ed4a_1 - - libsodium=1.0.18=h36c2ea0_1 - - libsqlite=3.46.0=hde9e2c9_0 - - libssh2=1.11.0=h0841786_0 - - libstdcxx-devel_linux-64=12.3.0=h6b66f73_113 - - libstdcxx-ng=13.2.0=hc0a3c3a_13 - - libsystemd0=255=h3516f8a_1 - - libtiff=4.6.0=h1dd3fc0_3 - - libtool=2.4.7=h27087fc_0 - - libudev1=255=h3f72095_1 - - libuuid=2.38.1=h0b41bf4_0 - - libuv=1.48.0=hd590300_0 - - libvorbis=1.3.7=h9c3ff4c_0 - - libwebp=1.4.0=h2c329e2_0 - - libwebp-base=1.4.0=hd590300_0 - - libxcb=1.16=hd590300_0 - - libxcrypt=4.4.36=hd590300_1 - - libxkbcommon=1.7.0=h2c5496b_1 - - libxml2=2.12.7=hc051c1a_1 - - libzlib=1.3.1=h4ab18f5_1 - - linbox=1.7.0=ha329b40_0 - - llvm-openmp=18.1.8=hf5423f3_0 - - lrcalc=2.1=h59595ed_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - lz4-c=1.9.4=hcb278e6_0 - - m4=1.4.18=h516909a_1001 - - m4ri=20140914=hae5d5c5_1006 - - m4rie=20150908=h267a509_1002 - - make=4.3=hd18ef5c_1 - - markupsafe=2.1.5=py311h459d7ec_0 - - mathjax=3.2.2=ha770c72_0 - - matplotlib=3.8.4=py311h38be061_2 - - matplotlib-base=3.8.4=py311ha4ca890_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=hed6455c_2 - - memory-allocator=0.1.3=py311h459d7ec_0 - - meson=1.5.2=pyhd8ed1ab_0 - - meson-python=0.15.0=pyh0c530f3_0 - - metis=5.1.0=h59595ed_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=hfe3b2da_0 - - mpfi=1.5.4=h9f54685_1001 - - mpfr=4.2.1=h9458935_1 - - mpg123=1.32.6=h59595ed_0 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py311h52f7536_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - mysql-common=8.3.0=hf1915f5_4 - - mysql-libs=8.3.0=hca2cd23_4 - - nauty=2.8.8=hd590300_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h59595ed_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h297d8ca_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - nspr=4.35=h27087fc_0 - - nss=3.101=h593d115_0 - - ntl=11.4.3=hef3c4d3_1 - - numpy=1.26.4=py311h64a7726_0 - - openblas=0.3.25=pthreads_h7a3da1a_0 - - openjdk=21.0.2=haa376d0_0 - - openjpeg=2.5.2=h488ebb8_0 - - openssh=9.6p1=h2d3b35a_0 - - openssl=3.3.1=h4ab18f5_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=h36c2ea0_0 - - pandoc=3.2.1=ha770c72_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h84a9a3c_0 - - pari=2.15.5=h4d4ae9b_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=h7f98852_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h0f59acf_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_hd590300_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py311h82a398c_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.2=h59595ed_0 - - pkg-config=0.29.2=h36c2ea0_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=hd590300_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h6ec01c2_1006 - - pplpy=0.8.9=py311ha9f9f00_1 - - primecount=7.9=hcb278e6_0 - - primecountpy=0.1.0=py311h9547e67_4 - - primesieve=11.1=h59595ed_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py311h331c9d8_0 - - pthread-stubs=0.4=h36c2ea0_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pulseaudio-client=17.0=hb77b528_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py311h9547e67_0 - - pybind11-global=2.12.0=py311h9547e67_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py311h5ecf98a_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyqt=5.15.9=py311hf0fb5b6_5 - - pyqt5-sip=12.12.2=py311hb755f60_5 - - pyrsistent=0.20.0=py311h459d7ec_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.11.9=hb806964_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py311hb755f60_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.11=4_cp311 - - pythran=0.15.0=py311h92ebd52_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py311h38be061_4 - - pyyaml=6.0.1=py311h459d7ec_1 - - pyzmq=26.0.3=py311h08a0b41_0 - - qd=2.3.22=h2cc385e_1004 - - qhull=2020.2=h4bd325d_2 - - qt-main=5.15.8=ha2b5568_22 - - r-base=4.3.3=he2d9a6e_3 - - r-lattice=0.22_6=r43h57805ef_0 - - readline=8.2=h8228510_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hd590300_0 - - rpds-py=0.18.1=py311h5ecf98a_0 - - rpy2=3.5.11=py311r43h1f0f07a_3 - - ruamel.yaml=0.18.6=py311h459d7ec_0 - - ruamel.yaml.clib=0.2.8=py311h459d7ec_0 - - rw=0.9=hd590300_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py311h64a7726_0 - - secretstorage=3.3.3=py311h38be061_2 - - sed=4.8=he412f7d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h33f5c3f_1 - - sip=6.7.12=py311hb755f60_0 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h6d4b2fc_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf4753ba_1 - - symmetrica=3.0.1=hcb278e6_0 - - sympow=2.023.6=hc6ab17c_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-64=2.12=he073ed8_17 - - tachyon=0.99b6=hba7d16a_1002 - - tar=1.34=hb2e2bae_1 - - tbb=2021.12.0=h297d8ca_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h0f457ee_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=noxft_h4845f30_101 - - tktable=2.10=h8bc8fbc_6 - - toml=0.10.2=pyhd8ed1ab_0 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py311h331c9d8_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py311h38be061_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xcb-util=0.4.1=hb711507_2 - - xcb-util-image=0.4.0=hb711507_2 - - xcb-util-keysyms=0.4.1=hb711507_0 - - xcb-util-renderutil=0.3.10=hb711507_0 - - xcb-util-wm=0.4.2=hb711507_0 - - xkeyboard-config=2.42=h4ab18f5_0 - - xorg-fixesproto=5.0=h7f98852_1002 - - xorg-inputproto=2.3.2=h7f98852_1002 - - xorg-kbproto=1.0.7=h7f98852_1002 - - xorg-libice=1.1.1=hd590300_0 - - xorg-libsm=1.2.4=h7391055_0 - - xorg-libx11=1.8.9=hb711507_1 - - xorg-libxau=1.0.11=hd590300_0 - - xorg-libxdmcp=1.1.3=h7f98852_0 - - xorg-libxext=1.3.4=h0b41bf4_2 - - xorg-libxfixes=5.0.3=h7f98852_1004 - - xorg-libxi=1.7.10=h7f98852_0 - - xorg-libxrender=0.9.11=hd590300_0 - - xorg-libxt=1.3.0=hd590300_1 - - xorg-libxtst=1.2.3=h7f98852_1002 - - xorg-recordproto=1.14.2=h7f98852_1002 - - xorg-renderproto=0.11.1=h7f98852_1002 - - xorg-xextproto=7.3.0=h0b41bf4_1003 - - xorg-xf86vidmodeproto=2.3.1=h7f98852_1002 - - xorg-xproto=7.0.31=h7f98852_1007 - - xz=5.2.6=h166bdaf_0 - - yaml=0.2.5=h7f98852_2 - - zeromq=4.3.5=h75354e8_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h4ab18f5_1 - - zstd=1.5.6=ha6fb4c9_0 diff --git a/environment-dev-3.11-macos-x86_64.yml b/environment-dev-3.11-macos-x86_64.yml deleted file mode 100644 index d49d10ccdd9..00000000000 --- a/environment-dev-3.11-macos-x86_64.yml +++ /dev/null @@ -1,469 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: osx-64 -# input_hash: 76cbd25511c5f90d515f03ecbad120b0c890d6418428d7ee7d5cc0e82468e02a - -channels: - - conda-forge -dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py311h2725bcf_4 - - arpack=3.9.1=nompi_hf81eadf_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321hed12c24_1 - - automake=1.16.5=pl5321h694c41f_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=h0d85af4_0 - - bdw-gc=8.0.6=h940c156_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osx64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h07eb623_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h0dc2134_1 - - brotli-bin=1.1.0=h0dc2134_1 - - brotli-python=1.1.0=py311hdf8f085_1 - - bwidget=1.9.14=h694c41f_1 - - bzip2=1.0.8=h10d778d_5 - - c-ares=1.28.1=h10d778d_0 - - c-compiler=1.7.0=h282daa2_1 - - ca-certificates=2024.6.2=h8857fd0_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=h9f650ed_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cctools=986=h40f6528_0 - - cctools_osx-64=986=ha1c5b94_0 - - cddlib=1!0.94m=h0f52abe_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py311hc0b63fd_0 - - chardet=5.2.0=py311h6eed73b_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_ha3b9224_8 - - clang-16=16.0.6=default_h4c8afb6_8 - - clang_impl_osx-64=16.0.6=h8787910_16 - - clang_osx-64=16.0.6=hb91bd55_16 - - clangxx=16.0.6=default_ha3b9224_8 - - clangxx_impl_osx-64=16.0.6=h6d92fbe_16 - - clangxx_osx-64=16.0.6=hb91bd55_16 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=h10d778d_1 - - cmake=3.29.6=h749d262_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py311h6eed73b_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=ha38d28d_2 - - compiler-rt_osx-64=16.0.6=ha38d28d_2 - - compilers=1.7.0=h694c41f_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py311h1d816ee_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - curl=8.8.0=hea67d85_0 - - cvxopt=1.3.2=py311he94735a_2 - - cxx-compiler=1.7.0=h7728843_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py311h4fde0ae_0 - - cysignals=1.11.2=py311h8a58447_3 - - cython=3.0.10=py311hdd0406b_0 - - debugpy=1.8.1=py311hdd0406b_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h6e329d1_1203 - - ecl=23.9.9=h2b27fa8_0 - - eclib=20231212=h02435c3_0 - - ecm=7.0.5=h4f6b447_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h73e2aa4_0 - - fflas-ffpack=2.5.0=h5898d61_0 - - fftw=3.3.10=nompi_h292e606_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h5bb23bf_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py311h72ae277_0 - - fortran-compiler=1.7.0=h6c2ab21_1 - - fplll=5.4.5=hb7981ad_0 - - fpylll=0.6.1=py311h85fbf69_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=h60636b9_2 - - fribidi=1.0.10=hbcb3906_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=hc16eb5f_3 - - gap-defaults=4.12.2=h694c41f_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=he49afe7_0 - - gettext=0.22.5=h5ff76d1_2 - - gettext-tools=0.22.5=h5ff76d1_2 - - gf2x=1.3.0=hb2a7efb_2 - - gfan=0.6.2=hd793b56_1003 - - gfortran=12.3.0=h2c809b3_1 - - gfortran_impl_osx-64=12.3.0=hc328e78_3 - - gfortran_osx-64=12.3.0=h18f7dce_1 - - gh=2.52.0=he13f2d6_0 - - giac=1.9.0.21=h92f3f65_1 - - giflib=5.2.2=h10d778d_0 - - git=2.45.2=pl5321hb0c6a96_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=h1b3d6f7_0 - - glpk=5.0=h3cb5acd_0 - - gmp=6.3.0=hf036a51_2 - - gmpy2=2.1.5=py311hab17429_1 - - graphite2=1.3.13=h73e2aa4_1003 - - gsl=2.7=h93259b0_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h053f038_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hf5e326d_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hde4452d_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h61918c1_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isl=0.26=imath32_h2e86a7b_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.9=h694c41f_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py311h6eed73b_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py311h6eed73b_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - keyring=25.2.1=pyh534df25_0 - - kiwisolver=1.4.5=py311h5fe6e05_1 - - krb5=1.21.2=hb884880_0 - - lcalc=2.0.5=h547a6ed_2 - - lcms2=2.16=ha2f27b4_0 - - ld64=711=ha02d983_0 - - ld64_osx-64=711=ha20a434_0 - - lerc=4.0.0=hb486fe8_0 - - libasprintf=0.22.5=h5ff76d1_2 - - libasprintf-devel=0.22.5=h5ff76d1_2 - - libatomic_ops=7.6.14=hb7f2c08_0 - - libblas=3.9.0=20_osx64_openblas - - libboost=1.85.0=h739af76_2 - - libboost-devel=1.85.0=h2b186f8_2 - - libboost-headers=1.85.0=h694c41f_2 - - libbraiding=1.2=hf0c8a7f_0 - - libbrial=1.2.12=h81e9653_3 - - libbrotlicommon=1.1.0=h0dc2134_1 - - libbrotlidec=1.1.0=h0dc2134_1 - - libbrotlienc=1.1.0=h0dc2134_1 - - libcblas=3.9.0=20_osx64_openblas - - libcbor=0.10.2=hf0c8a7f_0 - - libclang-cpp16=16.0.6=default_h4c8afb6_8 - - libcurl=8.8.0=hf9fcc65_0 - - libcxx=17.0.6=h88467a6_0 - - libdeflate=1.20=h49d49c5_0 - - libedit=3.1.20191231=h0678c8f_2 - - libev=4.33=h10d778d_2 - - libexpat=2.6.2=h73e2aa4_0 - - libffi=3.4.2=h0d85af4_5 - - libfido2=1.15.0=h41b28d8_0 - - libflint=3.0.1=h5d15de0_ntl_100 - - libgd=2.3.3=h0dceb68_9 - - libgettextpo=0.22.5=h5ff76d1_2 - - libgettextpo-devel=0.22.5=h5ff76d1_2 - - libgfortran=5.0.0=13_2_0_h97931a8_3 - - libgfortran-devel_osx-64=12.3.0=h0b6f5ec_3 - - libgfortran5=13.2.0=h2873a65_3 - - libglib=2.80.2=h736d271_1 - - libhomfly=1.02r6=h10d778d_1 - - libhwloc=2.10.0=default_h456cccd_1001 - - libiconv=1.17=hd75f5a5_2 - - libintl=0.22.5=h5ff76d1_2 - - libintl-devel=0.22.5=h5ff76d1_2 - - libjpeg-turbo=3.0.0=h0dc2134_1 - - liblapack=3.9.0=20_osx64_openblas - - liblapacke=3.9.0=20_osx64_openblas - - libllvm16=16.0.6=hbedff68_3 - - libnghttp2=1.58.0=h64cf6d3_1 - - libopenblas=0.3.25=openmp_hfef2a42_0 - - libpng=1.6.43=h92b6c6a_0 - - libsodium=1.0.18=hbcb3906_1 - - libsqlite=3.46.0=h1b8f9f3_0 - - libssh2=1.11.0=hd019ec5_0 - - libtiff=4.6.0=h129831d_3 - - libtool=2.4.7=hf0c8a7f_0 - - libuv=1.48.0=h67532ce_0 - - libwebp=1.4.0=hc207709_0 - - libwebp-base=1.4.0=h10d778d_0 - - libxcb=1.16=h0dc2134_0 - - libxml2=2.12.7=h3e169fe_1 - - libzlib=1.3.1=h87427d6_1 - - linbox=1.7.0=h7061c92_0 - - llvm-openmp=18.1.8=h15ab845_0 - - llvm-tools=16.0.6=hbedff68_3 - - lrcalc=2.1=h73e2aa4_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - m4=1.4.18=haf1e3a3_1001 - - m4ri=20140914=hd82a5f3_1006 - - m4rie=20150908=hc616cfc_1002 - - make=4.3=h22f3db7_1 - - markupsafe=2.1.5=py311he705e18_0 - - mathjax=3.2.2=h694c41f_0 - - matplotlib=3.8.4=py311h6eed73b_2 - - matplotlib-base=3.8.4=py311hff79762_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2b27fa8_2 - - memory-allocator=0.1.3=py311h2725bcf_0 - - metis=5.1.0=he965462_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=h81bd1dd_0 - - mpfi=1.5.4=h52b28e3_1001 - - mpfr=4.2.1=h4f6b447_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py311h46c8309_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h10d778d_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h5846eda_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h3c5361c_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=h0ab3c2f_1 - - numpy=1.26.4=py311hc43a94b_0 - - openblas=0.3.25=openmp_h6794695_0 - - openjdk=22.0.1=h2d185b6_0 - - openjpeg=2.5.2=h7310d3a_0 - - openssh=9.6p1=h6dd4ff7_0 - - openssl=3.3.1=h87427d6_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=hbcb3906_0 - - pandoc=3.2.1=h694c41f_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h880b76c_0 - - pari=2.15.5=h7ba67ff_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=hbcf498f_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h7634a1b_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h10d778d_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py311h2755ac0_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h73e2aa4_0 - - pkg-config=0.29.2=ha3d46e9_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h10d778d_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=ha60d53e_1006 - - pplpy=0.8.9=py311h922ec50_1 - - primecount=7.6=ha894c9a_0 - - primecountpy=0.1.0=py311h5fe6e05_4 - - primesieve=11.0=hf0c8a7f_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py311h72ae277_0 - - pthread-stubs=0.4=hc929b4f_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py311h1d816ee_0 - - pybind11-global=2.12.0=py311h1d816ee_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py311h295b1db_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py311h9d23797_0 - - pyobjc-framework-cocoa=10.3.1=py311h9d23797_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py311he705e18_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.11.9=h657bba9_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py311hdd0406b_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.11=4_cp311 - - pythran=0.15.0=py311ha853786_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py311h6eed73b_4 - - pyyaml=6.0.1=py311h2725bcf_1 - - pyzmq=26.0.3=py311h89e2aaa_0 - - qd=2.3.22=h2beb688_1004 - - qhull=2020.2=h940c156_2 - - r-base=4.3.3=h4648a1f_3 - - r-lattice=0.22_6=r43hb2c329c_0 - - readline=8.2=h9e318b2_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h0dc2134_0 - - rpds-py=0.18.1=py311h295b1db_0 - - rpy2=3.5.11=py311r43h4a70a88_3 - - ruamel.yaml=0.18.6=py311he705e18_0 - - ruamel.yaml.clib=0.2.8=py311he705e18_0 - - rw=0.9=h10d778d_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py311he0bea55_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - sigtool=0.1.3=h88f4db0_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h0d51a9f_1 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h28673e1_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hd2b2131_1 - - symmetrica=3.0.1=hf0c8a7f_0 - - sympow=2.023.6=h115ba6a_3 - - sympy=1.12.1=pypyh2585a3b_103 - - tachyon=0.99b6=h3a1d103_1002 - - tapi=1100.0.11=h9ce4665_0 - - tar=1.34=hcb2f6ea_1 - - tbb=2021.12.0=h3c5361c_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321hc47821c_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h1abcd95_1 - - tktable=2.10=hba9d6f1_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py311h72ae277_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py311h6eed73b_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=h0dc2134_0 - - xorg-libxdmcp=1.1.3=h35c211d_0 - - xz=5.2.6=h775f41a_0 - - yaml=0.2.5=h0d85af4_2 - - zeromq=4.3.5=hde137ed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h87427d6_1 - - zstd=1.5.6=h915ae27_0 diff --git a/environment-dev-3.11-macos.yml b/environment-dev-3.11-macos.yml deleted file mode 100644 index 497abbec59f..00000000000 --- a/environment-dev-3.11-macos.yml +++ /dev/null @@ -1,471 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: osx-arm64 -# input_hash: 2a680a2d8d0e54717c485a773c614ef8a6102b81d2c396cd75bfe731f43e3b5f - -channels: - - conda-forge -dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py311heffc1b2_4 - - arpack=3.9.1=nompi_h593882a_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321hcd07c0c_1 - - automake=1.16.5=pl5321hce30654_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=h3422bc3_0 - - bdw-gc=8.0.6=hc021e02_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osxarm64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=hca5e981_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hb547adb_1 - - brotli-bin=1.1.0=hb547adb_1 - - brotli-python=1.1.0=py311ha891d26_1 - - bwidget=1.9.14=hce30654_1 - - bzip2=1.0.8=h93a5062_5 - - c-ares=1.28.1=h93a5062_0 - - c-compiler=1.7.0=h6aa9301_1 - - ca-certificates=2024.6.2=hf0a4a13_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=hc6c324b_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cctools=986=h4faf515_0 - - cctools_osx-arm64=986=h62378fb_0 - - cddlib=1!0.94m=h6d7a090_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py311h4a08483_0 - - chardet=5.2.0=py311h267d04e_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_h095aff0_8 - - clang-16=16.0.6=default_hb63da90_8 - - clang_impl_osx-arm64=16.0.6=hc421ffc_16 - - clang_osx-arm64=16.0.6=h54d7cd3_16 - - clangxx=16.0.6=default_h095aff0_8 - - clangxx_impl_osx-arm64=16.0.6=hcd7bac0_16 - - clangxx_osx-arm64=16.0.6=h54d7cd3_16 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=h93a5062_1 - - cmake=3.29.6=had79d8f_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py311h267d04e_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=h3808999_2 - - compiler-rt_osx-arm64=16.0.6=h3808999_2 - - compilers=1.7.0=hce30654_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py311hcc98501_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - curl=8.8.0=h653d890_0 - - cvxopt=1.3.2=py311h77cf4c7_2 - - cxx-compiler=1.7.0=h2ffa867_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py311h2c49a9d_0 - - cysignals=1.11.2=py311he42fc87_3 - - cython=3.0.10=py311h92babd0_0 - - debugpy=1.8.1=py311h92babd0_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h9397a75_1203 - - ecl=23.9.9=h1d9728a_0 - - eclib=20231212=h7f07de4_0 - - ecm=7.0.5=h41d338b_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=hebf3989_0 - - fflas-ffpack=2.5.0=h4bc3318_0 - - fftw=3.3.10=nompi_h6637ab6_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h82840c6_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py311hd3f4193_0 - - fortran-compiler=1.7.0=hafb19e3_1 - - fplll=5.4.5=hb7d509d_0 - - fpylll=0.6.1=py311h341b96b_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=hadb7bae_2 - - fribidi=1.0.10=h27ca646_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he8f4e70_3 - - gap-defaults=4.12.2=hce30654_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=hbdafb3b_0 - - gettext=0.22.5=h8fbad5d_2 - - gettext-tools=0.22.5=h8fbad5d_2 - - gf2x=1.3.0=hdaa854c_2 - - gfan=0.6.2=hec08f5c_1003 - - gfortran=12.3.0=h1ca8e4b_1 - - gfortran_impl_osx-arm64=12.3.0=h53ed385_3 - - gfortran_osx-arm64=12.3.0=h57527a5_1 - - gh=2.52.0=h163aea0_0 - - giac=1.9.0.21=h1c96721_1 - - giflib=5.2.2=h93a5062_0 - - git=2.45.2=pl5321h41514c7_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=h018886a_0 - - glpk=5.0=h6d7a090_0 - - gmp=6.3.0=h7bae524_2 - - gmpy2=2.1.5=py311h1e33d93_1 - - graphite2=1.3.13=hebf3989_1003 - - gsl=2.7=h6e638da_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h1836168_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hc8870d7_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h762ac30_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=hd73f12c_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.25.0=pyh707e725_0 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isl=0.26=imath32_h347afa1_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=hce30654_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py311h267d04e_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py311h267d04e_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - keyring=25.2.1=pyh534df25_0 - - kiwisolver=1.4.5=py311he4fd1f5_1 - - krb5=1.21.2=h92f50d5_0 - - lcalc=2.0.5=h4a402bc_2 - - lcms2=2.16=ha0e7c42_0 - - ld64=711=h634c8be_0 - - ld64_osx-arm64=711=ha4bd21c_0 - - lerc=4.0.0=h9a09cb3_0 - - libasprintf=0.22.5=h8fbad5d_2 - - libasprintf-devel=0.22.5=h8fbad5d_2 - - libatomic_ops=7.6.14=h1a8c8d9_0 - - libblas=3.9.0=20_osxarm64_openblas - - libboost=1.85.0=h17eb2be_2 - - libboost-devel=1.85.0=hf450f58_2 - - libboost-headers=1.85.0=hce30654_2 - - libbraiding=1.2=hb7217d7_0 - - libbrial=1.2.12=h56a29cd_3 - - libbrotlicommon=1.1.0=hb547adb_1 - - libbrotlidec=1.1.0=hb547adb_1 - - libbrotlienc=1.1.0=hb547adb_1 - - libcblas=3.9.0=20_osxarm64_openblas - - libcbor=0.10.2=hb7217d7_0 - - libclang-cpp16=16.0.6=default_hb63da90_8 - - libcurl=8.8.0=h7b6f9a7_0 - - libcxx=17.0.6=h5f092b4_0 - - libdeflate=1.20=h93a5062_0 - - libedit=3.1.20191231=hc8eb9b7_2 - - libev=4.33=h93a5062_2 - - libexpat=2.6.2=hebf3989_0 - - libffi=3.4.2=h3422bc3_5 - - libfido2=1.15.0=h9d74d49_0 - - libflint=3.0.1=h28749a5_ntl_100 - - libgd=2.3.3=hfdf3952_9 - - libgettextpo=0.22.5=h8fbad5d_2 - - libgettextpo-devel=0.22.5=h8fbad5d_2 - - libgfortran=5.0.0=13_2_0_hd922786_3 - - libgfortran-devel_osx-arm64=12.3.0=hc62be1c_3 - - libgfortran5=13.2.0=hf226fd6_3 - - libglib=2.80.2=h59d46d9_1 - - libhomfly=1.02r6=h93a5062_1 - - libhwloc=2.10.0=default_h7685b71_1001 - - libiconv=1.17=h0d3ecfb_2 - - libintl=0.22.5=h8fbad5d_2 - - libintl-devel=0.22.5=h8fbad5d_2 - - libjpeg-turbo=3.0.0=hb547adb_1 - - liblapack=3.9.0=20_osxarm64_openblas - - liblapacke=3.9.0=20_osxarm64_openblas - - libllvm16=16.0.6=haab561b_3 - - libnghttp2=1.58.0=ha4dd798_1 - - libopenblas=0.3.25=openmp_h6c19121_0 - - libpng=1.6.43=h091b4b1_0 - - libsodium=1.0.18=h27ca646_1 - - libsqlite=3.46.0=hfb93653_0 - - libssh2=1.11.0=h7a5bd25_0 - - libtiff=4.6.0=h07db509_3 - - libtool=2.4.7=hb7217d7_0 - - libuv=1.48.0=h93a5062_0 - - libwebp=1.4.0=h54798ee_0 - - libwebp-base=1.4.0=h93a5062_0 - - libxcb=1.16=hf2054a2_0 - - libxml2=2.12.7=ha661575_1 - - libzlib=1.3.1=hfb2fe0b_1 - - linbox=1.7.0=h3afee3a_0 - - llvm-openmp=18.1.8=hde57baf_0 - - llvm-tools=16.0.6=haab561b_3 - - lrcalc=2.1=hebf3989_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - m4=1.4.18=h642e427_1001 - - m4ri=20140914=hc97c1ff_1006 - - m4rie=20150908=h22b9e9d_1002 - - make=4.3=he57ea6c_1 - - markupsafe=2.1.5=py311h05b510d_0 - - mathjax=3.2.2=hce30654_0 - - matplotlib=3.8.4=py311ha1ab1f8_2 - - matplotlib-base=3.8.4=py311h000fb6e_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2bbcd85_2 - - memory-allocator=0.1.3=py311heffc1b2_0 - - meson=1.5.2=pyhd8ed1ab_0 - - meson-python=0.15.0=pyh0c530f3_0 - - metis=5.1.0=h13dd4ca_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=h91ba8db_0 - - mpfi=1.5.4=hbde5f5b_1001 - - mpfr=4.2.1=h41d338b_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py311h6bde47b_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h93a5062_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=hb89a1cb_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h420ef59_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=hbb3f309_1 - - numpy=1.26.4=py311h7125741_0 - - openblas=0.3.25=openmp_h55c453e_0 - - openjdk=22.0.1=hbeb2e11_0 - - openjpeg=2.5.2=h9f1df11_0 - - openssh=9.6p1=hd435d45_0 - - openssl=3.3.1=hfb2fe0b_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=h27ca646_0 - - pandoc=3.2.1=hce30654_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h5cb9fbc_0 - - pari=2.15.5=h4f2304c_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=h27ca646_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h297a79d_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h4614cfb_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py311hd7951ec_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=hebf3989_0 - - pkg-config=0.29.2=hab62308_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h93a5062_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h8b147cf_1006 - - pplpy=0.8.9=py311h3d77d83_1 - - primecount=7.6=hb6e4faa_0 - - primecountpy=0.1.0=py311he4fd1f5_4 - - primesieve=11.0=hb7217d7_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py311hd3f4193_0 - - pthread-stubs=0.4=h27ca646_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py311hcc98501_0 - - pybind11-global=2.12.0=py311hcc98501_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py311h98c6a39_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py311h5f135c3_0 - - pyobjc-framework-cocoa=10.3.1=py311h5f135c3_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py311h05b510d_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.11.9=h932a869_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py311h92babd0_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.11=4_cp311 - - pythran=0.15.0=py311hceb3b21_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py311h267d04e_4 - - pyyaml=6.0.1=py311heffc1b2_1 - - pyzmq=26.0.3=py311h9bed540_0 - - qd=2.3.22=hbec66e7_1004 - - qhull=2020.2=hc021e02_2 - - r-base=4.3.3=h8112bfe_3 - - r-lattice=0.22_6=r43hd2d937b_0 - - readline=8.2=h92ec313_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hb547adb_0 - - rpds-py=0.18.1=py311h98c6a39_0 - - rpy2=3.5.11=py311r43hb49d859_3 - - ruamel.yaml=0.18.6=py311h05b510d_0 - - ruamel.yaml.clib=0.2.8=py311h05b510d_0 - - rw=0.9=h93a5062_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py311h2b215a9_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - sigtool=0.1.3=h44b9a77_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hb460b52_1 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h5838104_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf6fcff2_1 - - symmetrica=3.0.1=hb7217d7_0 - - sympow=2.023.6=hb0babe8_3 - - sympy=1.12.1=pypyh2585a3b_103 - - tachyon=0.99b6=hb8a568e_1002 - - tapi=1100.0.11=he4954df_0 - - tar=1.34=h7cb298e_1 - - tbb=2021.12.0=h420ef59_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321h9ea1dce_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h5083fa2_1 - - tktable=2.10=h1e387b8_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py311hd3f4193_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py311h267d04e_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=hb547adb_0 - - xorg-libxdmcp=1.1.3=h27ca646_0 - - xz=5.2.6=h57fd34a_0 - - yaml=0.2.5=h3422bc3_2 - - zeromq=4.3.5=hcc0f68c_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=hfb2fe0b_1 - - zstd=1.5.6=hb46c0d2_0 diff --git a/environment-dev-3.9-linux-aarch64.yml b/environment-dev-3.9-linux-aarch64.yml deleted file mode 100644 index eaeb2644dcd..00000000000 --- a/environment-dev-3.9-linux-aarch64.yml +++ /dev/null @@ -1,489 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: linux-aarch64 -# input_hash: ce794cc8451c14571ca9bfc8ecdd74ad09cf8a281a340df449678e0fed967078 - -channels: - - conda-forge -dependencies: - - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - _sysroot_linux-aarch64_curr_repodata_hack=4=h57d6b7b_14 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.11=h31becfc_1 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py39h898b7ef_4 - - arpack=3.9.1=nompi_hd363cd0_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attr=2.5.1=h4e544f5_1 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321h2148fe1_1 - - automake=1.16.5=pl5321h8af1aa0_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=hf897c2e_0 - - bdw-gc=8.0.6=hd62202e_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=hf1166c9_7 - - binutils_impl_linux-aarch64=2.40=hf54a868_7 - - binutils_linux-aarch64=2.40=h1f91aba_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linuxaarch64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=ha990451_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h31becfc_1 - - brotli-bin=1.1.0=h31becfc_1 - - brotli-python=1.1.0=py39h387a81e_1 - - bwidget=1.9.14=h8af1aa0_1 - - bzip2=1.0.8=h31becfc_5 - - c-ares=1.28.1=h31becfc_0 - - c-compiler=1.7.0=h31becfc_1 - - ca-certificates=2024.6.2=hcefe29a_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=h5c54ea9_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cddlib=1!0.94m=h719063d_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py39hdf53b9e_0 - - chardet=5.2.0=py39ha65689a_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=h31becfc_1 - - cmake=3.29.6=h7042e5d_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py39h4420490_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=h8af1aa0_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py39hd16970a_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - cryptography=42.0.8=py39h33ea94c_0 - - curl=8.8.0=h7daf2e0_0 - - cvxopt=1.3.2=py39h093dae0_2 - - cxx-compiler=1.7.0=h2a328a1_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py39h532d932_0 - - cysignals=1.11.2=py39hfa81392_3 - - cython=3.0.10=py39h387a81e_0 - - dbus=1.13.6=h12b9eeb_3 - - debugpy=1.8.1=py39h387a81e_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hb12102e_1203 - - ecl=23.9.9=h6475f26_0 - - eclib=20231212=he26bab5_0 - - ecm=7.0.5=ha2d0fc4_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h2f0025b_0 - - fflas-ffpack=2.5.0=h503e619_0 - - fftw=3.3.10=nompi_h020dacd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=ha9a116f_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py39he257ee7_0 - - fortran-compiler=1.7.0=h7048d53_1 - - fplll=5.4.5=hb3a790e_0 - - fpylll=0.6.1=py39h97065f7_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=hf0a5ef3_2 - - fribidi=1.0.10=hb9de7d4_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=h597289e_3 - - gap-defaults=4.12.2=h8af1aa0_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=hdb0cc85_13 - - gcc_impl_linux-aarch64=12.3.0=h3d98823_13 - - gcc_linux-aarch64=12.3.0=ha52a6ea_9 - - gengetopt=2.23=h01db608_0 - - gf2x=1.3.0=h1b3b3a3_2 - - gfan=0.6.2=h5f589ec_1003 - - gfortran=12.3.0=hdb0cc85_13 - - gfortran_impl_linux-aarch64=12.3.0=h97ebfd2_13 - - gfortran_linux-aarch64=12.3.0=ha7b8e4b_9 - - gh=2.46.0=h652cbe9_0 - - giac=1.9.0.21=h04922a4_1 - - giflib=5.2.2=h31becfc_0 - - git=2.45.2=pl5321h011b5c6_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=h364d21b_0 - - glpk=5.0=h66325d0_0 - - gmp=6.3.0=h0a1ffab_2 - - gmpy2=2.1.5=py39hcc1b389_1 - - graphite2=1.3.13=h2f0025b_1003 - - gsl=2.7=h294027d_0 - - gxx=12.3.0=hdb0cc85_13 - - gxx_impl_linux-aarch64=12.3.0=hba91e99_13 - - gxx_linux-aarch64=12.3.0=h9d1f256_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h9812418_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h787c7f5_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h197073e_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h15043fe_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.18.1=pyh707e725_3 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jeepney=0.8.0=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=h8af1aa0_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py39h4420490_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py39h4420490_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-aarch64=4.18.0=h5b4a56d_14 - - keyring=25.2.1=pyha804496_0 - - keyutils=1.6.1=h4e544f5_0 - - kiwisolver=1.4.5=py39had2cf8c_1 - - krb5=1.21.2=hc419048_0 - - lcalc=2.0.5=he588f68_2 - - lcms2=2.16=h922389a_0 - - ld_impl_linux-aarch64=2.40=h9fc2d93_7 - - lerc=4.0.0=h4de3ea5_0 - - libatomic_ops=7.6.14=h4e544f5_0 - - libblas=3.9.0=20_linuxaarch64_openblas - - libboost=1.85.0=hb41fec8_2 - - libboost-devel=1.85.0=h37bb5a9_2 - - libboost-headers=1.85.0=h8af1aa0_2 - - libbraiding=1.2=hd600fc2_0 - - libbrial=1.2.12=h9429f74_3 - - libbrotlicommon=1.1.0=h31becfc_1 - - libbrotlidec=1.1.0=h31becfc_1 - - libbrotlienc=1.1.0=h31becfc_1 - - libcap=2.69=h883460d_0 - - libcblas=3.9.0=20_linuxaarch64_openblas - - libcbor=0.9.0=h01db608_0 - - libcups=2.3.3=h405e4a8_4 - - libcurl=8.8.0=h4e8248e_0 - - libdeflate=1.20=h31becfc_0 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=h31becfc_2 - - libexpat=2.6.2=h2f0025b_0 - - libffi=3.4.2=h3557bc0_5 - - libfido2=1.15.0=hab05c5e_0 - - libflint=3.0.1=hc392af7_ntl_100 - - libgcc-devel_linux-aarch64=12.3.0=h6144e03_113 - - libgcc-ng=13.2.0=he277a41_13 - - libgd=2.3.3=hcd22fd5_9 - - libgfortran-ng=13.2.0=he9431aa_13 - - libgfortran5=13.2.0=h2af0866_13 - - libglib=2.80.2=haee52c6_1 - - libgomp=13.2.0=he277a41_13 - - libhomfly=1.02r6=h31becfc_1 - - libhwloc=2.10.0=default_h3030c0e_1001 - - libiconv=1.17=h31becfc_2 - - libjpeg-turbo=3.0.0=h31becfc_1 - - liblapack=3.9.0=20_linuxaarch64_openblas - - liblapacke=3.9.0=20_linuxaarch64_openblas - - libnghttp2=1.58.0=hb0e430d_1 - - libnsl=2.0.1=h31becfc_0 - - libopenblas=0.3.25=pthreads_h5a5ec62_0 - - libpng=1.6.43=h194ca79_0 - - libsanitizer=12.3.0=h57e2e72_13 - - libsodium=1.0.18=hb9de7d4_1 - - libsqlite=3.46.0=hf51ef55_0 - - libssh2=1.11.0=h492db2e_0 - - libstdcxx-devel_linux-aarch64=12.3.0=h6144e03_113 - - libstdcxx-ng=13.2.0=h3f4de04_13 - - libtiff=4.6.0=hf980d43_3 - - libtool=2.4.7=h4de3ea5_0 - - libudev1=255=h31becfc_1 - - libuuid=2.38.1=hb4cce97_0 - - libuv=1.48.0=h31becfc_0 - - libwebp=1.4.0=h8b4e01b_0 - - libwebp-base=1.4.0=h31becfc_0 - - libxcb=1.16=h7935292_0 - - libxcrypt=4.4.36=h31becfc_1 - - libxml2=2.12.7=h49dc7a2_1 - - libzlib=1.3.1=h68df207_1 - - linbox=1.7.0=h681a5ee_0 - - llvm-openmp=18.1.8=hb063fc5_0 - - lrcalc=2.1=h2f0025b_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - m4=1.4.18=h516909a_1001 - - m4ri=20140914=hedfd65a_1006 - - m4rie=20150908=hf0a5ef3_1002 - - make=4.3=h309ac5b_1 - - markupsafe=2.1.5=py39h7cc1d5f_0 - - mathjax=3.2.2=h8af1aa0_0 - - matplotlib=3.8.4=py39ha65689a_2 - - matplotlib-base=3.8.4=py39hf44f4b6_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h6475f26_2 - - memory-allocator=0.1.3=py39h898b7ef_0 - - metis=5.1.0=h2f0025b_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=hf4c8f4c_0 - - mpfi=1.5.4=h846f343_1001 - - mpfr=4.2.1=ha2d0fc4_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py39h7e9cfeb_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h31becfc_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h0425590_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h70be974_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=h0d7519b_1 - - numpy=1.26.4=py39h91c28bb_0 - - openblas=0.3.25=pthreads_h339cbfa_0 - - openjdk=22.0.1=h3d4cd67_0 - - openjpeg=2.5.2=h0d9d63b_0 - - openssh=9.6p1=h04b8c23_0 - - openssl=3.3.1=h68df207_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=hb9de7d4_0 - - pandoc=3.2.1=h8af1aa0_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h399c48b_0 - - pari=2.15.5=h169c2a7_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=hf897c2e_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h070dd5b_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h31becfc_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py39h4a8821f_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h2f0025b_0 - - pkg-config=0.29.2=hb9de7d4_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h31becfc_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h984aac9_1006 - - pplpy=0.8.9=py39hf652505_1 - - primecount=7.6=hd600fc2_0 - - primecountpy=0.1.0=py39hd16970a_3 - - primesieve=11.0=hd600fc2_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py39he257ee7_0 - - pthread-stubs=0.4=hb9de7d4_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py39hd16970a_0 - - pybind11-global=2.12.0=py39hd16970a_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py39hb170bb1_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py39h7cc1d5f_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.9.19=h4ac3b42_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py39h387a81e_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.9=4_cp39 - - pythran=0.15.0=py39hc2250db_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py39h4420490_4 - - pyyaml=6.0.1=py39h898b7ef_1 - - pyzmq=26.0.3=py39h866fef3_0 - - qd=2.3.22=h05efe27_1004 - - qhull=2020.2=hd62202e_2 - - r-base=4.3.3=h7f20121_3 - - r-lattice=0.22_6=r43h25e906a_0 - - readline=8.2=h8fc344f_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h31becfc_0 - - rpds-py=0.18.1=py39hb8f4057_0 - - rpy2=3.5.11=py39r43h1ae4408_3 - - ruamel.yaml=0.18.6=py39h898b7ef_0 - - ruamel.yaml.clib=0.2.8=py39h898b7ef_0 - - rw=0.9=h31becfc_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.3=py39h91c28bb_1 - - secretstorage=3.3.3=py39ha65689a_2 - - sed=4.8=ha0d5d3d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hbe76a8a_1 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=hdc7ab3c_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=h3944111_1 - - symmetrica=3.0.1=hd600fc2_0 - - sympow=2.023.6=h157afb5_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-aarch64=2.17=h5b4a56d_14 - - tachyon=0.99b6=ha0bfc61_1002 - - tar=1.34=h048efde_0 - - tbb=2021.12.0=h70be974_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h17f021e_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h194ca79_0 - - tktable=2.10=h52f7bd3_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py39ha3e8b56_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py39h4420490_0 - - unicodedata2=15.1.0=py39h898b7ef_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-fixesproto=5.0=h3557bc0_1002 - - xorg-inputproto=2.3.2=h3557bc0_1002 - - xorg-kbproto=1.0.7=h3557bc0_1002 - - xorg-libice=1.1.1=h7935292_0 - - xorg-libsm=1.2.4=h5a01bc2_0 - - xorg-libx11=1.8.9=h08be655_1 - - xorg-libxau=1.0.11=h31becfc_0 - - xorg-libxdmcp=1.1.3=h3557bc0_0 - - xorg-libxext=1.3.4=h2a766a3_2 - - xorg-libxfixes=5.0.3=h3557bc0_1004 - - xorg-libxi=1.7.10=h3557bc0_0 - - xorg-libxrender=0.9.11=h7935292_0 - - xorg-libxt=1.3.0=h7935292_1 - - xorg-libxtst=1.2.3=hf897c2e_1002 - - xorg-recordproto=1.14.2=hf897c2e_1002 - - xorg-renderproto=0.11.1=h3557bc0_1002 - - xorg-xextproto=7.3.0=h2a766a3_1003 - - xorg-xproto=7.0.31=h3557bc0_1007 - - xz=5.2.6=h9cdd2b7_0 - - yaml=0.2.5=hf897c2e_2 - - zeromq=4.3.5=h28faeed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h68df207_1 - - zstd=1.5.6=h02f22dd_0 diff --git a/environment-dev-3.9-linux.yml b/environment-dev-3.9-linux.yml deleted file mode 100644 index ab8991dfcd6..00000000000 --- a/environment-dev-3.9-linux.yml +++ /dev/null @@ -1,536 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: linux-64 -# input_hash: 9434f8e084f9cad908d6fa3d6e7b5e95bb0546055588979176fb8fe260ae6d0f - -channels: - - conda-forge -dependencies: - - _libgcc_mutex=0.1=conda_forge - - _openmp_mutex=4.5=2_kmp_llvm - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - alsa-lib=1.2.12=h4ab18f5_0 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py39hd1e30aa_4 - - arpack=3.9.1=nompi_h77f6705_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attr=2.5.1=h166bdaf_1 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321h2b4cb7a_1 - - automake=1.16.5=pl5321ha770c72_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=h7f98852_0 - - bdw-gc=8.0.6=h4bd325d_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - binutils=2.40=h4852527_7 - - binutils_impl_linux-64=2.40=ha1999f0_7 - - binutils_linux-64=2.40=hb3c18ed_9 - - blas=2.120=openblas - - blas-devel=3.9.0=20_linux64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h44aadfe_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hd590300_1 - - brotli-bin=1.1.0=hd590300_1 - - brotli-python=1.1.0=py39h3d6467e_1 - - bwidget=1.9.14=ha770c72_1 - - bzip2=1.0.8=hd590300_5 - - c-ares=1.28.1=hd590300_0 - - c-compiler=1.7.0=hd590300_1 - - ca-certificates=2024.6.2=hbcca054_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=hbb29018_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cddlib=1!0.94m=h9202a9a_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py39h7a31438_0 - - chardet=5.2.0=py39hf3d152e_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=hd590300_1 - - cmake=3.29.6=hcafd917_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py39hf3d152e_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compilers=1.7.0=ha770c72_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py39h7633fee_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - cryptography=42.0.8=py39h8169da8_0 - - curl=8.8.0=he654da7_0 - - cvxopt=1.3.2=py39h640215f_2 - - cxx-compiler=1.7.0=h00ab1b0_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py39h1698a45_0 - - cysignals=1.11.2=py39h1ce0973_3 - - cython=3.0.10=py39h3d6467e_0 - - dbus=1.13.6=h5008d03_3 - - debugpy=1.8.1=py39h3d6467e_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=hd9d9efa_1203 - - ecl=23.9.9=hed6455c_0 - - eclib=20231212=h96f522a_0 - - ecm=7.0.5=h9458935_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h59595ed_0 - - fflas-ffpack=2.5.0=h4f9960b_0 - - fftw=3.3.10=nompi_hf1063bd_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h14ed4e7_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py39hd3abc70_0 - - fortran-compiler=1.7.0=heb67821_1 - - fplll=5.4.5=h384768b_0 - - fpylll=0.6.1=py39h2525e16_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=h267a509_2 - - fribidi=1.0.10=h36c2ea0_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he9a28a4_3 - - gap-defaults=4.12.2=ha770c72_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gcc=12.3.0=h915e2ae_13 - - gcc_impl_linux-64=12.3.0=h58ffeeb_13 - - gcc_linux-64=12.3.0=h9528a6a_9 - - gengetopt=2.23=h9c3ff4c_0 - - gettext=0.22.5=h59595ed_2 - - gettext-tools=0.22.5=h59595ed_2 - - gf2x=1.3.0=ha476b99_2 - - gfan=0.6.2=hb86e20a_1003 - - gfortran=12.3.0=h915e2ae_13 - - gfortran_impl_linux-64=12.3.0=h8f2110c_13 - - gfortran_linux-64=12.3.0=h5877db1_9 - - gh=2.52.0=he0e2781_0 - - giac=1.9.0.21=h673759e_1 - - giflib=5.2.2=hd590300_0 - - git=2.45.2=pl5321ha099dd3_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=hb789bce_0 - - glib=2.80.2=h8a4344b_1 - - glib-tools=2.80.2=h73ef956_1 - - glpk=5.0=h445213a_0 - - gmp=6.3.0=hac33072_2 - - gmpy2=2.1.5=py39h048c657_1 - - graphite2=1.3.13=h59595ed_1003 - - gsl=2.7=he838d99_0 - - gst-plugins-base=1.24.5=hbaaba92_0 - - gstreamer=1.24.5=haf2f30d_0 - - gxx=12.3.0=h915e2ae_13 - - gxx_impl_linux-64=12.3.0=h2a574ab_13 - - gxx_linux-64=12.3.0=ha28b414_9 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=hfac3d4d_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=h59595ed_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hef0740d_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h623f65a_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh3099207_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.18.1=pyh707e725_3 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jeepney=0.8.0=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=ha770c72_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py39hf3d152e_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py39hf3d152e_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - kernel-headers_linux-64=2.6.32=he073ed8_17 - - keyring=25.2.1=pyha804496_0 - - keyutils=1.6.1=h166bdaf_0 - - kiwisolver=1.4.5=py39h7633fee_1 - - krb5=1.21.2=h659d440_0 - - lame=3.100=h166bdaf_1003 - - lcalc=2.0.5=h5aac1b6_2 - - lcms2=2.16=hb7c19ff_0 - - ld_impl_linux-64=2.40=hf3520f5_7 - - lerc=4.0.0=h27087fc_0 - - libasprintf=0.22.5=h661eb56_2 - - libasprintf-devel=0.22.5=h661eb56_2 - - libatomic_ops=7.6.14=h166bdaf_0 - - libblas=3.9.0=20_linux64_openblas - - libboost=1.85.0=hba137d9_2 - - libboost-devel=1.85.0=h00ab1b0_2 - - libboost-headers=1.85.0=ha770c72_2 - - libbraiding=1.2=hcb278e6_0 - - libbrial=1.2.12=h76af697_3 - - libbrotlicommon=1.1.0=hd590300_1 - - libbrotlidec=1.1.0=hd590300_1 - - libbrotlienc=1.1.0=hd590300_1 - - libcap=2.69=h0f662aa_0 - - libcblas=3.9.0=20_linux64_openblas - - libcbor=0.10.2=hcb278e6_0 - - libclang-cpp15=15.0.7=default_h127d8a8_5 - - libclang13=18.1.8=default_h6ae225f_0 - - libcups=2.3.3=h4637d8d_4 - - libcurl=8.8.0=hca28451_0 - - libdeflate=1.20=hd590300_0 - - libedit=3.1.20191231=he28a2e2_2 - - libev=4.33=hd590300_2 - - libevent=2.1.12=hf998b51_1 - - libexpat=2.6.2=h59595ed_0 - - libffi=3.4.2=h7f98852_5 - - libfido2=1.15.0=hdd1f21f_0 - - libflac=1.4.3=h59595ed_0 - - libflint=3.0.1=h5f2e117_ntl_100 - - libgcc-devel_linux-64=12.3.0=h6b66f73_113 - - libgcc-ng=13.2.0=h77fa898_13 - - libgcrypt=1.10.3=hd590300_0 - - libgd=2.3.3=h119a65a_9 - - libgettextpo=0.22.5=h59595ed_2 - - libgettextpo-devel=0.22.5=h59595ed_2 - - libgfortran-ng=13.2.0=h69a702a_13 - - libgfortran5=13.2.0=h3d2ce59_13 - - libglib=2.80.2=h8a4344b_1 - - libgomp=13.2.0=h77fa898_13 - - libgpg-error=1.49=h4f305b6_0 - - libhomfly=1.02r6=hd590300_1 - - libhwloc=2.10.0=default_h5622ce7_1001 - - libiconv=1.17=hd590300_2 - - libjpeg-turbo=3.0.0=hd590300_1 - - liblapack=3.9.0=20_linux64_openblas - - liblapacke=3.9.0=20_linux64_openblas - - libllvm15=15.0.7=hb3ce162_4 - - libllvm18=18.1.8=hc9dba70_0 - - libnghttp2=1.58.0=h47da74e_1 - - libnsl=2.0.1=hd590300_0 - - libogg=1.3.5=h4ab18f5_0 - - libopenblas=0.3.25=pthreads_h413a1c8_0 - - libopus=1.3.1=h7f98852_1 - - libpng=1.6.43=h2797004_0 - - libpq=16.3=ha72fbe1_0 - - libsanitizer=12.3.0=hb8811af_13 - - libsndfile=1.2.2=hc60ed4a_1 - - libsodium=1.0.18=h36c2ea0_1 - - libsqlite=3.46.0=hde9e2c9_0 - - libssh2=1.11.0=h0841786_0 - - libstdcxx-devel_linux-64=12.3.0=h6b66f73_113 - - libstdcxx-ng=13.2.0=hc0a3c3a_13 - - libsystemd0=255=h3516f8a_1 - - libtiff=4.6.0=h1dd3fc0_3 - - libtool=2.4.7=h27087fc_0 - - libudev1=255=h3f72095_1 - - libuuid=2.38.1=h0b41bf4_0 - - libuv=1.48.0=hd590300_0 - - libvorbis=1.3.7=h9c3ff4c_0 - - libwebp=1.4.0=h2c329e2_0 - - libwebp-base=1.4.0=hd590300_0 - - libxcb=1.16=hd590300_0 - - libxcrypt=4.4.36=hd590300_1 - - libxkbcommon=1.7.0=h2c5496b_1 - - libxml2=2.12.7=hc051c1a_1 - - libzlib=1.3.1=h4ab18f5_1 - - linbox=1.7.0=ha329b40_0 - - llvm-openmp=18.1.8=hf5423f3_0 - - lrcalc=2.1=h59595ed_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - lz4-c=1.9.4=hcb278e6_0 - - m4=1.4.18=h516909a_1001 - - m4ri=20140914=hae5d5c5_1006 - - m4rie=20150908=h267a509_1002 - - make=4.3=hd18ef5c_1 - - markupsafe=2.1.5=py39hd1e30aa_0 - - mathjax=3.2.2=ha770c72_0 - - matplotlib=3.8.4=py39hf3d152e_2 - - matplotlib-base=3.8.4=py39h10d1fc8_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=hed6455c_2 - - memory-allocator=0.1.3=py39hd1e30aa_0 - - meson=1.5.2=pyhd8ed1ab_0 - - meson-python=0.15.0=pyh0c530f3_0 - - metis=5.1.0=h59595ed_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=hfe3b2da_0 - - mpfi=1.5.4=h9f54685_1001 - - mpfr=4.2.1=h9458935_1 - - mpg123=1.32.6=h59595ed_0 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py39h95fdab5_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - mysql-common=8.3.0=hf1915f5_4 - - mysql-libs=8.3.0=hca2cd23_4 - - nauty=2.8.8=hd590300_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h59595ed_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h297d8ca_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - nspr=4.35=h27087fc_0 - - nss=3.101=h593d115_0 - - ntl=11.4.3=hef3c4d3_1 - - numpy=1.26.4=py39h474f0d3_0 - - openblas=0.3.25=pthreads_h7a3da1a_0 - - openjdk=21.0.2=haa376d0_0 - - openjpeg=2.5.2=h488ebb8_0 - - openssh=9.6p1=h2d3b35a_0 - - openssl=3.3.1=h4ab18f5_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=h36c2ea0_0 - - pandoc=3.2.1=ha770c72_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h84a9a3c_0 - - pari=2.15.5=h4d4ae9b_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=h7f98852_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h0f59acf_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_hd590300_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py39h16a7006_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.2=h59595ed_0 - - pkg-config=0.29.2=h36c2ea0_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=hd590300_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h6ec01c2_1006 - - pplpy=0.8.9=py39h9e9cb73_1 - - primecount=7.9=hcb278e6_0 - - primecountpy=0.1.0=py39h7633fee_4 - - primesieve=11.1=h59595ed_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py39hd3abc70_0 - - pthread-stubs=0.4=h36c2ea0_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pulseaudio-client=17.0=hb77b528_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py39h7633fee_0 - - pybind11-global=2.12.0=py39h7633fee_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py39ha68c5e3_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyqt=5.15.9=py39h52134e7_5 - - pyqt5-sip=12.12.2=py39h3d6467e_5 - - pyrsistent=0.20.0=py39hd1e30aa_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.9.19=h0755675_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py39h3d6467e_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.9=4_cp39 - - pythran=0.15.0=py39hda80f44_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py39hf3d152e_4 - - pyyaml=6.0.1=py39hd1e30aa_1 - - pyzmq=26.0.3=py39ha1047a2_0 - - qd=2.3.22=h2cc385e_1004 - - qhull=2020.2=h4bd325d_2 - - qt-main=5.15.8=ha2b5568_22 - - r-base=4.3.3=he2d9a6e_3 - - r-lattice=0.22_6=r43h57805ef_0 - - readline=8.2=h8228510_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hd590300_0 - - rpds-py=0.18.1=py39ha68c5e3_0 - - rpy2=3.5.11=py39r43h44dd56e_3 - - ruamel.yaml=0.18.6=py39hd1e30aa_0 - - ruamel.yaml.clib=0.2.8=py39hd1e30aa_0 - - rw=0.9=hd590300_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py39h474f0d3_0 - - secretstorage=3.3.3=py39hf3d152e_2 - - sed=4.8=he412f7d_0 - - send2trash=1.8.3=pyh0d859eb_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h33f5c3f_1 - - sip=6.7.12=py39h3d6467e_0 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h6d4b2fc_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf4753ba_1 - - symmetrica=3.0.1=hcb278e6_0 - - sympow=2.023.6=hc6ab17c_3 - - sympy=1.12.1=pypyh2585a3b_103 - - sysroot_linux-64=2.12=he073ed8_17 - - tachyon=0.99b6=hba7d16a_1002 - - tar=1.34=hb2e2bae_1 - - tbb=2021.12.0=h297d8ca_1 - - terminado=0.18.1=pyh0d859eb_0 - - texinfo=7.0=pl5321h0f457ee_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=noxft_h4845f30_101 - - tktable=2.10=h8bc8fbc_6 - - toml=0.10.2=pyhd8ed1ab_0 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py39hd3abc70_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py39hf3d152e_0 - - unicodedata2=15.1.0=py39hd1e30aa_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xcb-util=0.4.1=hb711507_2 - - xcb-util-image=0.4.0=hb711507_2 - - xcb-util-keysyms=0.4.1=hb711507_0 - - xcb-util-renderutil=0.3.10=hb711507_0 - - xcb-util-wm=0.4.2=hb711507_0 - - xkeyboard-config=2.42=h4ab18f5_0 - - xorg-fixesproto=5.0=h7f98852_1002 - - xorg-inputproto=2.3.2=h7f98852_1002 - - xorg-kbproto=1.0.7=h7f98852_1002 - - xorg-libice=1.1.1=hd590300_0 - - xorg-libsm=1.2.4=h7391055_0 - - xorg-libx11=1.8.9=hb711507_1 - - xorg-libxau=1.0.11=hd590300_0 - - xorg-libxdmcp=1.1.3=h7f98852_0 - - xorg-libxext=1.3.4=h0b41bf4_2 - - xorg-libxfixes=5.0.3=h7f98852_1004 - - xorg-libxi=1.7.10=h7f98852_0 - - xorg-libxrender=0.9.11=hd590300_0 - - xorg-libxt=1.3.0=hd590300_1 - - xorg-libxtst=1.2.3=h7f98852_1002 - - xorg-recordproto=1.14.2=h7f98852_1002 - - xorg-renderproto=0.11.1=h7f98852_1002 - - xorg-xextproto=7.3.0=h0b41bf4_1003 - - xorg-xf86vidmodeproto=2.3.1=h7f98852_1002 - - xorg-xproto=7.0.31=h7f98852_1007 - - xz=5.2.6=h166bdaf_0 - - yaml=0.2.5=h7f98852_2 - - zeromq=4.3.5=h75354e8_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h4ab18f5_1 - - zstd=1.5.6=ha6fb4c9_0 diff --git a/environment-dev-3.9-macos-x86_64.yml b/environment-dev-3.9-macos-x86_64.yml deleted file mode 100644 index a09f7e4f3b1..00000000000 --- a/environment-dev-3.9-macos-x86_64.yml +++ /dev/null @@ -1,470 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: osx-64 -# input_hash: 87145dff13f485d3cacd44987c6622d73ff7e5ebfdff843fe604d9835dead5f9 - -channels: - - conda-forge -dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py39hdc70f33_4 - - arpack=3.9.1=nompi_hf81eadf_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321hed12c24_1 - - automake=1.16.5=pl5321h694c41f_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=h0d85af4_0 - - bdw-gc=8.0.6=h940c156_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osx64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=h07eb623_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=h0dc2134_1 - - brotli-bin=1.1.0=h0dc2134_1 - - brotli-python=1.1.0=py39h840bb9f_1 - - bwidget=1.9.14=h694c41f_1 - - bzip2=1.0.8=h10d778d_5 - - c-ares=1.28.1=h10d778d_0 - - c-compiler=1.7.0=h282daa2_1 - - ca-certificates=2024.6.2=h8857fd0_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=h9f650ed_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cctools=986=h40f6528_0 - - cctools_osx-64=986=ha1c5b94_0 - - cddlib=1!0.94m=h0f52abe_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py39h18ef598_0 - - chardet=5.2.0=py39h6e9494a_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_ha3b9224_8 - - clang-16=16.0.6=default_h4c8afb6_8 - - clang_impl_osx-64=16.0.6=h8787910_16 - - clang_osx-64=16.0.6=hb91bd55_16 - - clangxx=16.0.6=default_ha3b9224_8 - - clangxx_impl_osx-64=16.0.6=h6d92fbe_16 - - clangxx_osx-64=16.0.6=hb91bd55_16 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=h10d778d_1 - - cmake=3.29.6=h749d262_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py39h6e9494a_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=ha38d28d_2 - - compiler-rt_osx-64=16.0.6=ha38d28d_2 - - compilers=1.7.0=h694c41f_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py39h0ca7971_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - curl=8.8.0=hea67d85_0 - - cvxopt=1.3.2=py39hd66cc7a_2 - - cxx-compiler=1.7.0=h7728843_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py39hc0d7317_0 - - cysignals=1.11.2=py39hf6ae30e_3 - - cython=3.0.10=py39hd253f6c_0 - - debugpy=1.8.1=py39hd253f6c_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h6e329d1_1203 - - ecl=23.9.9=h2b27fa8_0 - - eclib=20231212=h02435c3_0 - - ecm=7.0.5=h4f6b447_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=h73e2aa4_0 - - fflas-ffpack=2.5.0=h5898d61_0 - - fftw=3.3.10=nompi_h292e606_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h5bb23bf_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py39hded5825_0 - - fortran-compiler=1.7.0=h6c2ab21_1 - - fplll=5.4.5=hb7981ad_0 - - fpylll=0.6.1=py39h3b3ffec_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=h60636b9_2 - - fribidi=1.0.10=hbcb3906_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=hc16eb5f_3 - - gap-defaults=4.12.2=h694c41f_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=he49afe7_0 - - gettext=0.22.5=h5ff76d1_2 - - gettext-tools=0.22.5=h5ff76d1_2 - - gf2x=1.3.0=hb2a7efb_2 - - gfan=0.6.2=hd793b56_1003 - - gfortran=12.3.0=h2c809b3_1 - - gfortran_impl_osx-64=12.3.0=hc328e78_3 - - gfortran_osx-64=12.3.0=h18f7dce_1 - - gh=2.52.0=he13f2d6_0 - - giac=1.9.0.21=h92f3f65_1 - - giflib=5.2.2=h10d778d_0 - - git=2.45.2=pl5321hb0c6a96_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=h1b3d6f7_0 - - glpk=5.0=h3cb5acd_0 - - gmp=6.3.0=hf036a51_2 - - gmpy2=2.1.5=py39h87b48b1_1 - - graphite2=1.3.13=h73e2aa4_1003 - - gsl=2.7=h93259b0_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h053f038_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hf5e326d_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=hde4452d_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=h61918c1_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.18.1=pyh707e725_3 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isl=0.26=imath32_h2e86a7b_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.9=h694c41f_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py39h6e9494a_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.1=py39h6e9494a_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - keyring=25.2.1=pyh534df25_0 - - kiwisolver=1.4.5=py39h8ee36c8_1 - - krb5=1.21.2=hb884880_0 - - lcalc=2.0.5=h547a6ed_2 - - lcms2=2.16=ha2f27b4_0 - - ld64=711=ha02d983_0 - - ld64_osx-64=711=ha20a434_0 - - lerc=4.0.0=hb486fe8_0 - - libasprintf=0.22.5=h5ff76d1_2 - - libasprintf-devel=0.22.5=h5ff76d1_2 - - libatomic_ops=7.6.14=hb7f2c08_0 - - libblas=3.9.0=20_osx64_openblas - - libboost=1.85.0=h739af76_2 - - libboost-devel=1.85.0=h2b186f8_2 - - libboost-headers=1.85.0=h694c41f_2 - - libbraiding=1.2=hf0c8a7f_0 - - libbrial=1.2.12=h81e9653_3 - - libbrotlicommon=1.1.0=h0dc2134_1 - - libbrotlidec=1.1.0=h0dc2134_1 - - libbrotlienc=1.1.0=h0dc2134_1 - - libcblas=3.9.0=20_osx64_openblas - - libcbor=0.10.2=hf0c8a7f_0 - - libclang-cpp16=16.0.6=default_h4c8afb6_8 - - libcurl=8.8.0=hf9fcc65_0 - - libcxx=17.0.6=h88467a6_0 - - libdeflate=1.20=h49d49c5_0 - - libedit=3.1.20191231=h0678c8f_2 - - libev=4.33=h10d778d_2 - - libexpat=2.6.2=h73e2aa4_0 - - libffi=3.4.2=h0d85af4_5 - - libfido2=1.15.0=h41b28d8_0 - - libflint=3.0.1=h5d15de0_ntl_100 - - libgd=2.3.3=h0dceb68_9 - - libgettextpo=0.22.5=h5ff76d1_2 - - libgettextpo-devel=0.22.5=h5ff76d1_2 - - libgfortran=5.0.0=13_2_0_h97931a8_3 - - libgfortran-devel_osx-64=12.3.0=h0b6f5ec_3 - - libgfortran5=13.2.0=h2873a65_3 - - libglib=2.80.2=h736d271_1 - - libhomfly=1.02r6=h10d778d_1 - - libhwloc=2.10.0=default_h456cccd_1001 - - libiconv=1.17=hd75f5a5_2 - - libintl=0.22.5=h5ff76d1_2 - - libintl-devel=0.22.5=h5ff76d1_2 - - libjpeg-turbo=3.0.0=h0dc2134_1 - - liblapack=3.9.0=20_osx64_openblas - - liblapacke=3.9.0=20_osx64_openblas - - libllvm16=16.0.6=hbedff68_3 - - libnghttp2=1.58.0=h64cf6d3_1 - - libopenblas=0.3.25=openmp_hfef2a42_0 - - libpng=1.6.43=h92b6c6a_0 - - libsodium=1.0.18=hbcb3906_1 - - libsqlite=3.46.0=h1b8f9f3_0 - - libssh2=1.11.0=hd019ec5_0 - - libtiff=4.6.0=h129831d_3 - - libtool=2.4.7=hf0c8a7f_0 - - libuv=1.48.0=h67532ce_0 - - libwebp=1.4.0=hc207709_0 - - libwebp-base=1.4.0=h10d778d_0 - - libxcb=1.16=h0dc2134_0 - - libxml2=2.12.7=h3e169fe_1 - - libzlib=1.3.1=h87427d6_1 - - linbox=1.7.0=h7061c92_0 - - llvm-openmp=18.1.8=h15ab845_0 - - llvm-tools=16.0.6=hbedff68_3 - - lrcalc=2.1=h73e2aa4_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - m4=1.4.18=haf1e3a3_1001 - - m4ri=20140914=hd82a5f3_1006 - - m4rie=20150908=hc616cfc_1002 - - make=4.3=h22f3db7_1 - - markupsafe=2.1.5=py39ha09f3b3_0 - - mathjax=3.2.2=h694c41f_0 - - matplotlib=3.8.4=py39h6e9494a_2 - - matplotlib-base=3.8.4=py39hfca4cae_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2b27fa8_2 - - memory-allocator=0.1.3=py39hdc70f33_0 - - metis=5.1.0=he965462_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=h81bd1dd_0 - - mpfi=1.5.4=h52b28e3_1001 - - mpfr=4.2.1=h4f6b447_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py39hdf1af86_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h10d778d_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=h5846eda_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h3c5361c_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=h0ab3c2f_1 - - numpy=1.26.4=py39h28c39a1_0 - - openblas=0.3.25=openmp_h6794695_0 - - openjdk=22.0.1=h2d185b6_0 - - openjpeg=2.5.2=h7310d3a_0 - - openssh=9.6p1=h6dd4ff7_0 - - openssl=3.3.1=h87427d6_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=hbcb3906_0 - - pandoc=3.2.1=h694c41f_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h880b76c_0 - - pari=2.15.5=h7ba67ff_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=hbcf498f_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h7634a1b_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h10d778d_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py39hc3a33ae_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=h73e2aa4_0 - - pkg-config=0.29.2=ha3d46e9_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h10d778d_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=ha60d53e_1006 - - pplpy=0.8.9=py39hc385998_1 - - primecount=7.6=ha894c9a_0 - - primecountpy=0.1.0=py39h8ee36c8_4 - - primesieve=11.0=hf0c8a7f_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py39hded5825_0 - - pthread-stubs=0.4=hc929b4f_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py39h0ca7971_0 - - pybind11-global=2.12.0=py39h0ca7971_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py39hf59063a_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py39hf8f43b1_0 - - pyobjc-framework-cocoa=10.3.1=py39hf8f43b1_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py39ha09f3b3_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.9.19=h7a9c478_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py39hd253f6c_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.9=4_cp39 - - pythran=0.15.0=py39h5d0c61a_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py39h6e9494a_4 - - pyyaml=6.0.1=py39hdc70f33_1 - - pyzmq=26.0.3=py39h304b177_0 - - qd=2.3.22=h2beb688_1004 - - qhull=2020.2=h940c156_2 - - r-base=4.3.3=h4648a1f_3 - - r-lattice=0.22_6=r43hb2c329c_0 - - readline=8.2=h9e318b2_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=h0dc2134_0 - - rpds-py=0.18.1=py39hf59063a_0 - - rpy2=3.5.11=py39r43hd01001f_3 - - ruamel.yaml=0.18.6=py39ha09f3b3_0 - - ruamel.yaml.clib=0.2.8=py39ha09f3b3_0 - - rw=0.9=h10d778d_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py39ha321857_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - sigtool=0.1.3=h88f4db0_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=h0d51a9f_1 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h28673e1_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hd2b2131_1 - - symmetrica=3.0.1=hf0c8a7f_0 - - sympow=2.023.6=h115ba6a_3 - - sympy=1.12.1=pypyh2585a3b_103 - - tachyon=0.99b6=h3a1d103_1002 - - tapi=1100.0.11=h9ce4665_0 - - tar=1.34=hcb2f6ea_1 - - tbb=2021.12.0=h3c5361c_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321hc47821c_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h1abcd95_1 - - tktable=2.10=hba9d6f1_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py39hded5825_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py39h6e9494a_0 - - unicodedata2=15.1.0=py39hdc70f33_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=h0dc2134_0 - - xorg-libxdmcp=1.1.3=h35c211d_0 - - xz=5.2.6=h775f41a_0 - - yaml=0.2.5=h0d85af4_2 - - zeromq=4.3.5=hde137ed_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=h87427d6_1 - - zstd=1.5.6=h915ae27_0 diff --git a/environment-dev-3.9-macos.yml b/environment-dev-3.9-macos.yml deleted file mode 100644 index dd2bccb3380..00000000000 --- a/environment-dev-3.9-macos.yml +++ /dev/null @@ -1,472 +0,0 @@ -name: sage-dev -# Generated by conda-lock. -# platform: osx-arm64 -# input_hash: 3e552281740b1a37b111ca4468f2f30142d4a3d4c041f3d342f28b36394c84de - -channels: - - conda-forge -dependencies: - - _r-mutex=1.0.1=anacondar_1 - - alabaster=0.7.16=pyhd8ed1ab_0 - - annotated-types=0.7.0=pyhd8ed1ab_0 - - anyio=4.4.0=pyhd8ed1ab_0 - - appdirs=1.4.4=pyh9f0ad1d_0 - - appnope=0.1.4=pyhd8ed1ab_0 - - argon2-cffi=23.1.0=pyhd8ed1ab_0 - - argon2-cffi-bindings=21.2.0=py39h0f82c59_4 - - arpack=3.9.1=nompi_h593882a_101 - - arrow=1.3.0=pyhd8ed1ab_0 - - asttokens=2.4.1=pyhd8ed1ab_0 - - async-lru=2.0.4=pyhd8ed1ab_0 - - attrs=23.2.0=pyh71513ae_0 - - autoconf=2.71=pl5321hcd07c0c_1 - - automake=1.16.5=pl5321hce30654_0 - - babel=2.14.0=pyhd8ed1ab_0 - - backports=1.0=pyhd8ed1ab_3 - - backports.tarfile=1.0.0=pyhd8ed1ab_1 - - bc=1.07.1=h3422bc3_0 - - bdw-gc=8.0.6=hc021e02_0 - - beautifulsoup4=4.12.3=pyha770c72_0 - - beniget=0.4.1=pyhd8ed1ab_0 - - blas=2.120=openblas - - blas-devel=3.9.0=20_osxarm64_openblas - - bleach=6.1.0=pyhd8ed1ab_0 - - boost-cpp=1.85.0=hca5e981_2 - - brial=1.2.12=pyh694c41f_3 - - brotli=1.1.0=hb547adb_1 - - brotli-bin=1.1.0=hb547adb_1 - - brotli-python=1.1.0=py39hb198ff7_1 - - bwidget=1.9.14=hce30654_1 - - bzip2=1.0.8=h93a5062_5 - - c-ares=1.28.1=h93a5062_0 - - c-compiler=1.7.0=h6aa9301_1 - - ca-certificates=2024.6.2=hf0a4a13_0 - - cachecontrol=0.14.0=pyhd8ed1ab_1 - - cachecontrol-with-filecache=0.14.0=pyhd8ed1ab_1 - - cached-property=1.5.2=hd8ed1ab_1 - - cached_property=1.5.2=pyha770c72_1 - - cachetools=5.3.3=pyhd8ed1ab_0 - - cachy=0.3.0=pyhd8ed1ab_1 - - cairo=1.18.0=hc6c324b_2 - - cattrs=23.2.3=pyhd8ed1ab_0 - - cctools=986=h4faf515_0 - - cctools_osx-arm64=986=h62378fb_0 - - cddlib=1!0.94m=h6d7a090_0 - - certifi=2024.6.2=pyhd8ed1ab_0 - - cffi=1.16.0=py39he153c15_0 - - chardet=5.2.0=py39h2804cbe_1 - - charset-normalizer=3.3.2=pyhd8ed1ab_0 - - clang=16.0.6=default_h095aff0_8 - - clang-16=16.0.6=default_hb63da90_8 - - clang_impl_osx-arm64=16.0.6=hc421ffc_16 - - clang_osx-arm64=16.0.6=h54d7cd3_16 - - clangxx=16.0.6=default_h095aff0_8 - - clangxx_impl_osx-arm64=16.0.6=hcd7bac0_16 - - clangxx_osx-arm64=16.0.6=h54d7cd3_16 - - click=8.1.7=unix_pyh707e725_0 - - click-default-group=1.2.4=pyhd8ed1ab_0 - - clikit=0.6.2=pyhd8ed1ab_2 - - cliquer=1.22=h93a5062_1 - - cmake=3.29.6=had79d8f_0 - - colorama=0.4.6=pyhd8ed1ab_0 - - colorlog=6.8.2=py39h2804cbe_0 - - comm=0.2.2=pyhd8ed1ab_0 - - compiler-rt=16.0.6=h3808999_2 - - compiler-rt_osx-arm64=16.0.6=h3808999_2 - - compilers=1.7.0=hce30654_1 - - conda-lock=2.5.7=pyhd8ed1ab_0 - - contourpy=1.2.1=py39h48c5dd5_0 - - conway-polynomials=0.9=pyhd8ed1ab_0 - - cppy=1.2.1=pyhd8ed1ab_0 - - crashtest=0.4.1=pyhd8ed1ab_0 - - curl=8.8.0=h653d890_0 - - cvxopt=1.3.2=py39hf9e8641_2 - - cxx-compiler=1.7.0=h2ffa867_1 - - cycler=0.12.1=pyhd8ed1ab_0 - - cypari2=2.1.5=py39h070b2a8_0 - - cysignals=1.11.2=py39h65fc70a_3 - - cython=3.0.10=py39hf3050f2_0 - - debugpy=1.8.1=py39hf3050f2_0 - - decorator=5.1.1=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - distlib=0.3.8=pyhd8ed1ab_0 - - docutils=0.21.2=pyhd8ed1ab_0 - - dsdp=5.8=h9397a75_1203 - - ecl=23.9.9=h1d9728a_0 - - eclib=20231212=h7f07de4_0 - - ecm=7.0.5=h41d338b_0 - - editables=0.5=pyhd8ed1ab_0 - - ensureconda=1.4.4=pyhd8ed1ab_0 - - entrypoints=0.4=pyhd8ed1ab_0 - - esbonio=0.16.4=pyhd8ed1ab_0 - - exceptiongroup=1.2.0=pyhd8ed1ab_2 - - execnet=2.1.1=pyhd8ed1ab_0 - - executing=2.0.1=pyhd8ed1ab_0 - - expat=2.6.2=hebf3989_0 - - fflas-ffpack=2.5.0=h4bc3318_0 - - fftw=3.3.10=nompi_h6637ab6_110 - - filelock=3.15.4=pyhd8ed1ab_0 - - flit-core=3.9.0=pyhd8ed1ab_1 - - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 - - font-ttf-inconsolata=3.000=h77eed37_0 - - font-ttf-source-code-pro=2.038=h77eed37_0 - - font-ttf-ubuntu=0.83=h77eed37_2 - - fontconfig=2.14.2=h82840c6_0 - - fonts-conda-ecosystem=1=0 - - fonts-conda-forge=1=0 - - fonttools=4.53.0=py39hfea33bf_0 - - fortran-compiler=1.7.0=hafb19e3_1 - - fplll=5.4.5=hb7d509d_0 - - fpylll=0.6.1=py39h2eadeda_0 - - fqdn=1.5.1=pyhd8ed1ab_0 - - freetype=2.12.1=hadb7bae_2 - - fribidi=1.0.10=h27ca646_0 - - furo=2024.5.6=pyhd8ed1ab_0 - - gap-core=4.12.2=he8f4e70_3 - - gap-defaults=4.12.2=hce30654_3 - - gast=0.5.4=pyhd8ed1ab_0 - - gengetopt=2.23=hbdafb3b_0 - - gettext=0.22.5=h8fbad5d_2 - - gettext-tools=0.22.5=h8fbad5d_2 - - gf2x=1.3.0=hdaa854c_2 - - gfan=0.6.2=hec08f5c_1003 - - gfortran=12.3.0=h1ca8e4b_1 - - gfortran_impl_osx-arm64=12.3.0=h53ed385_3 - - gfortran_osx-arm64=12.3.0=h57527a5_1 - - gh=2.52.0=h163aea0_0 - - giac=1.9.0.21=h1c96721_1 - - giflib=5.2.2=h93a5062_0 - - git=2.45.2=pl5321h41514c7_1 - - gitdb=4.0.11=pyhd8ed1ab_0 - - gitpython=3.1.43=pyhd8ed1ab_0 - - givaro=4.2.0=h018886a_0 - - glpk=5.0=h6d7a090_0 - - gmp=6.3.0=h7bae524_2 - - gmpy2=2.1.5=py39h9bb7c0c_1 - - graphite2=1.3.13=hebf3989_1003 - - gsl=2.7=h6e638da_0 - - h11=0.14.0=pyhd8ed1ab_0 - - h2=4.1.0=pyhd8ed1ab_0 - - harfbuzz=8.5.0=h1836168_0 - - hatchling=1.25.0=pyhd8ed1ab_0 - - hpack=4.0.0=pyh9f0ad1d_0 - - html5lib=1.1=pyh9f0ad1d_0 - - httpcore=1.0.5=pyhd8ed1ab_0 - - httpx=0.27.0=pyhd8ed1ab_0 - - hyperframe=6.0.1=pyhd8ed1ab_0 - - icu=73.2=hc8870d7_0 - - idna=3.7=pyhd8ed1ab_0 - - igraph=0.10.12=h762ac30_1 - - imagesize=1.4.1=pyhd8ed1ab_0 - - iml=1.0.5=hd73f12c_1004 - - importlib-metadata=8.0.0=pyha770c72_0 - - importlib-resources=6.4.0=pyhd8ed1ab_0 - - importlib_metadata=8.0.0=hd8ed1ab_0 - - importlib_resources=6.4.0=pyhd8ed1ab_0 - - iniconfig=2.0.0=pyhd8ed1ab_0 - - ipykernel=6.29.4=pyh57ce528_0 - - ipympl=0.9.4=pyhd8ed1ab_0 - - ipython=8.18.1=pyh707e725_3 - - ipython_genutils=0.2.0=pyhd8ed1ab_1 - - ipywidgets=8.1.3=pyhd8ed1ab_0 - - isl=0.26=imath32_h347afa1_101 - - isoduration=20.11.0=pyhd8ed1ab_0 - - jaraco.classes=3.4.0=pyhd8ed1ab_1 - - jaraco.context=5.3.0=pyhd8ed1ab_1 - - jaraco.functools=4.0.0=pyhd8ed1ab_0 - - jedi=0.19.1=pyhd8ed1ab_0 - - jinja2=3.1.4=pyhd8ed1ab_0 - - jmol=14.32.10=hce30654_0 - - json5=0.9.25=pyhd8ed1ab_0 - - jsonpointer=3.0.0=py39h2804cbe_0 - - jsonschema=4.22.0=pyhd8ed1ab_0 - - jsonschema-specifications=2023.12.1=pyhd8ed1ab_0 - - jsonschema-with-format-nongpl=4.22.0=pyhd8ed1ab_0 - - jupyter-jsmol=2022.1.0=pyhd8ed1ab_0 - - jupyter-lsp=2.2.5=pyhd8ed1ab_0 - - jupyter-sphinx=0.5.3=pyha770c72_4 - - jupyter_client=8.6.2=pyhd8ed1ab_0 - - jupyter_core=5.7.2=py39h2804cbe_0 - - jupyter_events=0.10.0=pyhd8ed1ab_0 - - jupyter_server=2.14.1=pyhd8ed1ab_0 - - jupyter_server_terminals=0.5.3=pyhd8ed1ab_0 - - jupyter_sphinx=0.5.3=hd8ed1ab_4 - - jupyterlab=4.2.2=pyhd8ed1ab_0 - - jupyterlab_pygments=0.3.0=pyhd8ed1ab_1 - - jupyterlab_server=2.27.2=pyhd8ed1ab_0 - - jupyterlab_widgets=3.0.11=pyhd8ed1ab_0 - - keyring=25.2.1=pyh534df25_0 - - kiwisolver=1.4.5=py39hbd775c9_1 - - krb5=1.21.2=h92f50d5_0 - - lcalc=2.0.5=h4a402bc_2 - - lcms2=2.16=ha0e7c42_0 - - ld64=711=h634c8be_0 - - ld64_osx-arm64=711=ha4bd21c_0 - - lerc=4.0.0=h9a09cb3_0 - - libasprintf=0.22.5=h8fbad5d_2 - - libasprintf-devel=0.22.5=h8fbad5d_2 - - libatomic_ops=7.6.14=h1a8c8d9_0 - - libblas=3.9.0=20_osxarm64_openblas - - libboost=1.85.0=h17eb2be_2 - - libboost-devel=1.85.0=hf450f58_2 - - libboost-headers=1.85.0=hce30654_2 - - libbraiding=1.2=hb7217d7_0 - - libbrial=1.2.12=h56a29cd_3 - - libbrotlicommon=1.1.0=hb547adb_1 - - libbrotlidec=1.1.0=hb547adb_1 - - libbrotlienc=1.1.0=hb547adb_1 - - libcblas=3.9.0=20_osxarm64_openblas - - libcbor=0.10.2=hb7217d7_0 - - libclang-cpp16=16.0.6=default_hb63da90_8 - - libcurl=8.8.0=h7b6f9a7_0 - - libcxx=17.0.6=h5f092b4_0 - - libdeflate=1.20=h93a5062_0 - - libedit=3.1.20191231=hc8eb9b7_2 - - libev=4.33=h93a5062_2 - - libexpat=2.6.2=hebf3989_0 - - libffi=3.4.2=h3422bc3_5 - - libfido2=1.15.0=h9d74d49_0 - - libflint=3.0.1=h28749a5_ntl_100 - - libgd=2.3.3=hfdf3952_9 - - libgettextpo=0.22.5=h8fbad5d_2 - - libgettextpo-devel=0.22.5=h8fbad5d_2 - - libgfortran=5.0.0=13_2_0_hd922786_3 - - libgfortran-devel_osx-arm64=12.3.0=hc62be1c_3 - - libgfortran5=13.2.0=hf226fd6_3 - - libglib=2.80.2=h59d46d9_1 - - libhomfly=1.02r6=h93a5062_1 - - libhwloc=2.10.0=default_h7685b71_1001 - - libiconv=1.17=h0d3ecfb_2 - - libintl=0.22.5=h8fbad5d_2 - - libintl-devel=0.22.5=h8fbad5d_2 - - libjpeg-turbo=3.0.0=hb547adb_1 - - liblapack=3.9.0=20_osxarm64_openblas - - liblapacke=3.9.0=20_osxarm64_openblas - - libllvm16=16.0.6=haab561b_3 - - libnghttp2=1.58.0=ha4dd798_1 - - libopenblas=0.3.25=openmp_h6c19121_0 - - libpng=1.6.43=h091b4b1_0 - - libsodium=1.0.18=h27ca646_1 - - libsqlite=3.46.0=hfb93653_0 - - libssh2=1.11.0=h7a5bd25_0 - - libtiff=4.6.0=h07db509_3 - - libtool=2.4.7=hb7217d7_0 - - libuv=1.48.0=h93a5062_0 - - libwebp=1.4.0=h54798ee_0 - - libwebp-base=1.4.0=h93a5062_0 - - libxcb=1.16=hf2054a2_0 - - libxml2=2.12.7=ha661575_1 - - libzlib=1.3.1=hfb2fe0b_1 - - linbox=1.7.0=h3afee3a_0 - - llvm-openmp=18.1.8=hde57baf_0 - - llvm-tools=16.0.6=haab561b_3 - - lrcalc=2.1=hebf3989_6 - - lsprotocol=2023.0.1=pyhd8ed1ab_0 - - m4=1.4.18=h642e427_1001 - - m4ri=20140914=hc97c1ff_1006 - - m4rie=20150908=h22b9e9d_1002 - - make=4.3=he57ea6c_1 - - markupsafe=2.1.5=py39h17cfd9d_0 - - mathjax=3.2.2=hce30654_0 - - matplotlib=3.8.4=py39hdf13c20_2 - - matplotlib-base=3.8.4=py39h15359f4_2 - - matplotlib-inline=0.1.7=pyhd8ed1ab_0 - - maxima=5.47.0=h2bbcd85_2 - - memory-allocator=0.1.3=py39h0f82c59_0 - - meson=1.5.2=pyhd8ed1ab_0 - - meson-python=0.15.0=pyh0c530f3_0 - - metis=5.1.0=h13dd4ca_1007 - - mistune=3.0.2=pyhd8ed1ab_0 - - more-itertools=10.3.0=pyhd8ed1ab_0 - - mpc=1.3.1=h91ba8db_0 - - mpfi=1.5.4=hbde5f5b_1001 - - mpfr=4.2.1=h41d338b_1 - - mpmath=1.3.0=pyhd8ed1ab_0 - - msgpack-python=1.0.8=py39ha1e04a5_0 - - munkres=1.1.4=pyh9f0ad1d_0 - - nauty=2.8.8=h93a5062_1 - - nbclient=0.10.0=pyhd8ed1ab_0 - - nbconvert=7.16.4=hd8ed1ab_1 - - nbconvert-core=7.16.4=pyhd8ed1ab_1 - - nbconvert-pandoc=7.16.4=hd8ed1ab_1 - - nbformat=5.10.4=pyhd8ed1ab_0 - - ncurses=6.5=hb89a1cb_0 - - nest-asyncio=1.6.0=pyhd8ed1ab_0 - - networkx=3.2.1=pyhd8ed1ab_0 - - ninja=1.12.1=h420ef59_0 - - notebook=7.2.1=pyhd8ed1ab_0 - - notebook-shim=0.2.4=pyhd8ed1ab_0 - - ntl=11.4.3=hbb3f309_1 - - numpy=1.26.4=py39h7aa2656_0 - - openblas=0.3.25=openmp_h55c453e_0 - - openjdk=22.0.1=hbeb2e11_0 - - openjpeg=2.5.2=h9f1df11_0 - - openssh=9.6p1=hd435d45_0 - - openssl=3.3.1=hfb2fe0b_0 - - overrides=7.7.0=pyhd8ed1ab_0 - - packaging=24.1=pyhd8ed1ab_0 - - palp=2.20=h27ca646_0 - - pandoc=3.2.1=hce30654_0 - - pandocfilters=1.5.0=pyhd8ed1ab_0 - - pango=1.54.0=h5cb9fbc_0 - - pari=2.15.5=h4f2304c_2_pthread - - pari-elldata=0.0.20161017=0 - - pari-galdata=0.0.20180411=0 - - pari-galpol=0.0.20180625=0 - - pari-seadata=0.0.20090618=0 - - pari-seadata-small=0.0.20090618=0 - - parso=0.8.4=pyhd8ed1ab_0 - - pastel=0.2.1=pyhd8ed1ab_0 - - patch=2.7.6=h27ca646_1002 - - pathspec=0.12.1=pyhd8ed1ab_0 - - pcre2=10.44=h297a79d_0 - - pep517=0.13.0=pyhd8ed1ab_0 - - perl=5.32.1=7_h4614cfb_perl5 - - pexpect=4.9.0=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pillow=10.3.0=py39h3baf582_1 - - pip=24.0=pyhd8ed1ab_0 - - pixman=0.43.4=hebf3989_0 - - pkg-config=0.29.2=hab62308_1008 - - pkgconfig=1.5.5=pyhd8ed1ab_4 - - pkginfo=1.11.1=pyhd8ed1ab_0 - - pkgutil-resolve-name=1.3.10=pyhd8ed1ab_1 - - planarity=3.0.2.0=h93a5062_0 - - platformdirs=4.2.2=pyhd8ed1ab_0 - - pluggy=1.5.0=pyhd8ed1ab_0 - - ply=3.11=pyhd8ed1ab_2 - - ppl=1.2=h8b147cf_1006 - - pplpy=0.8.9=py39ha497ee3_1 - - primecount=7.6=hb6e4faa_0 - - primecountpy=0.1.0=py39hbd775c9_4 - - primesieve=11.0=hb7217d7_0 - - prometheus_client=0.20.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.47=pyha770c72_0 - - prompt_toolkit=3.0.47=hd8ed1ab_0 - - psutil=6.0.0=py39hfea33bf_0 - - pthread-stubs=0.4=h27ca646_1001 - - ptyprocess=0.7.0=pyhd3deb0d_0 - - pure_eval=0.2.2=pyhd8ed1ab_0 - - py=1.11.0=pyh6c4a22f_0 - - pybind11=2.12.0=py39h48c5dd5_0 - - pybind11-global=2.12.0=py39h48c5dd5_0 - - pycodestyle=2.12.0=pyhd8ed1ab_0 - - pycparser=2.22=pyhd8ed1ab_0 - - pydantic=2.7.4=pyhd8ed1ab_0 - - pydantic-core=2.18.4=py39h0019b8a_0 - - pygls=1.3.1=pyhd8ed1ab_0 - - pygments=2.18.0=pyhd8ed1ab_0 - - pylev=1.4.0=pyhd8ed1ab_0 - - pyobjc-core=10.3.1=py39h336d860_0 - - pyobjc-framework-cocoa=10.3.1=py39h336d860_0 - - pyparsing=3.1.2=pyhd8ed1ab_0 - - pyproject-api=1.7.1=pyhd8ed1ab_0 - - pyrsistent=0.20.0=py39h17cfd9d_0 - - pysocks=1.7.1=pyha2e5f31_6 - - pyspellchecker=0.8.0=pyhd8ed1ab_0 - - pytest=8.2.2=pyhd8ed1ab_0 - - pytest-xdist=3.6.1=pyhd8ed1ab_0 - - python=3.9.19=hd7ebdb9_0_cpython - - python-build=1.2.1=pyhd8ed1ab_0 - - python-dateutil=2.9.0=pyhd8ed1ab_0 - - python-fastjsonschema=2.20.0=pyhd8ed1ab_0 - - python-json-logger=2.0.7=pyhd8ed1ab_0 - - python-lrcalc=2.1=py39hf3050f2_6 - - python-tzdata=2024.1=pyhd8ed1ab_0 - - python_abi=3.9=4_cp39 - - pythran=0.15.0=py39h1261dcd_1 - - pytz=2024.1=pyhd8ed1ab_0 - - pytz-deprecation-shim=0.1.0.post0=py39h2804cbe_4 - - pyyaml=6.0.1=py39h0f82c59_1 - - pyzmq=26.0.3=py39he7f0319_0 - - qd=2.3.22=hbec66e7_1004 - - qhull=2020.2=hc021e02_2 - - r-base=4.3.3=h8112bfe_3 - - r-lattice=0.22_6=r43hd2d937b_0 - - readline=8.2=h92ec313_1 - - referencing=0.35.1=pyhd8ed1ab_0 - - requests=2.32.3=pyhd8ed1ab_0 - - rfc3339-validator=0.1.4=pyhd8ed1ab_0 - - rfc3986-validator=0.1.1=pyh9f0ad1d_0 - - rhash=1.4.4=hb547adb_0 - - rpds-py=0.18.1=py39h0019b8a_0 - - rpy2=3.5.11=py39r43hf4a74a7_3 - - ruamel.yaml=0.18.6=py39h17cfd9d_0 - - ruamel.yaml.clib=0.2.8=py39h17cfd9d_0 - - rw=0.9=h93a5062_2 - - sagemath-db-combinatorial-designs=20140630=1 - - sagemath-db-elliptic-curves=0.8.1=hecc5488_0 - - sagemath-db-graphs=20210214=hd8ed1ab_0 - - sagemath-db-polytopes=20170220=1 - - sagetex=3.6.1=pyhd8ed1ab_0 - - scipy=1.11.4=py39h36c428d_0 - - send2trash=1.8.3=pyh31c8845_0 - - setuptools=70.1.1=pyhd8ed1ab_0 - - setuptools-scm=8.1.0=pyhd8ed1ab_0 - - setuptools_scm=8.1.0=hd8ed1ab_0 - - sigtool=0.1.3=h44b9a77_0 - - simplegeneric=0.8.1=py_1 - - singular=4.3.2.p8=hb460b52_1 - - six=1.16.0=pyh6c4a22f_0 - - smmap=5.0.0=pyhd8ed1ab_0 - - sniffio=1.3.1=pyhd8ed1ab_0 - - snowballstemmer=2.2.0=pyhd8ed1ab_0 - - soupsieve=2.5=pyhd8ed1ab_1 - - sphinx=7.3.7=pyhd8ed1ab_0 - - sphinx-basic-ng=1.0.0b2=pyhd8ed1ab_1 - - sphinx-copybutton=0.5.2=pyhd8ed1ab_0 - - sphinxcontrib-applehelp=1.0.8=pyhd8ed1ab_0 - - sphinxcontrib-devhelp=1.0.6=pyhd8ed1ab_0 - - sphinxcontrib-htmlhelp=2.0.5=pyhd8ed1ab_0 - - sphinxcontrib-jsmath=1.0.1=pyhd8ed1ab_0 - - sphinxcontrib-qthelp=1.0.7=pyhd8ed1ab_0 - - sphinxcontrib-serializinghtml=1.1.10=pyhd8ed1ab_0 - - sphinxcontrib-websupport=1.2.7=pyhd8ed1ab_0 - - sqlite=3.46.0=h5838104_0 - - stack_data=0.6.2=pyhd8ed1ab_0 - - suitesparse=7.7.0=hf6fcff2_1 - - symmetrica=3.0.1=hb7217d7_0 - - sympow=2.023.6=hb0babe8_3 - - sympy=1.12.1=pypyh2585a3b_103 - - tachyon=0.99b6=hb8a568e_1002 - - tapi=1100.0.11=he4954df_0 - - tar=1.34=h7cb298e_1 - - tbb=2021.12.0=h420ef59_1 - - terminado=0.18.1=pyh31c8845_0 - - texinfo=7.0=pl5321h9ea1dce_0 - - three.js=122=hd8ed1ab_2 - - threejs-sage=122=hd8ed1ab_2 - - tinycss2=1.3.0=pyhd8ed1ab_0 - - tk=8.6.13=h5083fa2_1 - - tktable=2.10=h1e387b8_6 - - tomli=2.0.1=pyhd8ed1ab_0 - - tomlkit=0.12.5=pyha770c72_0 - - toolz=0.12.1=pyhd8ed1ab_0 - - tornado=6.4.1=py39hfea33bf_0 - - tox=4.15.1=pyhd8ed1ab_0 - - traitlets=5.14.3=pyhd8ed1ab_0 - - trove-classifiers=2024.5.22=pyhd8ed1ab_0 - - types-python-dateutil=2.9.0.20240316=pyhd8ed1ab_0 - - typing-extensions=4.12.2=hd8ed1ab_0 - - typing_extensions=4.12.2=pyha770c72_0 - - typing_utils=0.1.0=pyhd8ed1ab_0 - - tzdata=2024a=h0c530f3_0 - - tzlocal=5.2=py39h2804cbe_0 - - unicodedata2=15.1.0=py39h0f82c59_0 - - uri-template=1.3.0=pyhd8ed1ab_0 - - urllib3=1.26.19=pyhd8ed1ab_0 - - virtualenv=20.26.3=pyhd8ed1ab_0 - - wcwidth=0.2.13=pyhd8ed1ab_0 - - webcolors=24.6.0=pyhd8ed1ab_0 - - webencodings=0.5.1=pyhd8ed1ab_2 - - websocket-client=1.8.0=pyhd8ed1ab_0 - - wheel=0.43.0=pyhd8ed1ab_1 - - widgetsnbextension=4.0.11=pyhd8ed1ab_0 - - xorg-libxau=1.0.11=hb547adb_0 - - xorg-libxdmcp=1.1.3=h27ca646_0 - - xz=5.2.6=h57fd34a_0 - - yaml=0.2.5=h3422bc3_2 - - zeromq=4.3.5=hcc0f68c_4 - - zipp=3.19.2=pyhd8ed1ab_0 - - zlib=1.3.1=hfb2fe0b_1 - - zstd=1.5.6=hb46c0d2_0 diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sage-conf_conda/MANIFEST.in b/pkgs/sage-conf_conda/MANIFEST.in index ea5f85f8c99..98897c3d4a7 100644 --- a/pkgs/sage-conf_conda/MANIFEST.in +++ b/pkgs/sage-conf_conda/MANIFEST.in @@ -8,7 +8,6 @@ include sage_root/Makefile include sage_root/README.md include sage_root/VERSION.txt include sage_root/bootstrap -include sage_root/bootstrap-conda graft sage_root/build prune sage_root/build/.tox exclude sage_root/build/bin/sage-build-env-config # generated by configure diff --git a/pkgs/sage-conf_conda/VERSION.txt b/pkgs/sage-conf_conda/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sage-conf_conda/VERSION.txt +++ b/pkgs/sage-conf_conda/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/pyproject.toml b/pyproject.toml index 47c125c4e26..a1febc07917 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,12 +4,13 @@ build-backend = 'mesonpy' requires = [ 'meson-python', 'cypari2 >=2.1.1', - 'cysignals >=1.11.4', + # Exclude 1.12.0 because of https://github.com/sagemath/cysignals/issues/212 + 'cysignals >=1.11.2, != 1.12.0', # Exclude 3.0.3 because of https://github.com/cython/cython/issues/5748 'cython >=3.0, != 3.0.3', 'gmpy2 ~=2.1.b999', 'memory_allocator', - 'numpy >=1.19', + 'numpy >=1.25', 'jinja2' ] [project] @@ -19,12 +20,13 @@ dependencies = [ 'six >=1.15.0', 'conway-polynomials >=0.8', 'cypari2 >=2.1.1', - 'cysignals >=1.10.2', + # Exclude 1.12.0 because of https://github.com/sagemath/cysignals/issues/212 + 'cysignals >=1.11.2, != 1.12.0', 'cython >=3.0, != 3.0.3', 'gmpy2 ~=2.1.b999', 'lrcalc ~=2.1', 'memory_allocator', - 'numpy >=1.19', + 'numpy >=1.25', # Issue #30922: pplpy 0.8.4 and earlier do not declare dependencies correctly 'pplpy >=0.8.6', 'primecountpy', @@ -32,21 +34,13 @@ dependencies = [ # According to https://github.com/python/typing_extensions/blob/main/CHANGELOG.md, # version 4.4.0 adds another Python 3.11 typing backport 'typing_extensions >= 4.4.0; python_version<"3.11"', - 'ipython >=7.13.0', + 'ipython >=8.9.0', 'pexpect >=4.8.0', 'sphinx >=5.2, <9', - 'networkx >=2.4', - # 1.8 is known good version. - # Per https://docs.scipy.org/doc/scipy/dev/core-dev/index.html#version-numbering - # and https://docs.scipy.org/doc/scipy/dev/core-dev/index.html#deprecations, - # deprecations cannot be introduced in micro releases. - # SciPy devs wait "at least 6 months", "in practice two (minor) releases" - # from deprecation to removal of a feature. - 'scipy >=1.5', + 'networkx >=3.1', + 'scipy >=1.11', 'sympy >=1.6, <2.0', - # Issue #33642: Set lower bound for use of matplotlib color maps introduced in #33491, - # and to suppress deprecation warnings (https://github.com/matplotlib/matplotlib/pull/21073) - 'matplotlib >=3.5.1', + 'matplotlib >=3.7.0', 'pillow >=7.2.0', 'mpmath >=1.1.0', 'ipykernel >=5.2.1', @@ -54,6 +48,8 @@ dependencies = [ 'ipywidgets >=7.5.1', 'fpylll >=0.5.9', 'ptyprocess > 0.5', + # TODO: Remove this once the migration to meson is complete + 'pkgconfig' ] dynamic = ["version"] license = {text = "GNU General Public License (GPL) v2 or later"} @@ -70,11 +66,12 @@ classifiers = [ "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Scientific/Engineering :: Mathematics", ] urls = {Homepage = "https://www.sagemath.org"} -requires-python = ">=3.9, <3.13" +requires-python = ">=3.9, <3.14" [project.optional-dependencies] R = [ @@ -90,8 +87,17 @@ platforms = [ 'osx-64', 'linux-64', 'linux-aarch64', 'osx-arm64' ] -[external] +[tool.pytest.ini_options] +python_files = "*_test.py" +norecursedirs = "local prefix venv build builddir pkgs .git src/doc src/bin src/sage_setup/autogen/flint tools" +# The "no:warnings" is to stop pytest from capturing warnings so that they are printed to the output of the doctest +addopts = "--import-mode importlib -p no:warnings" +doctest_optionflags = "NORMALIZE_WHITESPACE ELLIPSIS" +# https://docs.pytest.org/en/stable/reference/reference.html#confval-consider_namespace_packages +consider_namespace_packages = true + # External dependencies in the format proposed by https://peps.python.org/pep-0725 +[external] build-requires = [ "virtual:compiler/c", "virtual:compiler/cpp", @@ -100,6 +106,7 @@ build-requires = [ host-requires = [ "virtual:interface/blas", + "virtual:compiler/fortran", "pkg:generic/boost", "pkg:generic/brial", "pkg:generic/cddlib", @@ -152,4 +159,23 @@ dependencies = [ "pkg:generic/tachyon", "pkg:generic/sagemath-polytopes-db", "pkg:generic/sagemath-elliptic-curves", + "pkg:generic/sagemath-graphs", +] + +[dependency-groups] +test = [ + "pytest", + "pytest-xdist", + "coverage", +] +docs = [ + "sphinx", + "sphinx-inline-tabs", + "furo", +] +lint = [ + "relint", + "ruff", + "pycodestyle", + "flake8-rst-docstrings", ] diff --git a/ruff.toml b/ruff.toml index b3070914153..15def717a4e 100644 --- a/ruff.toml +++ b/ruff.toml @@ -12,3 +12,8 @@ lint.select = [ lint.ignore = [ "E501", # Line too long - hard to avoid in doctests, and better handled by black. ] + +[lint.per-file-ignores] +"all.py" = [ + "F401", # Unused import - these files are by definition collections of imports. +] diff --git a/src/Pipfile.m4 b/src/Pipfile.m4 deleted file mode 100644 index feca57f7de9..00000000000 --- a/src/Pipfile.m4 +++ /dev/null @@ -1,22 +0,0 @@ -## Pipfile with all dependencies of sagelib and version information as free as possible -## (for developers to generate a dev environment) -[[source]] -name = "pypi" -url = "https://pypi.org/simple" -verify_ssl = true - -[dev-packages] -## We do not list packages that are already declared as install_requires -## in setup.cfg -pycodestyle = "*" -tox = "*" -pytest = "*" -rope = "*" -six = "*" - -[packages] -## We do not list packages that are already declared as install_requires -## in setup.cfg - -[packages.e1839a8] -path = "." diff --git a/src/VERSION.txt b/src/VERSION.txt index 861a196a402..8595985e4bf 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.5.rc2 +10.6.beta4 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 0386f6ef5aa..ddaee05e046 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='10.5.rc2' -SAGE_RELEASE_DATE='2024-11-30' -SAGE_VERSION_BANNER='SageMath version 10.5.rc2, Release Date: 2024-11-30' +SAGE_VERSION='10.6.beta4' +SAGE_RELEASE_DATE='2025-01-18' +SAGE_VERSION_BANNER='SageMath version 10.6.beta4, Release Date: 2025-01-18' diff --git a/src/conftest.py b/src/conftest.py deleted file mode 100644 index 6bc7ee2e3fd..00000000000 --- a/src/conftest.py +++ /dev/null @@ -1,183 +0,0 @@ -# pyright: strict -"""Configuration and fixtures for pytest. - -This file configures pytest and provides some global fixtures. -See https://docs.pytest.org/en/latest/index.html for more details. -""" - -from __future__ import annotations - -import inspect -from pathlib import Path -from typing import Any, Iterable - -import pytest -from _pytest.doctest import ( - DoctestItem, - DoctestModule, - _get_continue_on_failure, - _get_runner, - _is_mocked, - _patch_unwrap_mock_aware, - get_optionflags, -) -from _pytest.pathlib import ImportMode, import_path -from sage.doctest.parsing import SageDocTestParser, SageOutputChecker - - -class SageDoctestModule(DoctestModule): - """ - This is essentially a copy of `DoctestModule` from - https://github.com/pytest-dev/pytest/blob/main/src/_pytest/doctest.py. - The only change is that we use `SageDocTestParser` to extract the doctests - and `SageOutputChecker` to verify the output. - """ - - def collect(self) -> Iterable[DoctestItem]: - import doctest - - class MockAwareDocTestFinder(doctest.DocTestFinder): - """A hackish doctest finder that overrides stdlib internals to fix a stdlib bug. - https://github.com/pytest-dev/pytest/issues/3456 - https://bugs.python.org/issue25532 - """ - - def __init__(self) -> None: - super().__init__(parser=SageDocTestParser(set(["sage"]))) - - def _find_lineno(self, obj, source_lines): - """Doctest code does not take into account `@property`, this - is a hackish way to fix it. https://bugs.python.org/issue17446 - Wrapped Doctests will need to be unwrapped so the correct - line number is returned. This will be reported upstream. #8796 - """ - if isinstance(obj, property): - obj = getattr(obj, "fget", obj) - - if hasattr(obj, "__wrapped__"): - # Get the main obj in case of it being wrapped - obj = inspect.unwrap(obj) - - # Type ignored because this is a private function. - return super()._find_lineno( # type:ignore[misc] - obj, - source_lines, - ) - - def _find( - self, tests, obj, name, module, source_lines, globs, seen - ) -> None: - if _is_mocked(obj): - return - with _patch_unwrap_mock_aware(): - - # Type ignored because this is a private function. - super()._find( # type:ignore[misc] - tests, obj, name, module, source_lines, globs, seen - ) - - if self.path.name == "conftest.py": - module = self.config.pluginmanager._importconftest( - self.path, - self.config.getoption("importmode"), - rootpath=self.config.rootpath, - ) - else: - try: - module = import_path( - self.path, - mode=ImportMode.importlib, - root=self.config.rootpath, - consider_namespace_packages=True, - ) - except ImportError: - if self.config.getvalue("doctest_ignore_import_errors"): - pytest.skip("unable to import module %r" % self.path) - else: - raise - # Uses internal doctest module parsing mechanism. - finder = MockAwareDocTestFinder() - optionflags = get_optionflags(self.config) - runner = _get_runner( - verbose=False, - optionflags=optionflags, - checker=SageOutputChecker(), - continue_on_failure=_get_continue_on_failure(self.config), - ) - - for test in finder.find(module, module.__name__): - if test.examples: # skip empty doctests - yield DoctestItem.from_parent( - self, name=test.name, runner=runner, dtest=test - ) - - -class IgnoreCollector(pytest.Collector): - """ - Ignore a file. - """ - def __init__(self, parent: pytest.Collector) -> None: - super().__init__('ignore', parent) - - def collect(self) -> Iterable[pytest.Item | pytest.Collector]: - return [] - - -def pytest_collect_file( - file_path: Path, parent: pytest.Collector -) -> pytest.Collector | None: - """ - This hook is called when collecting test files, and can be used to - modify the file or test selection logic by returning a list of - ``pytest.Item`` objects which the ``pytest`` command will directly - add to the list of test items. - - See `pytest documentation `_. - """ - if file_path.suffix == ".pyx": - # We don't allow pytests to be defined in Cython files. - # Normally, Cython files are filtered out already by pytest and we only - # hit this here if someone explicitly runs `pytest some_file.pyx`. - return IgnoreCollector.from_parent(parent) - elif file_path.suffix == ".py": - if parent.config.option.doctest: - if file_path.name == "__main__.py": - # We don't allow tests to be defined in __main__.py files (because their import will fail). - return IgnoreCollector.from_parent(parent) - if file_path.name == "postprocess.py" and file_path.parent.name == "nbconvert": - # This is an executable file. - return IgnoreCollector.from_parent(parent) - return SageDoctestModule.from_parent(parent, path=file_path) - - -def pytest_addoption(parser): - # Add a command line option to run doctests - # (we don't use the built-in --doctest-modules option because then doctests are collected twice) - group = parser.getgroup("collect") - group.addoption( - "--doctest", - action="store_true", - default=False, - help="Run doctests in all .py modules", - dest="doctest", - ) - -@pytest.fixture(autouse=True, scope="session") -def add_imports(doctest_namespace: dict[str, Any]): - """ - Add global imports for doctests. - - See `pytest documentation `. - """ - # Inject sage.all into each doctest - import sage.all - dict_all = sage.all.__dict__ - - # Remove '__package__' item from the globals since it is not - # always in the globals in an actual Sage session. - dict_all.pop("__package__", None) - - sage_namespace = dict(dict_all) - sage_namespace["__name__"] = "__main__" - - doctest_namespace.update(**sage_namespace) diff --git a/src/doc/Makefile b/src/doc/Makefile index 98a3d138baf..9c03292b070 100644 --- a/src/doc/Makefile +++ b/src/doc/Makefile @@ -66,6 +66,8 @@ doc-html-other: doc-html-reference $(MAKE) $(foreach doc, $(wordlist 2, 100, $(DOCS)), doc-html--$(subst /,-,$(doc))) doc-html: doc-html-reference doc-html-other + SAGE_DOC=$$(sage --python -c "from sage.env import SAGE_DOC; print(SAGE_DOC)") + find $${SAGE_DOC}/html -type d -path "*/jupyter_execute" -exec rm -rf {} + # Matches doc-pdf--developer, doc-pdf--reference-manifolds etc. doc-pdf--%: @@ -88,7 +90,8 @@ doc-pdf-other: doc-pdf-reference $(MAKE) SAGE_DOCBUILD_OPTS="$(SAGE_DOCBUILD_OPTS) --no-prune-empty-dirs" $(foreach doc, $(wordlist 2, 100, $(DOCS)), doc-pdf--$(subst /,-,$(doc))) doc-pdf: doc-pdf-reference doc-pdf-other - + SAGE_DOC=$$(sage --python -c "from sage.env import SAGE_DOC; print(SAGE_DOC)") + find $${SAGE_DOC}/latex -type d -path "*/jupyter_execute" -exec rm -rf {} + .PHONY: all clean \ doc-src \ diff --git a/src/doc/de/tutorial/programming.rst b/src/doc/de/tutorial/programming.rst index ceeed63c84c..02b2d132351 100644 --- a/src/doc/de/tutorial/programming.rst +++ b/src/doc/de/tutorial/programming.rst @@ -263,15 +263,9 @@ aussehen könnten. Hier sind einige Beispiele: sqrt(2) sage: V = VectorSpace(QQ,2) sage: V.basis() - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: basis(V) - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: M = MatrixSpace(GF(7), 2); M Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 sage: A = M([1,2,3,4]); A @@ -425,11 +419,7 @@ Vektorräumen. Es ist wichtig, dass sie nicht verändert werden können. :: sage: V = QQ^3; B = V.basis(); B - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: type(B) sage: B[0] = B[1] diff --git a/src/doc/de/tutorial/tour_advanced.rst b/src/doc/de/tutorial/tour_advanced.rst index 7ee92b357df..56523ae5650 100644 --- a/src/doc/de/tutorial/tour_advanced.rst +++ b/src/doc/de/tutorial/tour_advanced.rst @@ -20,12 +20,10 @@ die Kurven als irreduzible Komponenten der Vereinigung zurück erhalten. Affine Plane Curve over Rational Field defined by x^5 + x^3*y^2 + x^2*y^3 + y^5 - x^3 - y^3 - x^2 - y^2 + 1 sage: D.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 + y^2 - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^3 + y^3 - 1 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^2 + y^2 - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^3 + y^3 - 1] Wir können auch alle Punkte im Schnitt der beiden Kurven finden, indem wir diese schneiden und dann die irreduziblen Komponenten berechnen. @@ -36,17 +34,15 @@ wir diese schneiden und dann die irreduziblen Komponenten berechnen. sage: V = C2.intersection(C3) sage: V.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y, - x - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y - 1, - x, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x + y + 2, - 2*y^2 + 4*y + 3 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y, + x - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y - 1, + x, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x + y + 2, + 2*y^2 + 4*y + 3] Also sind zum Beispiel :math:`(1,0)` und :math:`(0,1)` auf beiden Kurven (wie man sofort sieht), genauso wie bestimmte (quadratischen) @@ -333,10 +329,8 @@ Faktorisierung des Moduls entsprechen. [1, 2, 2, 1, 1, 2, 2, 1] sage: G.decomposition() - [ - Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, - Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2 - ] + [Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, + Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2] Als nächstes konstruieren wir die Gruppe der Dirichlet-Charaktere mod 20, jedoch mit Werten in :math:`\QQ(i)`: @@ -465,9 +459,7 @@ Nun berechnen wir ein paar charakteristische Polynome und [-2 0] [ 0 -2] sage: S.q_expansion_basis(10) - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10)] Wir können sogar Räume von Modulsymbolen mit Charakteren berechnen. @@ -487,10 +479,7 @@ Wir können sogar Räume von Modulsymbolen mit Charakteren berechnen. sage: S.T(2).charpoly('x').factor() (x + zeta6 + 1)^2 sage: S.q_expansion_basis(10) - [ - q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 - + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10) - ] + [q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10)] Hier ist ein weiteres Beispiel davon wie Sage mit den Operationen von Hecke-Operatoren auf dem Raum von Modulformen rechnen kann. diff --git a/src/doc/de/tutorial/tour_linalg.rst b/src/doc/de/tutorial/tour_linalg.rst index 1be6540c89e..f037f086175 100644 --- a/src/doc/de/tutorial/tour_linalg.rst +++ b/src/doc/de/tutorial/tour_linalg.rst @@ -63,11 +63,7 @@ Sage kann auch Eigenwerte und Eigenvektoren berechnen:: [-2*I, 2*I] sage: B = matrix([[1, 3], [3, 1]]) sage: B.eigenvectors_left() - [(4, [ - (1, 1) - ], 1), (-2, [ - (1, -1) - ], 1)] + [(4, [(1, 1)], 1), (-2, [(1, -1)], 1)] (Die Syntax der Ausgabe von ``eigenvectors_left`` ist eine Liste von Tripeln: (Eigenwert, Eigenvektor, Vielfachheit).) Eigenwerte und @@ -245,4 +241,4 @@ Beachten Sie, dass Python zwischen Klein- und Großschreibung unterscheidet: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: ...__init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse'... diff --git a/src/doc/en/constructions/linear_algebra.rst b/src/doc/en/constructions/linear_algebra.rst index b25cdf94634..4327dedb0c1 100644 --- a/src/doc/en/constructions/linear_algebra.rst +++ b/src/doc/en/constructions/linear_algebra.rst @@ -22,10 +22,7 @@ one can create a subspace. Note the basis computed by Sage is sage: V = VectorSpace(GF(2),8) sage: S = V.subspace([V([1,1,0,0,0,0,0,0]),V([1,0,0,0,0,1,1,0])]) sage: S.basis() - [ - (1, 0, 0, 0, 0, 1, 1, 0), - (0, 1, 0, 0, 0, 1, 1, 0) - ] + [(1, 0, 0, 0, 0, 1, 1, 0), (0, 1, 0, 0, 0, 1, 1, 0)] sage: S.dimension() 2 @@ -205,26 +202,21 @@ gives matrices :math:`D` and :math:`P` such that :math:`AP=PD` (resp. sage: A.eigenvalues() [3, 2, 1] sage: A.eigenvectors_right() - [(3, [ - (0, 0, 1) - ], 1), (2, [ - (1, 1, 0) - ], 1), (1, [ - (1, 0, 0) - ], 1)] + [(3, [(0, 0, 1)], 1), (2, [(1, 1, 0)], 1), (1, [(1, 0, 0)], 1)] sage: A.eigenspaces_right() - [ - (3, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [0 0 1]), - (2, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [1 1 0]), - (1, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [1 0 0]) - ] + [(3, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [0 0 1]), + (2, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [1 1 0]), + (1, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [1 0 0])] sage: D, P = A.eigenmatrix_right() sage: D @@ -256,20 +248,19 @@ floating point entries (over ``CDF`` and ``RDF``) can be obtained with the sage: MS = MatrixSpace(QQ, 2, 2) sage: A = MS([1,-4,1, -1]) sage: A.eigenspaces_left(format='all') - [ - (-1.732050807568878?*I, Vector space of degree 2 and dimension 1 over Algebraic Field - User basis matrix: - [ 1 -1 - 1.732050807568878?*I]), - (1.732050807568878?*I, Vector space of degree 2 and dimension 1 over Algebraic Field - User basis matrix: - [ 1 -1 + 1.732050807568878?*I]) - ] + [(-1.732050807568878?*I, + Vector space of degree 2 and dimension 1 over Algebraic Field + User basis matrix: + [ 1 -1 - 1.732050807568878?*I]), + (1.732050807568878?*I, + Vector space of degree 2 and dimension 1 over Algebraic Field + User basis matrix: + [ 1 -1 + 1.732050807568878?*I])] sage: A.eigenspaces_left(format='galois') - [ - (a0, Vector space of degree 2 and dimension 1 over Number Field in a0 with defining polynomial x^2 + 3 - User basis matrix: - [ 1 a0 - 1]) - ] + [(a0, + Vector space of degree 2 and dimension 1 over Number Field in a0 with defining polynomial x^2 + 3 + User basis matrix: + [ 1 a0 - 1])] Another approach is to use the interface with Maxima: diff --git a/src/doc/en/developer/coding_basics.rst b/src/doc/en/developer/coding_basics.rst index 9b56de46ad0..02936d3e423 100644 --- a/src/doc/en/developer/coding_basics.rst +++ b/src/doc/en/developer/coding_basics.rst @@ -82,6 +82,19 @@ In particular, def SomeIdentityValue(x): return SomeValue(1) +.. _section-python-version: + +Python Version +================= + +In order to reduce the technical debt of maintaining the project, Sage follows +the time window-based support policy +`SPEC 0 — Minimum Supported Dependencies `_ +for Python versions. Accordingly, support for Python versions will be dropped +3 years after their initial release. +For the drop schedule of Python versions, see the +`SPEC 0 `_ +document. .. _chapter-directory-structure: diff --git a/src/doc/en/developer/coding_in_cython.rst b/src/doc/en/developer/coding_in_cython.rst index d0c7b0d521f..a912a75c544 100644 --- a/src/doc/en/developer/coding_in_cython.rst +++ b/src/doc/en/developer/coding_in_cython.rst @@ -32,13 +32,13 @@ up-to-date information or check out the to get started immediately. -Writing cython code in Sage +Writing Cython code in Sage =========================== There are several ways to create and build Cython code in Sage. -#. In the Sage Notebook, begin any cell with ``%cython``. When you - evaluate that cell, +#. In the Sage notebook or the Sage command line, begin any cell with + a line containing ``%%cython``. When you evaluate that cell, #. It is saved to a file. @@ -53,22 +53,21 @@ There are several ways to create and build Cython code in Sage. program that was compiled to create the ``.so`` file. #. A ``cpdef`` or ``def`` function, say ``testfunction``, defined in - a ``%cython`` cell in a worksheet can be imported and made available - in a different ``%cython`` cell within the same worksheet by + a ``%%cython`` cell in a worksheet can be imported and made available + in a different ``%%cython`` cell within the same worksheet by importing it as shown below:: - %cython + %%cython from __main__ import testfunction -#. Create an ``.spyx`` file and attach or load it from the command - line. This is similar to creating a ``%cython`` cell in the - notebook but works completely from the command line (and not from - the notebook). + Refer to :meth:`sage.repl.ipython_extension.SageMagics.cython`. + +#. Create an ``.spyx`` file and attach or load it + from the command line. #. Create a ``.pyx`` file and add it to the Sage library. Then run ``sage -b`` to rebuild Sage. - Attaching or loading .spyx files ================================ diff --git a/src/doc/en/developer/coding_in_python.rst b/src/doc/en/developer/coding_in_python.rst index bb08408777b..1ea6eebb317 100644 --- a/src/doc/en/developer/coding_in_python.rst +++ b/src/doc/en/developer/coding_in_python.rst @@ -786,13 +786,13 @@ the procedure below: class NewClass: ... - OldClass = NewClass # OldClass is deprecated. See Issue 12345. + OldClass = NewClass # OldClass is deprecated. See Issue #12345. * **Removing a class:** add a comment: .. CODE-BLOCK:: python - # OldClass is deprecated. See Issue 12345. + # OldClass is deprecated. See Issue #12345. class OldClass: diff --git a/src/doc/en/developer/packaging.rst b/src/doc/en/developer/packaging.rst index 2b6903ca466..cfa6fec89d3 100644 --- a/src/doc/en/developer/packaging.rst +++ b/src/doc/en/developer/packaging.rst @@ -497,10 +497,9 @@ should not need to add it yourself. The following are also available, but rarely used. -- ``sdh_cmake [...]``: Runs ``cmake`` in the current directory with - the given arguments, as well as additional arguments passed to - cmake (assuming packages are using the GNUInstallDirs module) so - that ``CMAKE_INSTALL_PREFIX`` and ``CMAKE_INSTALL_LIBDIR`` are set +- ``sdh_cmake [...]``: Runs ``cmake`` with the given arguments, as well as + additional arguments (assuming packages are using the GNUInstallDirs module) + so that ``CMAKE_INSTALL_PREFIX`` and ``CMAKE_INSTALL_LIBDIR`` are set correctly. - ``sdh_preload_lib EXECUTABLE SONAME``: (Linux only -- no-op on other diff --git a/src/doc/en/installation/conda.rst b/src/doc/en/installation/conda.rst index e3cbf6b342c..ae560bb5a38 100644 --- a/src/doc/en/installation/conda.rst +++ b/src/doc/en/installation/conda.rst @@ -86,14 +86,14 @@ Here we assume that you are using a git checkout. .. code-block:: shell - $ mamba env create --file environment-dev-3.11-linux.yml --name sage-dev + $ mamba env create --file environment-3.11-linux.yml --name sage-dev $ conda activate sage-dev .. tab:: conda .. code-block:: shell - $ conda env create --file environment-dev-3.11-linux.yml --name sage-dev + $ conda env create --file environment-3.11-linux.yml --name sage-dev $ conda activate sage-dev Alternatively, you can use ``environment-3.11-linux.yml`` or @@ -137,7 +137,7 @@ After editing any Cython files, rebuild the Sage library using:: In order to update the conda environment later, you can run:: - $ mamba env update --file environment-dev-3.11-linux.yml --name sage-dev + $ mamba env update --file environment-3.11-linux.yml --name sage-dev To build the documentation, use:: @@ -156,5 +156,5 @@ To build the documentation, use:: You can update the conda lock files by running ``.github/workflows/conda-lock-update.py`` or by running - ``conda-lock --platform linux-64 --filename environment-dev-3.11-linux.yml --lockfile environment-dev-3.11-linux.lock`` + ``conda-lock --platform linux-64 --filename environment-3.11-linux.yml --lockfile environment-3.11-linux.lock`` manually. diff --git a/src/doc/en/installation/meson.rst b/src/doc/en/installation/meson.rst index b8e44bc12fc..e0051dbbf68 100644 --- a/src/doc/en/installation/meson.rst +++ b/src/doc/en/installation/meson.rst @@ -9,12 +9,12 @@ This is a short guide on how to build the Sage from source using Meson. Walkthrough =========== -Assume we're starting from a clean repo and a fully set up conda environment: +Assume we're starting from a clean repo and a fully set up conda environment +(modify ``-linux`` according to your operating system): .. CODE-BLOCK:: shell-session - $ ./bootstrap-conda - $ mamba env create --file src/environment-dev-3.11.yml --name sage-dev + $ mamba env create --file environment-3.11-linux.yml --name sage-dev $ conda activate sage-dev Alternatively, install all build requirements as described in section @@ -56,8 +56,9 @@ or run the tests with ``./sage -t``. By using ``pip install --editable`` in the above steps, the Sage library is installed in editable mode. This means that when you only edit source files, there is no need to rebuild the library; it suffices to restart Sage. - Note that this even works when you edit Cython files, so you no longer need - to manually compile after editing Cython files. + Note that this even works when you edit Cython files (they will be recompiled + automatically), so you no longer need to manually compile after editing Cython + files. .. NOTE:: @@ -65,6 +66,15 @@ or run the tests with ``./sage -t``. This means that any Sage-the-distribution commands such as ``sage -i`` will not work. +.. NOTE:: + + By default, Meson will automatically determine the number of jobs to + run in parallel based on the number of CPU available. This can be adjusted + by passing ``--config-settings=compile-args=-jN`` to ``pip install``. + + ``--verbose`` can be passed to ``pip install``, then the meson commands + internally used by pip will be printed out. + Background information ====================== @@ -79,6 +89,12 @@ To configure the project, we need to run the following command: This will create a build directory ``builddir`` that will hold the build artifacts. The ``--prefix`` option specifies the directory where the Sage will be installed. + +If pip is used as above, ``builddir`` is set to be +``build/cp[Python major version][Python minor version]``, such as ``build/cp311``. +``--prefix=`` can be left unspecified, when conda is used then meson will +install to the conda environment e.g. ``$HOME/miniforge3/envs/sage-dev/``. + To compile the project, run the following command: .. CODE-BLOCK:: shell-session @@ -99,6 +115,8 @@ Usually, this directory is not on your Python path, so you have to use: $ PYTHONPATH=build-install/lib/python3.11/site-packages ./sage +When editable install is used, it is not necessary to reinstall after each compilation. + Alternatively, we can still use pip to install: .. CODE-BLOCK:: shell-session @@ -120,3 +138,17 @@ Alternatively, we can still use pip to install: See `Meson's quick guide `_ and `Meson's install guide `_ for more information. + +Miscellaneous tips +================== + +The environment variable ``MESONPY_EDITABLE_VERBOSE=1`` can be set while running ``./sage``, +so that when Cython files are recompiled a message is printed out. + +If a new ``.pyx`` file is added, it need to be added to ``meson.build`` file in the +containing directory. + +Unlike the ``make``-based build system which relies on header comments ``# distutils: language = c++`` +to determine whether C++ should be used, Meson-based build system requires specifying +``override_options: ['cython_language=cpp']`` in the ``meson.build`` file. +Similarly, dependencies need to be specified by ``dependencies: [...]``. diff --git a/src/doc/en/prep/Quickstarts/Graphs-and-Discrete.rst b/src/doc/en/prep/Quickstarts/Graphs-and-Discrete.rst index 771198b48d2..9917bd45e57 100644 --- a/src/doc/en/prep/Quickstarts/Graphs-and-Discrete.rst +++ b/src/doc/en/prep/Quickstarts/Graphs-and-Discrete.rst @@ -325,11 +325,7 @@ Start with a generator matrix over :math:`\ZZ/2\ZZ`. :: sage: D.basis() - [ - (1, 0, 1, 0, 1, 0, 1), - (0, 1, 1, 0, 0, 1, 1), - (0, 0, 0, 1, 1, 1, 1) - ] + [(1, 0, 1, 0, 1, 0, 1), (0, 1, 1, 0, 0, 1, 1), (0, 0, 0, 1, 1, 1, 1)] :: diff --git a/src/doc/en/prep/Quickstarts/Linear-Algebra.rst b/src/doc/en/prep/Quickstarts/Linear-Algebra.rst index 58cb44edd3c..93deaa9842a 100644 --- a/src/doc/en/prep/Quickstarts/Linear-Algebra.rst +++ b/src/doc/en/prep/Quickstarts/Linear-Algebra.rst @@ -256,10 +256,7 @@ of the matrix):: Or we can get the basis vectors explicitly as a list of vectors:: sage: V.basis() - [ - (1, 0, -1/3), - (0, 1, -2/3) - ] + [(1, 0, -1/3), (0, 1, -2/3)] .. note:: Kernels are **vector spaces** and bases are "\ **echelonized**\ " diff --git a/src/doc/en/reference/categories/index.rst b/src/doc/en/reference/categories/index.rst index a40cca76e0f..55ee54888b3 100644 --- a/src/doc/en/reference/categories/index.rst +++ b/src/doc/en/reference/categories/index.rst @@ -137,6 +137,7 @@ Individual Categories sage/categories/integral_domains sage/categories/j_trivial_semigroups sage/categories/kac_moody_algebras + sage/categories/kahler_algebras sage/categories/lambda_bracket_algebras sage/categories/lambda_bracket_algebras_with_basis sage/categories/lattice_posets @@ -268,6 +269,7 @@ Examples of parents using categories sage/categories/examples/posets sage/categories/examples/semigroups sage/categories/examples/semigroups_cython + sage/categories/examples/semirings sage/categories/examples/sets_cat sage/categories/examples/sets_with_grading sage/categories/examples/with_realizations diff --git a/src/doc/en/reference/data_structures/index.rst b/src/doc/en/reference/data_structures/index.rst index 08c03313ad3..1832d01eb75 100644 --- a/src/doc/en/reference/data_structures/index.rst +++ b/src/doc/en/reference/data_structures/index.rst @@ -9,5 +9,6 @@ Data Structures sage/data_structures/bounded_integer_sequences sage/data_structures/stream sage/data_structures/mutable_poset + sage/data_structures/pairing_heap .. include:: ../footer.txt diff --git a/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst b/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst index 97cff1bb835..021a50f262e 100644 --- a/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst +++ b/src/doc/en/reference/polynomial_rings/polynomial_rings_univar.rst @@ -45,3 +45,4 @@ whereas others have multiple bases. sage/rings/polynomial/polynomial_fateman sage/rings/polynomial/integer_valued_polynomials + sage/rings/polynomial/q_integer_valued_polynomials diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 45f5fbc090f..ca81cda3f75 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -44,8 +44,8 @@ REFERENCES: 1995 .. [Ab2022] Willie Aboumrad, - *Quantum compution with anyons: an F-matrix and braid calculator* - (2022). https://arxiv.org/abs/2212.00831 + *Quantum computing with anyons: an F-matrix and braid calculator* + (2022). :arxiv:`2212.00831` .. [Alekseyev2006] \M. Alekseyev: (Forum post on counting irreducible multivariate polynomials), @@ -76,7 +76,7 @@ REFERENCES: "Lilliput-AE: a New Lightweight Tweakable BlockCipher for Authenticated Encryption with AssociatedData" https://csrc.nist.gov/CSRC/media/Projects/Lightweight-Cryptography/documents/round-1/spec-doc/LILLIPUT-AE-spec.pdf -.. [ABCMT2019] \V. Arul, A. J. Best, E. Costa, R. Magner, and N. Triantafillou, *Computing zeta functions of cyclic covers in large characteristic,* The Open Book Series, vol. 2, no. 1, pp. 37–53, Jan. 2019. +.. [ABCMT2019] \V. Arul, A. J. Best, E. Costa, R. Magner, and N. Triantafillou, *Computing zeta functions of cyclic covers in large characteristic*, The Open Book Series, vol. 2, no. 1, pp. 37–53, Jan. 2019. .. [ABZ2007] \R. Aharoni and E. Berger and R. Ziv. *Independent systems of representatives in weighted graphs*. @@ -242,8 +242,8 @@ REFERENCES: .. [AM1990] \R. Abraham and J. E. Marsden, "Foundations of Mechanics", Addison-Wesley, 1980. -.. [AM1974] \J. F. Adams and H. R. Margolis, "Sub-Hopf-algebras of the - Steenrod algebra," Proc. Cambridge Philos. Soc. 76 (1974), +.. [AM1974] \J. F. Adams and H. R. Margolis, *Sub-Hopf-algebras of the + Steenrod algebra*, Proc. Cambridge Philos. Soc. 76 (1974), 45-52. .. [AM2000] \S. Ariki and A. Mathas. @@ -277,6 +277,10 @@ REFERENCES: .. [Ap1997] \T. Apostol, Modular functions and Dirichlet series in number theory, Springer, 1997 (2nd ed), section 3.7--3.9. +.. [AP2024] William Atherton, Dmitrii V. Pasechnik, *Decline and Fall of the + ICALP 2008 Modular Decomposition algorithm*, 2024. + :arxiv:`2404.14049`. + .. [APR2001] George E. Andrews, Peter Paule, Axel Riese, *MacMahon's partition analysis: the Omega package*, European J. Combin. 22 (2001), no. 7, 887--904. @@ -440,16 +444,16 @@ REFERENCES: Proc. Calgary Internat. Conference 1969, New York, 1970, Gordon and Breach. -.. [Bar2006] \G. Bard. 'Accelerating Cryptanalysis with the Method of - Four Russians'. Cryptography E-Print Archive +.. [Bar2006] \G. Bard. *Accelerating Cryptanalysis with the Method of + Four Russians*. Cryptography E-Print Archive (http://eprint.iacr.org/2006/251.pdf), 2006. .. [Bat1991] \V. V. Batyrev, *On the classification of smooth projective toric varieties*, Tohoku Math. J. **43** (1991), 569-585 .. [Bat1994] Victor V. Batyrev, - "Dual polyhedra and mirror symmetry for Calabi-Yau - hypersurfaces in toric varieties", + *Dual polyhedra and mirror symmetry for Calabi-Yau + hypersurfaces in toric varieties*, J. Algebraic Geom. 3 (1994), no. 3, 493-535. :arxiv:`alg-geom/9310003v1` @@ -496,6 +500,9 @@ REFERENCES: .. [BeBo2009] Olivier Bernardi and Nicolas Bonichon, *Intervals in Catalan lattices and realizers of triangulations*, JCTA 116 (2009) +.. [Best2021] Alex J. Best: Tools and Techniques for Rational Points on Curves. + PhD Thesis, Boston University, 2021. + .. [BBGL2008] \A. Blondin Massé, S. Brlek, A. Garon, and S. Labbé, Combinatorial properties of f -palindromes in the Thue-Morse sequence. Pure Math. Appl., @@ -533,14 +540,14 @@ REFERENCES: .. [Bodin2007] \A. Bodin: Number of irreducible polynomials in several variables over finite fields, The American Mathematical Monthly 115(7), pp. 653-660, 2008. - https://arxiv.org/abs/0706.0157 + :arxiv:`0706.0157` .. [BH2012] \A. Brouwer and W. Haemers, Spectra of graphs, Springer, 2012, http://homepages.cwi.nl/~aeb/math/ipm/ipm.pdf -.. [BMFPR2011] \M. Bousquet-Melou, É. Fusy, L.-F. Préville-Ratelle, +.. [BMFPR2011] \M. Bousquet-Mélou, É. Fusy, L.-F. Préville-Ratelle, *The number of intervals in the m-Tamari lattices*. Electronic Journal of Combinatorics 18(2), 2011. :doi:`10.37236/2027` @@ -706,8 +713,8 @@ REFERENCES: Journal of Algebraic Combinatorics (1992), vol.1, n.4, pp329-346, :doi:`10.1023/A%3A1022438616684`. -.. [Bec1992] Bernhard Beckermann. "A reliable method for computing M-Padé - approximants on arbitrary staircases". J. Comput. Appl. Math., +.. [Bec1992] Bernhard Beckermann. *A reliable method for computing M-Padé + approximants on arbitrary staircases*. J. Comput. Appl. Math., 40(1):19-42, 1992. :doi:`10.1016/0377-0427(92)90039-Z`. .. [BeCoMe] Frits Beukers, Henri Cohen, Anton Mellit, @@ -793,15 +800,16 @@ REFERENCES: .. [BF2005] \R.L. Burden and J.D. Faires. *Numerical Analysis*. 8th edition, Thomson Brooks/Cole, 2005. -.. [BFS2004] Magali Bardet, Jean-Charles Faugère, and Bruno Salvy, On +.. [BFS2004] Magali Bardet, Jean-Charles Faugère, and Bruno Salvy, *On the complexity of Groebner basis computation of - semi-regular overdetermined algebraic equations. + semi-regular overdetermined algebraic equations.* Proc. International Conference on Polynomial System Solving (ICPSS), pp. 71-75, 2004. .. [BFSS2006] \A. Bostan, P. Flajolet, B. Salvy and E. Schost, *Fast Computation of special resultants*, Journal of Symbolic Computation 41 (2006), 1-29 + :doi:`10.1016/j.jsc.2005.07.001` .. [BFZ2005] \A. Berenstein, \S. Fomin, and \A. Zelevinsky, *Cluster algebras. III. Upper bounds and double Bruhat cells*, @@ -970,6 +978,10 @@ REFERENCES: Anal. Appl. 15 (1994) 804-823. :doi:`10.1137/S0895479892230031` +.. [BL1995] W. Bosma, H.W. Lenstra: Complete Systems of Two Addition Laws for + Elliptic Curves. Journal of Number Theory, volume 53, issue 2, + pages 229-240. 1995. + .. [BHMPW20a] Tom Braden, June Huh, Jacob P. Matherne, Nicholas Proudfoot, and Botong Wang, *A semi-small decomposition of the Chow ring of a matroid*, :arxiv:`2002.03341` (2020). @@ -1104,18 +1116,18 @@ REFERENCES: lacunas of the Thue-Morse word*, Proc. GASCOM 2008 (June 16-20 2008, Bibbiena, Arezzo-Italia), 53--67. -.. [BMFPR] \M. Bousquet-Melou, E. Fusy, L.-F. Preville Ratelle. +.. [BMFPR] \M. Bousquet-Mélou, E. Fusy, L.-F. Preville Ratelle. *The number of intervals in the m-Tamari lattices*. :arxiv:`1106.1498` -.. [BMS2006] Bugeaud, Mignotte, and Siksek. "Classical and modular +.. [BMS2006] Bugeaud, Mignotte, and Siksek. *Classical and modular approaches to exponential Diophantine - equations: I. Fibonacci and Lucas perfect powers." Annals + equations: I. Fibonacci and Lucas perfect powers.* Annals of Math, 2006. .. [BMSS2006] Alin Bostan, Bruno Salvy, François Morain, Éric Schost. - Fast algorithms for computing isogenies between elliptic - curves. [Research Report] 2006, pp.28. - https://arxiv.org/pdf/cs/0609020.pdf + *Fast algorithms for computing isogenies between elliptic + curves*. [Research Report] 2006, pp.28. + :arxiv:`cs/0609020` .. [BN2010] \D. Bump and M. Nakasuji. Integration on `p`-adic groups and crystal bases. @@ -1584,12 +1596,13 @@ REFERENCES: IV. The quotient groups of the lower central series, Ann. of Math. 68 (1958) 81--95. -.. [CFZ2000] \J. Cassaigne, S. Ferenczi, L.Q. Zamboni, Imbalances in - Arnoux-Rauzy sequences, Ann. Inst. Fourier (Grenoble) +.. [CFZ2000] \J. Cassaigne, S. Ferenczi, L.Q. Zamboni, *Imbalances in + Arnoux-Rauzy sequences*, Ann. Inst. Fourier (Grenoble) 50 (2000) 1265--1276. -.. [CFZ2002] Chapoton, Fomin, Zelevinsky - Polytopal realizations of - generalized associahedra, :arxiv:`math/0202004`. +.. [CFZ2002] \F. Chapoton, S. Fomin, A. Zelevinsky - *Polytopal realizations of + generalized associahedra*, :arxiv:`math/0202004`, + :doi:`10.4153/CMB-2002-054-1` .. [CGHLM2013] \P. Crescenzi, R. Grossi, M. Habib, L. Lanzi, A. Marino. *On computing the diameter of real-world undirected graphs*. @@ -1637,9 +1650,9 @@ REFERENCES: .. [Cha18] Frédéric Chapoton, *Some properties of a new partial order on Dyck paths*, 2018, :arxiv:`1809.10981` -.. [Cha22005] \B. Cha. Vanishing of some cohomology groups and bounds +.. [Cha22005] \B. Cha. *Vanishing of some cohomology groups and bounds for the Shafarevich-Tate groups of elliptic - curves. J. Number Theory, 111:154-178, 2005. + curves*. J. Number Theory, 111:154-178, 2005. .. [Cha2008] Frédéric Chapoton. *Sur le nombre d'intervalles dans les treillis de Tamari*. @@ -1779,13 +1792,13 @@ REFERENCES: :doi:`10.1007/978-3-319-07959-2_5`, https://hal.inria.fr/hal-00943549/document -.. [CMO2011] \C. Chun, D. Mayhew, J. Oxley, A chain theorem for - internally 4-connected binary matroids. J. Combin. Theory +.. [CMO2011] \C. Chun, D. Mayhew, J. Oxley, *A chain theorem for + internally 4-connected binary matroids*. J. Combin. Theory Ser. B 101 (2011), 141-189. -.. [CMO2012] \C. Chun, D. Mayhew, J. Oxley, Towards a splitter +.. [CMO2012] \C. Chun, D. Mayhew, J. Oxley, *Towards a splitter theorem for internally 4-connected binary - matroids. J. Combin. Theory Ser. B 102 (2012), 688-700. + matroids*. J. Combin. Theory Ser. B 102 (2012), 688-700. .. [CMR2005] C\. Cid, S\. Murphy, M\. Robshaw, *Small Scale Variants of the AES*; in Proceedings of Fast Software Encryption @@ -2762,6 +2775,11 @@ REFERENCES: Cambridge University Press, Cambridge, 2009. See also the `Errata list `_. +.. [FSST1986] Michael L. Fredman, Robert Sedgewick, Daniel D. Sleator, + and Robert E. Tarjan. *The pairing heap: A new form of + self-adjusting heap*, Algorithmica, 1:111-129, 1986. + :doi:`10.1007/BF01840439` + .. [FST2012] \A. Felikson, \M. Shapiro, and \P. Tumarkin, *Cluster Algebras of Finite Mutation Type Via Unfoldings*, Int Math Res Notices (2012) 2012 (8): 1768-1804. @@ -3214,6 +3232,10 @@ REFERENCES: The Electronic Journal of Combinatorics 11 (2004), #R77. http://www.combinatorics.org/Volume_11/PDF/v11i1r77.pdf +.. [HaHo2017] Nate Harman and Sam Hopkins, + *Quantum integer-valued polynomials*, + J. Alg. Comb. 2017, :doi:`10.1007/s10801-016-0717-3` + .. [Hai1989] M.D. Haiman, *On mixed insertion, symmetry, and shifted Young tableaux*. Journal of Combinatorial Theory, Series A Volume 50, Number 2 (1989), pp. 196-225. @@ -3227,7 +3249,7 @@ REFERENCES: http://www-math.mit.edu/~hajiagha/pp11.ps .. [Han1960] Haim Hanani, - On quadruple systems, + *On quadruple systems*, pages 145--157, vol. 12, Canadian Journal of Mathematics, 1960 diff --git a/src/doc/en/reference/repl/index.rst b/src/doc/en/reference/repl/index.rst index d12d8866dda..cf17bba8fb3 100644 --- a/src/doc/en/reference/repl/index.rst +++ b/src/doc/en/reference/repl/index.rst @@ -1,3 +1,5 @@ +.. _section-command-line: + The Sage Command Line ===================== @@ -5,8 +7,8 @@ The Sage Read-Eval-Print-Loop (REPL) is based on IPython. In this document, you'll find how the IPython integration works. You should also be familiar with the documentation for IPython. -For more details about using the Sage command line, see the Sage -tutorial. +For more details about using the Sage command line, see `the Sage +tutorial <../../tutorial/index.html>`_. Running Sage ------------ diff --git a/src/doc/en/thematic_tutorials/coercion_and_categories.rst b/src/doc/en/thematic_tutorials/coercion_and_categories.rst index 5e9fcf77db6..9494f8c43ee 100644 --- a/src/doc/en/thematic_tutorials/coercion_and_categories.rst +++ b/src/doc/en/thematic_tutorials/coercion_and_categories.rst @@ -130,11 +130,8 @@ This base class provides a lot more methods than a general parent:: 'gen', 'gens', 'integral_closure', - 'is_commutative', 'is_field', - 'is_integrally_closed', 'krull_dimension', - 'localization', 'ngens', 'one', 'order', diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/level_one_forms.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/level_one_forms.rst index e2777d45512..dba40ee090b 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/level_one_forms.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/level_one_forms.rst @@ -47,22 +47,31 @@ rather nice diagonal shape. :: sage: victor_miller_basis(24, 6) - [ - 1 + 52416000*q^3 + 39007332000*q^4 + 6609020221440*q^5 + O(q^6), - q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), - q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) - ] + [1 + 52416000*q^3 + 39007332000*q^4 + 6609020221440*q^5 + O(q^6), + q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), + q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6)] sage: from sage.modular.dims import dimension_modular_forms sage: dimension_modular_forms(1,200) 17 sage: B = victor_miller_basis(200, 18) #5 seconds sage: B - [ - 1 + 79288314420681734048660707200000*q^17 + O(q^18), - q + 2687602718106772837928968846869*q^17 + O(q^18), - ... - q^16 + 96*q^17 + O(q^18) - ] + [1 + 79288314420681734048660707200000*q^17 + O(q^18), + q + 2687602718106772837928968846869*q^17 + O(q^18), + q^2 + 85789116961248834349485762560*q^17 + O(q^18), + q^3 + 2567045661341737693075080984*q^17 + O(q^18), + q^4 + 71629117222531314878690304*q^17 + O(q^18), + q^5 + 1852433650992110376992650*q^17 + O(q^18), + q^6 + 44081333191517147315712*q^17 + O(q^18), + q^7 + 956892703246212300900*q^17 + O(q^18), + q^8 + 18748755998771700480*q^17 + O(q^18), + q^9 + 327218645736859401*q^17 + O(q^18), + q^10 + 5001104379048960*q^17 + O(q^18), + q^11 + 65427591611128*q^17 + O(q^18), + q^12 + 709488619776*q^17 + O(q^18), + q^13 + 6070433286*q^17 + O(q^18), + q^14 + 37596416*q^17 + O(q^18), + q^15 + 138420*q^17 + O(q^18), + q^16 + 96*q^17 + O(q^18)] Note: Craig Citro has made the above computation an order of magnitude faster in code he has not quite got into Sage yet. diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modabvar.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modabvar.rst index 3c7d2688d18..de3fa3aaad4 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modabvar.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modabvar.rst @@ -35,10 +35,8 @@ compute some basic invariants. :: sage: D = J0(39).decomposition(); D - [ - Simple abelian subvariety 39a(1,39) of dimension 1 of J0(39), - Simple abelian subvariety 39b(1,39) of dimension 2 of J0(39) - ] + [Simple abelian subvariety 39a(1,39) of dimension 1 of J0(39), + Simple abelian subvariety 39b(1,39) of dimension 2 of J0(39)] sage: D[1].lattice() Free module of degree 6 and rank 4 over Integer Ring Echelon basis matrix: diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modular_forms_and_hecke_operators.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modular_forms_and_hecke_operators.rst index 4d223f282d3..0914cc949fa 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modular_forms_and_hecke_operators.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/modular_forms_and_hecke_operators.rst @@ -142,13 +142,11 @@ and :math:`k` is the weight. sage: S = CuspForms(Gamma0(25),4, prec=15); S Cuspidal subspace of dimension 5 of Modular Forms space ... sage: S.basis() - [ - q + q^9 - 8*q^11 - 8*q^14 + O(q^15), - q^2 - q^7 - q^8 - 7*q^12 + 7*q^13 + O(q^15), - q^3 + q^7 - 2*q^8 - 6*q^12 - 5*q^13 + O(q^15), - q^4 - q^6 - 3*q^9 + 5*q^11 - 2*q^14 + O(q^15), - q^5 - 4*q^10 + O(q^15) - ] + [q + q^9 - 8*q^11 - 8*q^14 + O(q^15), + q^2 - q^7 - q^8 - 7*q^12 + 7*q^13 + O(q^15), + q^3 + q^7 - 2*q^8 - 6*q^12 - 5*q^13 + O(q^15), + q^4 - q^6 - 3*q^9 + 5*q^11 - 2*q^14 + O(q^15), + q^5 - 4*q^10 + O(q^15)] Dimension Formulas ~~~~~~~~~~~~~~~~~~ @@ -200,9 +198,7 @@ described later. :: sage: CuspForms(DirichletGroup(5).0, 5).basis() - [ - q + (-zeta4 - 1)*q^2 + (6*zeta4 - 6)*q^3 - ... + O(q^6) - ] + [q + (-zeta4 - 1)*q^2 + (6*zeta4 - 6)*q^3 - 14*zeta4*q^4 + (15*zeta4 + 20)*q^5 + O(q^6)] Dirichlet Characters @@ -296,12 +292,10 @@ Hecke operator :math:`T_n`, and to compute the subspace sage: M = ModularForms(Gamma0(11),4) sage: M.basis() - [ - q + 3*q^3 - 6*q^4 - 7*q^5 + O(q^6), - q^2 - 4*q^3 + 2*q^4 + 8*q^5 + O(q^6), - 1 + O(q^6), - q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6) - ] + [q + 3*q^3 - 6*q^4 - 7*q^5 + O(q^6), + q^2 - 4*q^3 + 2*q^4 + 8*q^5 + O(q^6), + 1 + O(q^6), + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6)] sage: M.hecke_matrix(2) [0 2 0 0] [1 2 0 0] diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst index 9e5b3b8fbf0..753b16b564a 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/nf_galois_groups.rst @@ -101,20 +101,18 @@ You can also enumerate all complex embeddings of a number field: :: sage: K.complex_embeddings() - [ - Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Complex Field with 53 bits of precision - Defn: a |--> -0.629960524947437 - 1.09112363597172*I, - Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Complex Field with 53 bits of precision - Defn: a |--> -0.629960524947437 + 1.09112363597172*I, - Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Complex Field with 53 bits of precision - Defn: a |--> 1.25992104989487 - ] + [Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Complex Field with 53 bits of precision + Defn: a |--> -0.629960524947437 - 1.09112363597172*I, + Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Complex Field with 53 bits of precision + Defn: a |--> -0.629960524947437 + 1.09112363597172*I, + Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Complex Field with 53 bits of precision + Defn: a |--> 1.25992104989487] Class Numbers and Class Groups diff --git a/src/doc/en/tutorial/index.rst b/src/doc/en/tutorial/index.rst index 9098e68c78e..7b1591cf621 100644 --- a/src/doc/en/tutorial/index.rst +++ b/src/doc/en/tutorial/index.rst @@ -2,8 +2,6 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -.. _tutorial: - ======================== Welcome to Sage Tutorial ======================== diff --git a/src/doc/en/tutorial/programming.rst b/src/doc/en/tutorial/programming.rst index 7e4fd9b3468..08c6ac267dd 100644 --- a/src/doc/en/tutorial/programming.rst +++ b/src/doc/en/tutorial/programming.rst @@ -248,15 +248,9 @@ examples. sqrt(2) sage: V = VectorSpace(QQ,2) sage: V.basis() - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: basis(V) - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: M = MatrixSpace(GF(7), 2); M Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 sage: A = M([1,2,3,4]); A @@ -407,11 +401,7 @@ sequences, since it's important that you don't change them. :: sage: V = QQ^3; B = V.basis(); B - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: type(B) sage: B[0] = B[1] diff --git a/src/doc/en/tutorial/tour_advanced.rst b/src/doc/en/tutorial/tour_advanced.rst index a34bb01f5e4..da3dd7fc4c5 100644 --- a/src/doc/en/tutorial/tour_advanced.rst +++ b/src/doc/en/tutorial/tour_advanced.rst @@ -20,12 +20,10 @@ of the union. Affine Plane Curve over Rational Field defined by x^5 + x^3*y^2 + x^2*y^3 + y^5 - x^3 - y^3 - x^2 - y^2 + 1 sage: D.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 + y^2 - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^3 + y^3 - 1 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^2 + y^2 - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^3 + y^3 - 1] We can also find all points of intersection of the two curves by intersecting them and computing the irreducible components. @@ -36,17 +34,15 @@ intersecting them and computing the irreducible components. sage: V = C2.intersection(C3) sage: V.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y, - x - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y - 1, - x, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x + y + 2, - 2*y^2 + 4*y + 3 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y, + x - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y - 1, + x, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x + y + 2, + 2*y^2 + 4*y + 3] Thus, e.g., :math:`(1,0)` and :math:`(0,1)` are on both curves (visibly clear), as are certain (quadratic) points whose @@ -331,10 +327,8 @@ factorization of the modulus. [1, 2, 2, 1, 1, 2, 2, 1] sage: G.decomposition() - [ - Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, - Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2 - ] + [Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, + Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2] Next, we construct the group of Dirichlet characters mod 20, but with values in :math:`\QQ(i)`: @@ -462,9 +456,7 @@ Let's compute some characteristic polynomials and [-2 0] [ 0 -2] sage: S.q_expansion_basis(10) - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10)] We can even compute spaces of modular symbols with character. @@ -484,10 +476,7 @@ We can even compute spaces of modular symbols with character. sage: S.T(2).charpoly('x').factor() (x + zeta6 + 1)^2 sage: S.q_expansion_basis(10) - [ - q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 - + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10) - ] + [q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10)] Here is another example of how Sage can compute the action of Hecke operators on a space of modular forms. diff --git a/src/doc/en/tutorial/tour_linalg.rst b/src/doc/en/tutorial/tour_linalg.rst index 84a45f4931b..08f2858d7ef 100644 --- a/src/doc/en/tutorial/tour_linalg.rst +++ b/src/doc/en/tutorial/tour_linalg.rst @@ -63,11 +63,7 @@ Sage can also compute eigenvalues and eigenvectors:: [-2*I, 2*I] sage: B = matrix([[1, 3], [3, 1]]) sage: B.eigenvectors_left() - [(4, [ - (1, 1) - ], 1), (-2, [ - (1, -1) - ], 1)] + [(4, [(1, 1)], 1), (-2, [(1, -1)], 1)] (The syntax for the output of ``eigenvectors_left`` is a list of triples: (eigenvalue, eigenvector, multiplicity).) Eigenvalues and @@ -239,4 +235,4 @@ Note that Python is case sensitive: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: ...__init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse'... diff --git a/src/doc/en/website/versions.txt b/src/doc/en/website/versions.txt index 12aed2b8cfe..6d1a9aa05ea 100644 --- a/src/doc/en/website/versions.txt +++ b/src/doc/en/website/versions.txt @@ -7,6 +7,7 @@ # The sage-update-version script adds a new line for a new stable release # when run by the Sage release manager to prepare a new release # +10.5 doc-10-5--sagemath.netlify.app 10.4 doc-10-4--sagemath.netlify.app 10.3 doc-10-3--sagemath.netlify.app 10.2 doc-10-2--sagemath.netlify.app diff --git a/src/doc/es/tutorial/tour_linalg.rst b/src/doc/es/tutorial/tour_linalg.rst index a9b543cca0e..b82b16e2daa 100644 --- a/src/doc/es/tutorial/tour_linalg.rst +++ b/src/doc/es/tutorial/tour_linalg.rst @@ -71,11 +71,7 @@ Sage también puede calcular autovalores ("eigenvalues") y autovectores [-2*I, 2*I] sage: B = matrix([[1, 3], [3, 1]]) sage: B.eigenvectors_left() - [(4, [ - (1, 1) - ], 1), (-2, [ - (1, -1) - ], 1)] + [(4, [(1, 1)], 1), (-2, [(1, -1)], 1)] (La sintaxis de la salida de ``eigenvectors_left`` es una lista de tuplas: (autovalor, autovector, multiplicidad).) Los autovalores diff --git a/src/doc/fr/tutorial/programming.rst b/src/doc/fr/tutorial/programming.rst index 32f465cfc5c..508905bfedf 100644 --- a/src/doc/fr/tutorial/programming.rst +++ b/src/doc/fr/tutorial/programming.rst @@ -260,15 +260,9 @@ ne sont pas claires en notation orientée objet. Voici quelques exemples. sqrt(2) sage: V = VectorSpace(QQ,2) sage: V.basis() - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: basis(V) - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: M = MatrixSpace(GF(7), 2); M Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 sage: A = M([1,2,3,4]); A @@ -420,11 +414,7 @@ mutables, car il ne faut pas les modifier. :: sage: V = QQ^3; B = V.basis(); B - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: type(B) sage: B[0] = B[1] diff --git a/src/doc/fr/tutorial/tour_advanced.rst b/src/doc/fr/tutorial/tour_advanced.rst index c6a0f2078e8..70ece3bc944 100644 --- a/src/doc/fr/tutorial/tour_advanced.rst +++ b/src/doc/fr/tutorial/tour_advanced.rst @@ -20,12 +20,10 @@ en tant que composante irréductible de la réunion. Affine Plane Curve over Rational Field defined by x^5 + x^3*y^2 + x^2*y^3 + y^5 - x^3 - y^3 - x^2 - y^2 + 1 sage: D.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 + y^2 - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^3 + y^3 - 1 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^2 + y^2 - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^3 + y^3 - 1] Nous pouvons également trouver tous les points d'intersection des deux courbes en les intersectant et en calculant les composantes @@ -37,17 +35,15 @@ irréductibles. sage: V = C2.intersection(C3) sage: V.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y, - x - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y - 1, - x, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x + y + 2, - 2*y^2 + 4*y + 3 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y, + x - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y - 1, + x, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x + y + 2, + 2*y^2 + 4*y + 3] Ainsi, par exemple, :math:`(1,0)` et :math:`(0,1)` appartiennent aux deux courbes (ce dont on pouvait directement s'apercevoir) ; il en va de même des @@ -332,10 +328,8 @@ caractères, de même qu'une décomposition en produit direct correspondant [1, 2, 2, 1, 1, 2, 2, 1] sage: G.decomposition() - [ - Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, - Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2 - ] + [Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, + Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2] Construisons à present le groupe de caractères de Dirichlet modulo 20, mais à valeur dans :math:`\QQ(i)`: @@ -462,9 +456,7 @@ Calculons quelques polynômes caractéristiques et développements en série de [-2 0] [ 0 -2] sage: S.q_expansion_basis(10) - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10)] On peut même calculer des espaces de formes modulaires avec caractères. @@ -484,10 +476,7 @@ On peut même calculer des espaces de formes modulaires avec caractères. sage: S.T(2).charpoly('x').factor() (x + zeta6 + 1)^2 sage: S.q_expansion_basis(10) - [ - q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 - + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10) - ] + [q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10)] Voici un autre exemple montrant comment Sage peut calculer l'action d'un opérateur de Hecke sur un espace de formes modulaires. diff --git a/src/doc/fr/tutorial/tour_linalg.rst b/src/doc/fr/tutorial/tour_linalg.rst index 582a915edef..7ad0bd89387 100644 --- a/src/doc/fr/tutorial/tour_linalg.rst +++ b/src/doc/fr/tutorial/tour_linalg.rst @@ -63,11 +63,7 @@ Sage sait aussi calculer les valeurs propres et vecteurs propres:: [-2*I, 2*I] sage: B = matrix([[1, 3], [3, 1]]) sage: B.eigenvectors_left() - [(4, [ - (1, 1) - ], 1), (-2, [ - (1, -1) - ], 1)] + [(4, [(1, 1)], 1), (-2, [(1, -1)], 1)] (La sortie de ``eigenvectors_left`` est une liste de triplets (valeur propre, vecteur propre, multiplicité).) Sur ``QQ`` et ``RR``, on peut aussi utiliser @@ -241,4 +237,4 @@ Notez que Python distingue les majuscules des minuscules : sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: ...__init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse'... diff --git a/src/doc/ja/tutorial/japanesesupport.py b/src/doc/ja/tutorial/japanesesupport.py index 6d954e3ddc9..f19aa9953e1 100644 --- a/src/doc/ja/tutorial/japanesesupport.py +++ b/src/doc/ja/tutorial/japanesesupport.py @@ -2,6 +2,7 @@ import re __RGX = re.compile(r'([^!-~])[\n\r\t]+([^!-~])') + def trunc_whitespace(app, doctree, docname): from docutils.nodes import Text, paragraph if not app.config.japanesesupport_trunc_whitespace: @@ -15,6 +16,7 @@ def trunc_whitespace(app, doctree, docname): #newtext = newtext.strip() node.parent.replace(node, Text(newtext)) + def setup(app): app.add_config_value('japanesesupport_trunc_whitespace', True, True) app.connect("doctree-resolved", trunc_whitespace) diff --git a/src/doc/ja/tutorial/programming.rst b/src/doc/ja/tutorial/programming.rst index 1880cbd6d23..2b978c2f6a8 100644 --- a/src/doc/ja/tutorial/programming.rst +++ b/src/doc/ja/tutorial/programming.rst @@ -222,15 +222,9 @@ Sageでは,さらに多様な型が加わる. sqrt(2) sage: V = VectorSpace(QQ,2) sage: V.basis() - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: basis(V) - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: M = MatrixSpace(GF(7), 2); M Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 sage: A = M([1,2,3,4]); A @@ -387,11 +381,7 @@ Sageで使われる第三のリスト類似データ型が,シーケンスで :: sage: V = QQ^3; B = V.basis(); B - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: type(B) sage: B[0] = B[1] diff --git a/src/doc/ja/tutorial/tour_advanced.rst b/src/doc/ja/tutorial/tour_advanced.rst index 8ca8ce5660c..6b8ed96904a 100644 --- a/src/doc/ja/tutorial/tour_advanced.rst +++ b/src/doc/ja/tutorial/tour_advanced.rst @@ -20,12 +20,10 @@ Sageでは,任意の代数多様体を定義することができるが,そ Affine Plane Curve over Rational Field defined by x^5 + x^3*y^2 + x^2*y^3 + y^5 - x^3 - y^3 - x^2 - y^2 + 1 sage: D.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 + y^2 - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^3 + y^3 - 1 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^2 + y^2 - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^3 + y^3 - 1] 以上の2本の曲線の交わりを取れば,全ての交点を求めてその既約成分を計算することもできる. @@ -36,17 +34,15 @@ Sageでは,任意の代数多様体を定義することができるが,そ sage: V = C2.intersection(C3) sage: V.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y, - x - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y - 1, - x, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x + y + 2, - 2*y^2 + 4*y + 3 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y, + x - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y - 1, + x, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x + y + 2, + 2*y^2 + 4*y + 3] というわけで,点 :math:`(1,0)` および :math:`(0,1)` が双方の曲線上にあるのはすぐ見てとることができるし, :math:`y` 成分が :math:`2y^2 + 4y + 3=0` を満足する(2次の)点についても同じことだ. @@ -313,10 +309,8 @@ Cremonaのデータベースへ直接にアクセスすることも可能だ. [1, 2, 2, 1, 1, 2, 2, 1] sage: G.decomposition() - [ - Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, - Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2 - ] + [Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, + Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2] 次に,mod 20,ただし値が :math:`\QQ(i)` 上に収まるディリクレ指標の群を作成する: @@ -438,9 +432,7 @@ Sageを使ってモジュラー空間の次元,モジュラー・シンポル [-2 0] [ 0 -2] sage: S.q_expansion_basis(10) - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10)] モジュラー・シンボルの空間を,指標を指定して生成することも可能だ. @@ -460,10 +452,7 @@ Sageを使ってモジュラー空間の次元,モジュラー・シンポル sage: S.T(2).charpoly('x').factor() (x + zeta6 + 1)^2 sage: S.q_expansion_basis(10) - [ - q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 - + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10) - ] + [q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10)] 以下の例では,モジュラー形式によって張られる空間に対するHecke演算子の作用を,Sageでどうやって計算するかを示す. diff --git a/src/doc/ja/tutorial/tour_linalg.rst b/src/doc/ja/tutorial/tour_linalg.rst index 227f879136e..bc21ed4d8bf 100644 --- a/src/doc/ja/tutorial/tour_linalg.rst +++ b/src/doc/ja/tutorial/tour_linalg.rst @@ -70,11 +70,7 @@ Sageは固有値と固有ベクトルの計算もしてくれる: [-2*I, 2*I] sage: B = matrix([[1, 3], [3, 1]]) sage: B.eigenvectors_left() - [(4, [ - (1, 1) - ], 1), (-2, [ - (1, -1) - ], 1)] + [(4, [(1, 1)], 1), (-2, [(1, -1)], 1)] ( ``eigenvectors_left`` の出力は,三つ組タプル(固有値,固有ベクトル,多重度)のリストになっている.) @@ -252,4 +248,4 @@ Pythonでは,大文字小文字が区別されることに注意: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: ...__init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse'... diff --git a/src/doc/pt/tutorial/programming.rst b/src/doc/pt/tutorial/programming.rst index ea1d6b2e348..51965d03671 100644 --- a/src/doc/pt/tutorial/programming.rst +++ b/src/doc/pt/tutorial/programming.rst @@ -275,15 +275,9 @@ exemplos. sqrt(2) sage: V = VectorSpace(QQ,2) sage: V.basis() - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: basis(V) - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: M = MatrixSpace(GF(7), 2); M Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 sage: A = M([1,2,3,4]); A @@ -433,11 +427,7 @@ imutáveis, pois é importante que elas não sejam modificadas. :: sage: V = QQ^3; B = V.basis(); B - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: type(B) sage: B[0] = B[1] diff --git a/src/doc/pt/tutorial/tour_advanced.rst b/src/doc/pt/tutorial/tour_advanced.rst index 075b3b1551e..5a8fdd04de9 100644 --- a/src/doc/pt/tutorial/tour_advanced.rst +++ b/src/doc/pt/tutorial/tour_advanced.rst @@ -20,12 +20,10 @@ componentes irredutíveis da união. Affine Plane Curve over Rational Field defined by x^5 + x^3*y^2 + x^2*y^3 + y^5 - x^3 - y^3 - x^2 - y^2 + 1 sage: D.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 + y^2 - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^3 + y^3 - 1 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^2 + y^2 - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^3 + y^3 - 1] Você também pode encontrar todos os pontos de interseção das duas curvas, intersectando-as, e então calculando as componentes @@ -37,17 +35,15 @@ irredutíveis. sage: V = C2.intersection(C3) sage: V.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y, - x - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y - 1, - x, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x + y + 2, - 2*y^2 + 4*y + 3 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y, + x - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y - 1, + x, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x + y + 2, + 2*y^2 + 4*y + 3] Portanto, por exemplo, :math:`(1,0)` e :math:`(0,1)` estão em ambas as curvas (o que é claramente visível), como também estão certos pontos @@ -332,10 +328,8 @@ módulo. [1, 2, 2, 1, 1, 2, 2, 1] sage: G.decomposition() - [ - Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, - Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2 - ] + [Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, + Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2] A seguir, construímos o grupo de caracteres de Dirichlet mod 20, mas com valores em :math:`\QQ(i)`: @@ -463,9 +457,7 @@ Vamos calcular alguns polinômios característicos e expansões [-2 0] [ 0 -2] sage: S.q_expansion_basis(10) - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10)] Podemos até mesmo calcular espaços de símbolos modulares com carácter. @@ -485,10 +477,7 @@ Podemos até mesmo calcular espaços de símbolos modulares com carácter. sage: S.T(2).charpoly('x').factor() (x + zeta6 + 1)^2 sage: S.q_expansion_basis(10) - [ - q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 - + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10) - ] + [q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10)] Aqui está um outro exemplo de como o Sage pode calcular a ação de operadores de Hecke em um espaço de formas modulares. diff --git a/src/doc/pt/tutorial/tour_linalg.rst b/src/doc/pt/tutorial/tour_linalg.rst index 806a36c6446..5cb4a4f8f11 100644 --- a/src/doc/pt/tutorial/tour_linalg.rst +++ b/src/doc/pt/tutorial/tour_linalg.rst @@ -61,11 +61,7 @@ O Sage também pode calcular autovalores e autovetores:: [-2*I, 2*I] sage: B = matrix([[1, 3], [3, 1]]) sage: B.eigenvectors_left() - [(4, [ - (1, 1) - ], 1), (-2, [ - (1, -1) - ], 1)] + [(4, [(1, 1)], 1), (-2, [(1, -1)], 1)] (A sintaxe para a resposta de ``eigenvectors_left`` é uma lista com três componentes: (autovalor, autovetor, multiplicidade).) Autovalores @@ -220,4 +216,4 @@ Note que o Python é sensível a maiúsculas e minúsculas: sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: ...__init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse'... diff --git a/src/doc/ru/tutorial/programming.rst b/src/doc/ru/tutorial/programming.rst index 0ea10634c0b..c8caf6ade63 100644 --- a/src/doc/ru/tutorial/programming.rst +++ b/src/doc/ru/tutorial/programming.rst @@ -242,15 +242,9 @@ C и обработан компилятором C. sqrt(2) sage: V = VectorSpace(QQ,2) sage: V.basis() - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: basis(V) - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] sage: M = MatrixSpace(GF(7), 2); M Full MatrixSpace of 2 by 2 dense matrices over Finite Field of size 7 sage: A = M([1,2,3,4]); A @@ -395,11 +389,7 @@ Python, сработает нормально. :: sage: V = QQ^3; B = V.basis(); B - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: type(B) sage: B[0] = B[1] diff --git a/src/doc/ru/tutorial/tour_advanced.rst b/src/doc/ru/tutorial/tour_advanced.rst index 69eb42dfd4c..1420053e93b 100644 --- a/src/doc/ru/tutorial/tour_advanced.rst +++ b/src/doc/ru/tutorial/tour_advanced.rst @@ -19,12 +19,10 @@ Sage позволяет создавать любые алгебраически Affine Plane Curve over Rational Field defined by x^5 + x^3*y^2 + x^2*y^3 + y^5 - x^3 - y^3 - x^2 - y^2 + 1 sage: D.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^2 + y^2 - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x^3 + y^3 - 1 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^2 + y^2 - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x^3 + y^3 - 1] Также можно найти все точки пересечения двух кривых. @@ -34,17 +32,15 @@ Sage позволяет создавать любые алгебраически sage: V = C2.intersection(C3) sage: V.irreducible_components() - [ - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y, - x - 1, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - y - 1, - x, - Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: - x + y + 2, - 2*y^2 + 4*y + 3 - ] + [Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y, + x - 1, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + y - 1, + x, + Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + x + y + 2, + 2*y^2 + 4*y + 3] Таким образом точки :math:`(1,0)` и :math:`(0,1)` находятся на обеих кривых, а координаты по оси :math:`y` удовлетворяют функции :math:`2y^2 + 4y + 3=0`. @@ -296,10 +292,8 @@ Sage может вычислить тороидальный идеал непл [1, 2, 2, 1, 1, 2, 2, 1] sage: G.decomposition() - [ - Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, - Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2 - ] + [Group of Dirichlet characters modulo 3 with values in Cyclotomic Field of order 6 and degree 2, + Group of Dirichlet characters modulo 7 with values in Cyclotomic Field of order 6 and degree 2] Далее надо построить группу символов Дирихле по модулю 20, но со значениями с :math:`\QQ(i)`: @@ -423,9 +417,7 @@ Sage может выполнять вычисления, связанные с [-2 0] [ 0 -2] sage: S.q_expansion_basis(10) - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 - 2*q^9 + O(q^10)] Также возможны вычисления пространств модулярных символов с буквами. @@ -445,10 +437,7 @@ Sage может выполнять вычисления, связанные с sage: S.T(2).charpoly('x').factor() (x + zeta6 + 1)^2 sage: S.q_expansion_basis(10) - [ - q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 - + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10) - ] + [q + (-zeta6 - 1)*q^2 + (2*zeta6 - 2)*q^3 + zeta6*q^4 + (-2*zeta6 + 1)*q^5 + (-2*zeta6 + 4)*q^6 + (2*zeta6 - 1)*q^8 - zeta6*q^9 + O(q^10)] Пример того, как Sage может вычислять действия операторов Гекке на пространство модулярных форм. diff --git a/src/doc/ru/tutorial/tour_linalg.rst b/src/doc/ru/tutorial/tour_linalg.rst index bf2a1084544..675de2d7a3c 100644 --- a/src/doc/ru/tutorial/tour_linalg.rst +++ b/src/doc/ru/tutorial/tour_linalg.rst @@ -56,11 +56,7 @@ Sage может находить собственное число и собст [-2*I, 2*I] sage: B = matrix([[1, 3], [3, 1]]) sage: B.eigenvectors_left() - [(4, [ - (1, 1) - ], 1), (-2, [ - (1, -1) - ], 1)] + [(4, [(1, 1)], 1), (-2, [(1, -1)], 1)] (Результат ``eigenvectors_left`` - это список троек: (собственное число, собственный вектор, многообразие).) Собственные числа и вектора @@ -214,4 +210,4 @@ Sage поддерживает разреженную линейную алгеб sage: M = MatrixSpace(QQ, 10,10, Sparse=True) Traceback (most recent call last): ... - TypeError: ...__init__() got an unexpected keyword argument 'Sparse' + TypeError: ...__init__() got an unexpected keyword argument 'Sparse'... diff --git a/src/meson.build b/src/meson.build index 31544d29dbd..fb22b2cec22 100644 --- a/src/meson.build +++ b/src/meson.build @@ -56,9 +56,10 @@ print(cypari2.__file__.replace('__init__.py', '')) check: true, ).stdout().strip() cypari2 = declare_dependency(include_directories: inc_cypari2) +# Cannot be found via pkg-config pari = cc.find_library('pari') -mpfr = cc.find_library('mpfr') +mpfr = dependency('mpfr') flint = dependency('flint', version: '>=3.0.0') if flint.version().version_compare('<3.1') @@ -78,41 +79,51 @@ endif # that too to make the fallback detection with CMake work blas_order += ['cblas', 'openblas', 'OpenBLAS', 'flexiblas', 'blis', 'blas'] blas = dependency(blas_order) -gsl = dependency('gsl', version: '>=2.5', required: true) -gd = cc.find_library('gd') +gsl = dependency('gsl', version: '>=2.5') +gd = dependency('gdlib', required: false, version: '>=2.1') +if not gd.found() + gd = cc.find_library('gd', required: true) +endif # Only some platforms have a standalone math library (https://mesonbuild.com/howtox.html#add-math-library-lm-portably) m = cc.find_library('m', required: false) -m4ri = cc.find_library('m4ri') -m4rie = cc.find_library('m4rie') -mtx = cc.find_library('mtx', required: false, disabler: true) -png = cc.find_library('png', required: false) -if not png.found() - png = cc.find_library('png16') +m4ri = dependency('m4ri', version: '>=20140914') +m4rie = dependency('m4rie', required: false) +if not m4rie.found() + # For some reason, m4rie is not found via pkg-config on some systems (eg Conda) + m4rie = cc.find_library('m4rie') endif -zlib = cc.find_library('z') # Cannot be found via pkg-config -ec = cc.find_library('ec') +mtx = cc.find_library('mtx', required: false, disabler: true) +png = dependency(['libpng', 'png', 'png16'], version: '>=1.2') +zlib = dependency('zlib', version: '>=1.2.11') +# We actually want >= 20231212, but the version number is not updated in the pkgconfig +# https://github.com/conda-forge/eclib-feedstock/issues/48 +ec = dependency('eclib', version: '>=20231211') +# Cannot be found via pkg-config ecm = cc.find_library('ecm') +# Cannot be found via pkg-config ppl = cc.find_library('ppl') -gmpxx = cc.find_library('gmpxx') -fflas = dependency('fflas-ffpack') +gmpxx = dependency('gmpxx') +fflas = dependency('fflas-ffpack', version: '>=2.5.0') fplll = dependency('fplll') -givaro = cc.find_library('givaro') -linbox = dependency('linbox', required: false) +givaro = dependency('givaro', version: '>=4.2.0') +linbox = dependency('linbox', required: false, version: '>=1.7.0') if not linbox.found() linbox = cc.find_library('linbox') endif mpc = cc.find_library('mpc') mpfi = cc.find_library('mpfi') -# Cannot be found via pkg-config (pkg-config file will be added in 4.13) -# Test for common.h header that was added in 4.12 as a indirect version check -gap = cc.find_library('gap', has_headers: ['gap/common.h']) + +gap = dependency('libgap', version: '>=4.13.0', required: false) +if not gap.found() + # Fallback in case pkg-config info is not available + # Test for common.h header that was added in 4.12 as a indirect version check + gap = cc.find_library('gap', has_headers: ['gap/common.h']) +endif singular = dependency('Singular') maxima = find_program('maxima', required: true) # Cannot be found via pkg-config ntl = cc.find_library('ntl') -# Cannot be found via pkg-config -meataxe = cc.find_library('meataxe', required: false, disabler: true) # Meson currently ignores include_directories for Cython modules, so we # have to add them manually. diff --git a/src/sage/algebras/algebra.py b/src/sage/algebras/algebra.py deleted file mode 100644 index 8d9395a3176..00000000000 --- a/src/sage/algebras/algebra.py +++ /dev/null @@ -1,40 +0,0 @@ -# sage.doctest: needs sage.combinat sage.modules -""" -Abstract base class for algebras -""" - -#***************************************************************************** -# Copyright (C) 2005 William Stein -# -# 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: -# -# http://www.gnu.org/licenses/ -#***************************************************************************** - -from sage.categories.algebras import Algebras - - -def is_Algebra(x): - r""" - Return ``True`` if `x` is an Algebra. - - EXAMPLES:: - - sage: from sage.algebras.algebra import is_Algebra - sage: R. = FreeAlgebra(QQ,2) - sage: is_Algebra(R) - doctest:warning... - DeprecationWarning: the function is_Algebra is deprecated; use '... in Algebras(base_ring)' instead - See https://github.com/sagemath/sage/issues/35253 for details. - True - """ - from sage.misc.superseded import deprecation - deprecation(35253, "the function is_Algebra is deprecated; use '... in Algebras(base_ring)' instead") - return x in Algebras(x.base_ring()) diff --git a/src/sage/algebras/clifford_algebra.py b/src/sage/algebras/clifford_algebra.py index 92ad6c34d64..091f5e0d559 100644 --- a/src/sage/algebras/clifford_algebra.py +++ b/src/sage/algebras/clifford_algebra.py @@ -844,7 +844,7 @@ def one_basis(self): """ return FrozenBitset() - def is_commutative(self): + def is_commutative(self) -> bool: """ Check if ``self`` is a commutative algebra. diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index 6772673cbcb..ca34a34acfc 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -572,12 +572,12 @@ def homogeneous_components(self) -> dict: components[g_vect] += self.parent().retract(x.monomial_coefficient(m) * m) else: components[g_vect] = self.parent().retract(x.monomial_coefficient(m) * m) - for g_vect in components: - components[g_vect]._is_homogeneous = True - components[g_vect]._g_vector = g_vect + for g_vect, compo in components.items(): + compo._is_homogeneous = True + compo._g_vector = g_vect self._is_homogeneous = (len(components) == 1) if self._is_homogeneous: - self._g_vector = list(components.keys())[0] + self._g_vector = next(iter(components)) return components def theta_basis_decomposition(self): diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index fdcaeedaad8..7dadae0de4d 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -1559,7 +1559,7 @@ def homogeneous_parts(self): res[deg] = term return {i: res[i] for i in sorted(res.keys())} - def monomial_coefficients(self): + def monomial_coefficients(self, copy=True): r""" A dictionary that determines the element. @@ -1578,7 +1578,7 @@ def monomial_coefficients(self): sage: sorted(elt.dict().items()) [((0, 1, 1, 0), -5), ((1, 1, 0, 0), 1), ((1, 2, 3, 1), 7)] """ - return self.lift().monomial_coefficients() + return self.lift().monomial_coefficients(copy=copy) dict = monomial_coefficients diff --git a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py index 3ba4bc658cb..66b3943b7d0 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -497,7 +497,7 @@ def is_associative(self): return True @cached_method - def is_commutative(self): + def is_commutative(self) -> bool: """ Return ``True`` if ``self`` is commutative. diff --git a/src/sage/algebras/finite_dimensional_algebras/meson.build b/src/sage/algebras/finite_dimensional_algebras/meson.build index 075f0b8cebd..85f04b2afcb 100644 --- a/src/sage/algebras/finite_dimensional_algebras/meson.build +++ b/src/sage/algebras/finite_dimensional_algebras/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'finite_dimensional_algebra.py', 'finite_dimensional_algebra_element.pxd', diff --git a/src/sage/algebras/free_algebra.py b/src/sage/algebras/free_algebra.py index 8b73482e7bf..a18e15c1df6 100644 --- a/src/sage/algebras/free_algebra.py +++ b/src/sage/algebras/free_algebra.py @@ -160,23 +160,24 @@ # *************************************************************************** -from sage.categories.rings import Rings - -from sage.monoids.free_monoid import FreeMonoid -from sage.monoids.free_monoid_element import FreeMonoidElement - from sage.algebras.free_algebra_element import FreeAlgebraElement - -from sage.structure.factory import UniqueFactory -from sage.misc.cachefunc import cached_method -from sage.misc.lazy_import import lazy_import -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.integer_ring import ZZ from sage.categories.algebras_with_basis import AlgebrasWithBasis +from sage.categories.functor import Functor +from sage.categories.pushout import (ConstructionFunctor, + CompositeConstructionFunctor, + IdentityConstructionFunctor) +from sage.categories.rings import Rings from sage.combinat.free_module import CombinatorialFreeModule from sage.combinat.words.word import Word +from sage.misc.cachefunc import cached_method +from sage.misc.lazy_import import lazy_import +from sage.monoids.free_monoid import FreeMonoid +from sage.monoids.free_monoid_element import FreeMonoidElement +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.category_object import normalize_names - +from sage.structure.coerce_exceptions import CoercionException +from sage.structure.factory import UniqueFactory lazy_import('sage.algebras.letterplace.free_algebra_letterplace', 'FreeAlgebra_letterplace') @@ -199,12 +200,12 @@ class FreeAlgebraFactory(UniqueFactory): sage: FreeAlgebra(GF(5),3, 'abc') Free Algebra on 3 generators (a, b, c) over Finite Field of size 5 sage: FreeAlgebra(GF(5),1, 'z') - Free Algebra on 1 generators (z,) over Finite Field of size 5 + Free Algebra on 1 generator (z,) over Finite Field of size 5 sage: FreeAlgebra(GF(5),1, ['alpha']) - Free Algebra on 1 generators (alpha,) over Finite Field of size 5 + Free Algebra on 1 generator (alpha,) over Finite Field of size 5 sage: FreeAlgebra(FreeAlgebra(ZZ,1,'a'), 2, 'x') Free Algebra on 2 generators (x0, x1) over - Free Algebra on 1 generators (a,) over Integer Ring + Free Algebra on 1 generator (a,) over Integer Ring Free algebras are globally unique:: @@ -264,7 +265,7 @@ class FreeAlgebraFactory(UniqueFactory): sage: s = a*b^2 * c^3; s a*b^2*c^3 sage: parent(s) - Free Algebra on 1 generators (c,) over + Free Algebra on 1 generator (c,) over Free Algebra on 2 generators (a, b) over Rational Field sage: c^3 * a * b^2 a*b^2*c^3 @@ -507,6 +508,17 @@ def __init__(self, R, n, names, degrees=None): else: self._degrees = {g: ZZ(d) for g, d in zip(self.monoid().gens(), degrees)} + def construction(self): + """ + Return the construction of ``self``. + + EXAMPLES:: + + sage: F, R = algebras.Free(QQ,4,'x,y,z,t').construction(); F + Associative[x,y,z,t] + """ + return AssociativeFunctor(self.variable_names(), self._degrees), self.base_ring() + def one_basis(self): """ Return the index of the basis element `1`. @@ -554,16 +566,17 @@ def _repr_(self) -> str: sage: F # indirect doctest QQ<> sage: FreeAlgebra(ZZ, 1, ['a']) - Free Algebra on 1 generators (a,) over Integer Ring + Free Algebra on 1 generator (a,) over Integer Ring sage: FreeAlgebra(QQ, 2, ['x', 'y'], degrees=(2,1)) Free Algebra on 2 generators (x, y) with degrees (2, 1) over Rational Field """ + txt = "generator" if self.__ngens == 1 else "generators" if self._degrees is None: - return "Free Algebra on {} generators {} over {}".format( - self.__ngens, self.gens(), self.base_ring()) - return "Free Algebra on {} generators {} with degrees {} over {}".format( - self.__ngens, self.gens(), tuple(self._degrees.values()), self.base_ring()) + return "Free Algebra on {} {} {} over {}".format( + self.__ngens, txt, self.gens(), self.base_ring()) + return "Free Algebra on {} {} {} with degrees {} over {}".format( + self.__ngens, txt, self.gens(), tuple(self._degrees.values()), self.base_ring()) def _latex_(self) -> str: r""" @@ -634,13 +647,24 @@ def _element_constructor_(self, x): 1.00000000000000*x^2 * 1.00000000000000*y^3 sage: F(f) 1.00000000000000*x^2*y^3 + + Check for extended coercion:: + + sage: A = algebras.Free(QQ,['x','y']) + sage: B = algebras.Free(QQ,['y']) + sage: y, = B.gens() + sage: A(4+y) + 4 + y """ if isinstance(x, FreeAlgebraElement): P = x.parent() if P is self: return x - if P is not self.base_ring(): - return self.element_class(self, x) + # from another FreeAlgebra: + if x not in self.base_ring(): + D = {self.monoid()(T): cf + for T, cf in x.monomial_coefficients().items()} + return self.element_class(self, D) elif hasattr(x, 'letterplace_polynomial'): P = x.parent() if self.has_coerce_map_from(P): # letterplace versus generic @@ -678,21 +702,23 @@ def exp_to_monomial(T): return self.element_class(self, {}) return self.element_class(self, {self.one_basis(): x}) - def _coerce_map_from_(self, R): + def _coerce_map_from_(self, R) -> bool: """ Return ``True`` if there is a coercion from ``R`` into ``self`` and - ``False`` otherwise. The things that coerce into ``self`` are: + ``False`` otherwise. + + The things that coerce into ``self`` are: - This free algebra. - - Anything with a coercion into ``self.monoid()``. + - The PBW basis of ``self``. - - Free algebras in the same variables over a base with a coercion - map into ``self.base_ring()``. + - Free algebras in some subset of variables + over a base with a coercion map into ``self.base_ring()``. - The underlying monoid. - - The PBW basis of ``self``. + - Anything with a coercion into ``self.monoid()``. - Anything with a coercion into ``self.base_ring()``. @@ -706,7 +732,7 @@ def _coerce_map_from_(self, R): sage: G._coerce_map_from_(F) True sage: F._coerce_map_from_(H) - False + True sage: F._coerce_map_from_(QQ) False sage: G._coerce_map_from_(QQ) @@ -743,7 +769,7 @@ def _coerce_map_from_(self, R): # free algebras in the same variable over any base that coerces in: if isinstance(R, (FreeAlgebra_generic, FreeAlgebra_letterplace)): - if R.variable_names() == self.variable_names(): + if all(x in self.variable_names() for x in R.variable_names()): return self.base_ring().has_coerce_map_from(R.base_ring()) if isinstance(R, PBWBasisOfFreeAlgebra): return self.has_coerce_map_from(R._alg) @@ -808,7 +834,7 @@ def algebra_generators(self): return Family(self.variable_names(), lambda i: ret[i]) @cached_method - def gens(self): + def gens(self) -> tuple: """ Return the generators of ``self``. @@ -1302,7 +1328,7 @@ def _coerce_map_from_(self, R): sage: G._coerce_map_from_(F) True sage: F._coerce_map_from_(H) - False + True sage: F._coerce_map_from_(QQ) False sage: G._coerce_map_from_(QQ) @@ -1449,3 +1475,222 @@ def expand(self): x + x^2*y - 2*x*y*x + y*x^2 + y^4*x """ return self.parent().expansion(self) + + +class AssociativeFunctor(ConstructionFunctor): + """ + A constructor for free associative algebras. + + EXAMPLES:: + + sage: P = algebras.Free(ZZ, 2, 'x,y') + sage: x,y = P.gens() + sage: F = P.construction()[0]; F + Associative[x,y] + + sage: A = GF(5)['a,b'] + sage: a, b = A.gens() + sage: F(A) + Free Algebra on 2 generators (x, y) over Multivariate Polynomial Ring in a, b over Finite Field of size 5 + + sage: f = A.hom([a+b,a-b],A) + sage: F(f) + Generic endomorphism of Free Algebra on 2 generators (x, y) + over Multivariate Polynomial Ring in a, b over Finite Field of size 5 + + sage: F(f)(a * F(A)(x)) + (a+b)*x + """ + rank = 9 + + def __init__(self, vars, degs=None): + """ + EXAMPLES:: + + sage: from sage.algebras.free_algebra import AssociativeFunctor + sage: F = AssociativeFunctor(['x','y']) + sage: F + Associative[x,y] + sage: F(ZZ) + Free Algebra on 2 generators (x, y) over Integer Ring + """ + Functor.__init__(self, Rings(), Rings()) + if not isinstance(vars, (list, tuple)): + raise TypeError("vars must be a list or tuple") + if degs is not None and not isinstance(degs, (list, tuple, dict)): + raise TypeError("degs must be a list, tuple or dict") + self.vars = vars + self.degs = degs + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: R = algebras.Free(ZZ, 3, 'x,y,z') + sage: F = R.construction()[0]; F + Associative[x,y,z] + sage: type(F) + + sage: F(ZZ) # indirect doctest + Free Algebra on 3 generators (x, y, z) over Integer Ring + """ + return FreeAlgebra(R, self.vars, self.degs) + + def _apply_functor_to_morphism(self, f): + """ + Apply the functor ``self`` to the ring morphism `f`. + + TESTS:: + + sage: R = algebras.Free(ZZ, 'x').construction()[0] + sage: R(ZZ.hom(GF(3))) # indirect doctest + Generic morphism: + From: Free Algebra on 1 generator (x,) over Integer Ring + To: Free Algebra on 1 generator (x,) over Finite Field of size 3 + """ + dom = self(f.domain()) + codom = self(f.codomain()) + + def action(x): + return codom._from_dict({a: f(b) + for a, b in x.monomial_coefficients().items()}) + return dom.module_morphism(function=action, codomain=codom) + + def __eq__(self, other): + """ + EXAMPLES:: + + sage: F = algebras.Free(ZZ, 3, 'x,y,z').construction()[0] + sage: G = algebras.Free(QQ, 3, 'x,y,z').construction()[0] + sage: F == G + True + sage: G == loads(dumps(G)) + True + sage: G = algebras.Free(QQ, 2, 'x,y').construction()[0] + sage: F == G + False + """ + if not isinstance(other, AssociativeFunctor): + return False + return self.vars == other.vars and self.degs == other.degs + + def __mul__(self, other): + """ + If two Associative functors are given in a row, form a single Associative functor + with all of the variables. + + EXAMPLES:: + + sage: from sage.algebras.free_algebra import AssociativeFunctor + sage: F = AssociativeFunctor(['x','y']) + sage: G = AssociativeFunctor(['t']) + sage: G * F + Associative[x,y,t] + """ + if isinstance(other, IdentityConstructionFunctor): + return self + if isinstance(other, AssociativeFunctor): + if set(self.vars).intersection(other.vars): + raise CoercionException("Overlapping variables (%s,%s)" % + (self.vars, other.vars)) + return AssociativeFunctor(other.vars + self.vars) + elif (isinstance(other, CompositeConstructionFunctor) and + isinstance(other.all[-1], AssociativeFunctor)): + return CompositeConstructionFunctor(other.all[:-1], + self * other.all[-1]) + else: + return CompositeConstructionFunctor(other, self) + + def merge(self, other): + """ + Merge ``self`` with another construction functor, or return ``None``. + + EXAMPLES:: + + sage: from sage.algebras.free_algebra import AssociativeFunctor + sage: F = AssociativeFunctor(['x','y']) + sage: G = AssociativeFunctor(['t']) + sage: F.merge(G) + Associative[x,y,t] + sage: F.merge(F) + Associative[x,y] + + With degrees:: + + sage: F = AssociativeFunctor(['x','y'], (2,3)) + sage: G = AssociativeFunctor(['t'], (4,)) + sage: H = AssociativeFunctor(['z','y'], (5,3)) + sage: F.merge(G) + Associative[x,y,t] with degrees (2, 3, 4) + sage: F.merge(H) + Associative[x,y,z] with degrees (2, 3, 5) + + Now some actual use cases:: + + sage: R = algebras.Free(ZZ, 3, 'x,y,z') + sage: x,y,z = R.gens() + sage: 1/2 * x + 1/2*x + sage: parent(1/2 * x) + Free Algebra on 3 generators (x, y, z) over Rational Field + + sage: S = algebras.Free(QQ, 2, 'z,t') + sage: z,t = S.gens() + sage: x + t + t + x + sage: parent(x + t) + Free Algebra on 4 generators (z, t, x, y) over Rational Field + + TESTS:: + + sage: F = AssociativeFunctor(['x','y'], (2,3)) + sage: H = AssociativeFunctor(['z','y'], (5,4)) + sage: F.merge(H) + """ + if isinstance(other, AssociativeFunctor): + if self.vars == other.vars and self.degs == other.degs: + return self + + ret = list(self.vars) + self_vars = set(ret) + ret.extend(v for v in other.vars if v not in self_vars) + + # first case: no degrees + if self.degs is None and other.degs is None: + return AssociativeFunctor(tuple(ret)) + + # second case: merge the degrees + if self.degs is None: + deg = [1] * len(self.vars) + else: + deg = list(self.degs) + if other.degs is None: + o_degs = [1] * len(other.vars) + else: + o_degs = list(other.degs) + self_table = {w: d for w, d in zip(self.vars, deg)} + for v, d in zip(other.vars, o_degs): + if v not in self_vars: + deg.append(d) + elif d != self_table[v]: + # incompatible degrees + return None + return AssociativeFunctor(tuple(ret), tuple(deg)) + + return None + + def _repr_(self) -> str: + """ + TESTS:: + + sage: algebras.Free(QQ,4,'x,y,z,t').construction()[0] + Associative[x,y,z,t] + sage: algebras.Free(QQ,4,'x,y,z,t',degrees=(1,2,3,4)).construction()[0] + Associative[x,y,z,t] with degrees {x: 1, y: 2, z: 3, t: 4} + """ + vars = ','.join(self.vars) + if self.degs is None: + return f"Associative[{vars}]" + return f"Associative[{vars}] with degrees {self.degs}" diff --git a/src/sage/algebras/free_algebra_quotient_element.py b/src/sage/algebras/free_algebra_quotient_element.py index b594cc65dec..640c868617f 100644 --- a/src/sage/algebras/free_algebra_quotient_element.py +++ b/src/sage/algebras/free_algebra_quotient_element.py @@ -142,7 +142,7 @@ def _repr_(self): return repr_lincomb(zip(mons, cffs), strip_one=True) def _latex_(self): - """ + r""" EXAMPLES:: sage: H, (i,j,k) = sage.algebras.free_algebra_quotient.hamilton_quatalg(QQ) diff --git a/src/sage/algebras/fusion_rings/f_matrix.py b/src/sage/algebras/fusion_rings/f_matrix.py index b832a520fec..e48a89fc664 100644 --- a/src/sage/algebras/fusion_rings/f_matrix.py +++ b/src/sage/algebras/fusion_rings/f_matrix.py @@ -1991,7 +1991,7 @@ def _get_explicit_solution(self, eqns=None, verbose=True): def find_orthogonal_solution(self, checkpoint=False, save_results='', warm_start='', use_mp=True, verbose=True): r""" - Solve the the hexagon and pentagon relations, along with + Solve the hexagon and pentagon relations, along with orthogonality constraints, to evaluate an orthogonal F-matrix. INPUT: diff --git a/src/sage/algebras/fusion_rings/fusion_ring.py b/src/sage/algebras/fusion_rings/fusion_ring.py index 56045d2dce6..e454b07dfcb 100644 --- a/src/sage/algebras/fusion_rings/fusion_ring.py +++ b/src/sage/algebras/fusion_rings/fusion_ring.py @@ -1564,15 +1564,14 @@ def q_dimension(self, base_coercion=True): R = ZZ['q'] q = R.gen() expr = R.fraction_field().one() - for val in powers: - exp = powers[val] + for val, exp in powers.items(): if exp > 0: expr *= q_int(P._nf * val, q)**exp elif exp < 0: expr /= q_int(P._nf * val, q)**(-exp) expr = R(expr) - expr = expr.substitute(q=q**4) / (q**(2*expr.degree())) - zet = P.field().gen() ** (P._cyclotomic_order/P._l) + expr = expr.substitute(q=q**4) / (q**(2 * expr.degree())) + zet = P.field().gen() ** (P._cyclotomic_order / P._l) ret = expr.substitute(q=zet) if (not base_coercion) or (self.parent()._basecoer is None): diff --git a/src/sage/algebras/fusion_rings/meson.build b/src/sage/algebras/fusion_rings/meson.build index 281460a066a..221cce6146e 100644 --- a/src/sage/algebras/fusion_rings/meson.build +++ b/src/sage/algebras/fusion_rings/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'f_matrix.py', 'fast_parallel_fmats_methods.pxd', diff --git a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py index 8d674d0aaf1..e6368ea8389 100644 --- a/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py +++ b/src/sage/algebras/hecke_algebras/ariki_koike_algebra.py @@ -954,9 +954,8 @@ def _product_LTwTv(self, L, w, v): ret = {v: self.base_ring().one()} qm1 = self._q - self.base_ring().one() for i in reversed(w.reduced_word()): - temp = {} # start from 0 - for p in ret: - c = ret[p] + temp = {} # start from 0 + for p, c in ret.items(): # We have to flip the side due to Sage's # convention for multiplying permutations pi = p.apply_simple_reflection(i, side='left') @@ -965,7 +964,7 @@ def _product_LTwTv(self, L, w, v): else: iaxpy(1, {pi: c}, temp) ret = temp - return {(L, p): ret[p] for p in ret} + return {(L, p): c for p, c in ret.items()} def _product_Tw_L(self, w, L): r""" @@ -1011,10 +1010,9 @@ def _product_Tw_L(self, w, L): q = self._q one = q.parent().one() for i in w.reduced_word()[::-1]: - iL = {} # this will become T_i * L, written in standard form - for lv in wL: - c = wL[lv] - L = list(lv[0]) # make a copy + iL = {} # this will become T_i * L, written in standard form + for lv, c in wL.items(): + L = list(lv[0]) # make a copy v = lv[1] a, b = L[i-1], L[i] L[i-1], L[i] = L[i], L[i-1] # swap L_i=L[i-1] and L_{i+1}=L[i] @@ -1038,7 +1036,7 @@ def _product_Tw_L(self, w, L): c *= (one - q) iaxpy(1, {(tuple(l), v): c for l in Ls}, iL) - wL = iL # replace wL with iL and repeat + wL = iL # replace wL with iL and repeat return self._from_dict(wL, remove_zeros=False, coerce=False) @cached_method diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index 9aa6fa63ff2..514d9b035d7 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -352,7 +352,7 @@ def matrix(self, subdivide=False, representation_type=None, original=False): [(-2*a + u)*b - 2*a^2 + 2*u*a - v b 0] [ b 1 a] - using the the ``representation_type`` option:: + using the ``representation_type`` option:: sage: CHA3. = algebras.CubicHecke(3) # optional gap3 sage: chevie = CHA3.repr_type.SplitIrredChevie # optional gap3 @@ -364,7 +364,7 @@ def matrix(self, subdivide=False, representation_type=None, original=False): [ b 0] [a^2 - u*a + v -b - a + u] - using the the ``original`` option:: + using the ``original`` option:: sage: c0mo = c0.matrix(original=True) sage: c0mo_ch = c0.matrix(representation_type=chevie, original=True) # optional gap3 @@ -1116,7 +1116,6 @@ def check_base_ring_embedding(base_ring_embedding): # initializing the basis extension (in case of more than 4 strands) # ---------------------------------------------------------------------- self._init_basis_extension() - return ############################################################################ # -------------------------------------------------------------------------- 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 b980e2fa80c..1b011c68c61 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -105,8 +105,6 @@ def register_ring_hom(ring_hom): except ValueError: verbose('\nthe map:\n%s\ncannot be registered as conversion\n' % ring_hom) - return - # ----------------------------------------------------------------------------- # class for the Galois Group action on the generic extension ring corresponding @@ -683,7 +681,7 @@ def create_specialization(self, im_cubic_equation_roots, im_writhe_parameter=Non if len(cyclotomic_roots) > 0: E3 = cyclotomic_roots[0] - verbose('thrird root of unity %s found in %s' % (E3, E3.parent()), level=2) + verbose('third root of unity %s found in %s' % (E3, E3.parent()), level=2) if E3 is None: raise RuntimeError('cannot find a ring containing a third root of unity for the this choice of cubic roots!') @@ -1005,11 +1003,10 @@ def __init__(self, names=('u', 'v', 'w', 's'), order='degrevlex', markov_trace_v # Init of data used on demand # ---------------------------------------------------------------------- self._mirror = None - return - ############################################################################ + # ######################################################################## # overloaded inherited methods - ############################################################################ + # ######################################################################## def _defining_names(self): r""" Return the generators of ``self`` as the defining names. diff --git a/src/sage/algebras/iwahori_hecke_algebra.py b/src/sage/algebras/iwahori_hecke_algebra.py index 01390f1a5a4..ecc6788979b 100644 --- a/src/sage/algebras/iwahori_hecke_algebra.py +++ b/src/sage/algebras/iwahori_hecke_algebra.py @@ -766,7 +766,7 @@ def is_field(self, proof=True): """ return False - def is_commutative(self): + def is_commutative(self) -> bool: """ Return whether this Iwahori-Hecke algebra is commutative. diff --git a/src/sage/algebras/letterplace/meson.build b/src/sage/algebras/letterplace/meson.build index 1ada90927a7..3e429eb420a 100644 --- a/src/sage/algebras/letterplace/meson.build +++ b/src/sage/algebras/letterplace/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'free_algebra_element_letterplace.pxd', 'free_algebra_letterplace.pxd', diff --git a/src/sage/algebras/lie_algebras/bgg_dual_module.py b/src/sage/algebras/lie_algebras/bgg_dual_module.py index c4e060131da..854c62ea5ac 100644 --- a/src/sage/algebras/lie_algebras/bgg_dual_module.py +++ b/src/sage/algebras/lie_algebras/bgg_dual_module.py @@ -172,7 +172,7 @@ def _repr_generator(self, m): return self._module._repr_generator(m) + "^*" def _latex_generator(self, m): - """ + r""" Return a latex representation of the generator indexed by ``m``. EXAMPLES:: diff --git a/src/sage/algebras/lie_algebras/free_lie_algebra.py b/src/sage/algebras/lie_algebras/free_lie_algebra.py index f5217231263..e841be77a59 100644 --- a/src/sage/algebras/lie_algebras/free_lie_algebra.py +++ b/src/sage/algebras/lie_algebras/free_lie_algebra.py @@ -202,7 +202,7 @@ def _construct_UEA(self): Free Algebra on 2 generators (x, y) over Rational Field sage: L. = LieAlgebra(QQ) sage: L._construct_UEA() - Free Algebra on 1 generators (x,) over Rational Field + Free Algebra on 1 generator (x,) over Rational Field """ return FreeAlgebra(self.base_ring(), len(self._names), self._names) diff --git a/src/sage/algebras/lie_algebras/meson.build b/src/sage/algebras/lie_algebras/meson.build index f50959cb44b..754d8729fbb 100644 --- a/src/sage/algebras/lie_algebras/meson.build +++ b/src/sage/algebras/lie_algebras/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'abelian.py', 'affine_lie_algebra.py', 'all.py', diff --git a/src/sage/algebras/lie_algebras/verma_module.py b/src/sage/algebras/lie_algebras/verma_module.py index 01320616c5a..71ea8e68cb9 100644 --- a/src/sage/algebras/lie_algebras/verma_module.py +++ b/src/sage/algebras/lie_algebras/verma_module.py @@ -701,21 +701,23 @@ def _homogeneous_component_f(self, d): """ if not d: return frozenset([self.highest_weight_vector()]) - f = {i: self._pbw(g) for i,g in enumerate(self._g.f())} - basis = d.parent().basis() # Standard basis vectors + f = {i: self._pbw(g) for i, g in enumerate(self._g.f())} + basis = d.parent().basis() # Standard basis vectors ret = set() def degree(m): m = m.dict() if not m: return d.parent().zero() - return sum(e * self._g.degree_on_basis(k) for k,e in m.items()).to_vector() - for i in f: + return sum(e * self._g.degree_on_basis(k) + for k, e in m.items()).to_vector() + for i, fi in f.items(): if d[i] == 0: continue for b in self._homogeneous_component_f(d + basis[i]): - temp = f[i] * b - ret.update([self.monomial(m) for m in temp.support() if degree(m) == d]) + temp = fi * b + ret.update([self.monomial(m) for m in temp.support() + if degree(m) == d]) return frozenset(ret) def _Hom_(self, Y, category=None, **options): diff --git a/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py index 6027dee4a95..3cfa3343d80 100644 --- a/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/abelian_lie_conformal_algebra.py @@ -89,16 +89,17 @@ def __init__(self, R, ngens=1, weights=None, names = 'a' self._latex_names = tuple(r'a_{%d}' % i for i in range(ngens)) - names,index_set = standardize_names_index_set(names=names, - index_set=index_set, - ngens=ngens) + names, index_set = standardize_names_index_set(names=names, + index_set=index_set, + ngens=ngens) abeliandict = {} GradedLieConformalAlgebra.__init__(self, R, abeliandict, names=names, - index_set=index_set, weights=weights, + index_set=index_set, + weights=weights, parity=parity) - def _repr_(self): + def _repr_(self) -> str: """ String representation. diff --git a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py index e9f697e8257..66d4fe6da5c 100644 --- a/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/affine_lie_conformal_algebra.py @@ -142,7 +142,7 @@ def cartan_type(self): """ return self._ct - def _repr_(self): + def _repr_(self) -> str: """ The name of this Lie conformal algebra. @@ -152,4 +152,4 @@ def _repr_(self): The affine Lie conformal algebra of type ['A', 1] over Rational Field """ return "The affine Lie conformal algebra of type {} over {}".format( - self._ct,self.base_ring()) + self._ct, self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py index 2e689ee4c60..a3db3b8334e 100644 --- a/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/bosonic_ghosts_lie_conformal_algebra.py @@ -120,7 +120,7 @@ def __init__(self, R, ngens=2, names=None, index_set=None): weights=weights, central_elements=('K',)) - def _repr_(self): + def _repr_(self) -> str: """ String representation. @@ -130,4 +130,4 @@ def _repr_(self): The Bosonic ghosts Lie conformal algebra with generators (beta, gamma, K) over Algebraic Field """ return "The Bosonic ghosts Lie conformal algebra with generators {} "\ - "over {}".format(self.gens(),self.base_ring()) + "over {}".format(self.gens(), self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py index 6c4418e4751..787310885c3 100644 --- a/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/fermionic_ghosts_lie_conformal_algebra.py @@ -117,7 +117,7 @@ def __init__(self, R, ngens=2, names=None, index_set=None): parity=parity, central_elements=('K',)) - def _repr_(self): + def _repr_(self) -> str: """ String representation. @@ -127,4 +127,4 @@ def _repr_(self): The Fermionic ghosts Lie conformal algebra with generators (b, c, K) over Rational Field """ return "The Fermionic ghosts Lie conformal algebra with generators {} "\ - "over {}".format(self.gens(),self.base_ring()) + "over {}".format(self.gens(), self.base_ring()) diff --git a/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py index e66489d49ca..215cabd83e8 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_bosons_lie_conformal_algebra.py @@ -114,37 +114,39 @@ def __init__(self, R, ngens=None, gram_matrix=None, names=None, if ngens is None: ngens = gram_matrix.dimensions()[0] try: - assert (gram_matrix in MatrixSpace(R,ngens,ngens)) + assert (gram_matrix in MatrixSpace(R, ngens, ngens)) except AssertionError: raise ValueError("the gram_matrix should be a symmetric " + - "{0} x {0} matrix, got {1}".format(ngens,gram_matrix)) + "{0} x {0} matrix, got {1}".format(ngens, gram_matrix)) if not gram_matrix.is_symmetric(): raise ValueError("the gram_matrix should be a symmetric " + - "{0} x {0} matrix, got {1}".format(ngens,gram_matrix)) + "{0} x {0} matrix, got {1}".format(ngens, gram_matrix)) else: if ngens is None: ngens = 1 gram_matrix = identity_matrix(R, ngens, ngens) latex_names = None - if (names is None) and (index_set is None): + if names is None and index_set is None: names = 'alpha' latex_names = tuple(r'\alpha_{%d}' % i for i in range(ngens)) + ('K',) - names,index_set = standardize_names_index_set(names=names, - index_set=index_set, - ngens=ngens) - bosondict = {(i,j): {1: {('K',0): gram_matrix[index_set.rank(i), - index_set.rank(j)]}} for i in index_set for j in index_set} - - GradedLieConformalAlgebra.__init__(self,R,bosondict,names=names, + names, index_set = standardize_names_index_set(names=names, + index_set=index_set, + ngens=ngens) + bosondict = {(i, j): {1: {('K', 0): gram_matrix[index_set.rank(i), + index_set.rank(j)]}} + for i in index_set for j in index_set} + + GradedLieConformalAlgebra.__init__(self, R, bosondict, + names=names, latex_names=latex_names, index_set=index_set, central_elements=('K',)) self._gram_matrix = gram_matrix - def _repr_(self): + def _repr_(self) -> str: """ String representation. @@ -154,7 +156,7 @@ def _repr_(self): The free Bosons Lie conformal algebra with generators (alpha, K) over Algebraic Real Field """ return "The free Bosons Lie conformal algebra with generators {}"\ - " over {}".format(self.gens(),self.base_ring()) + " over {}".format(self.gens(), self.base_ring()) def gram_matrix(self): r""" diff --git a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py index 40810602ac4..32d8f65e8d9 100644 --- a/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/free_fermions_lie_conformal_algebra.py @@ -94,17 +94,17 @@ def __init__(self, R, ngens=None, gram_matrix=None, names=None, """ from sage.matrix.matrix_space import MatrixSpace from sage.matrix.special import identity_matrix - if (gram_matrix is not None): + if gram_matrix is not None: if ngens is None: ngens = gram_matrix.dimensions()[0] try: - assert (gram_matrix in MatrixSpace(R,ngens,ngens)) + assert (gram_matrix in MatrixSpace(R, ngens, ngens)) except AssertionError: raise ValueError("The gram_matrix should be a symmetric " + - "{0} x {0} matrix, got {1}".format(ngens,gram_matrix)) + "{0} x {0} matrix, got {1}".format(ngens, gram_matrix)) if not gram_matrix.is_symmetric(): raise ValueError("The gram_matrix should be a symmetric " + - "{0} x {0} matrix, got {1}".format(ngens,gram_matrix)) + "{0} x {0} matrix, got {1}".format(ngens, gram_matrix)) else: if ngens is None: ngens = 1 @@ -112,34 +112,33 @@ def __init__(self, R, ngens=None, gram_matrix=None, names=None, latex_names = None - if (names is None) and (index_set is None): - if ngens == 1: - names = 'psi' - else: - names = 'psi_' + if names is None and index_set is None: + names = 'psi' if ngens == 1 else 'psi_' latex_names = tuple(r"\psi_{%d}" % i for i in range(ngens)) + ('K',) from sage.structure.indexed_generators import \ - standardize_names_index_set - names,index_set = standardize_names_index_set(names=names, - index_set=index_set, - ngens=ngens) - fermiondict = {(i,j): {0: {('K', 0): gram_matrix[index_set.rank(i), - index_set.rank(j)]}} for i in index_set for j in index_set} + standardize_names_index_set + names, index_set = standardize_names_index_set(names=names, + index_set=index_set, + ngens=ngens) + fermiondict = {(i, j): {0: {('K', 0): gram_matrix[index_set.rank(i), + index_set.rank(j)]}} + for i in index_set for j in index_set} from sage.rings.rational_field import QQ - weights = (QQ(1/2),)*ngens - parity = (1,)*ngens - GradedLieConformalAlgebra.__init__(self,R,fermiondict,names=names, + weights = (QQ((1, 2)),) * ngens + parity = (1,) * ngens + GradedLieConformalAlgebra.__init__(self, R, fermiondict, names=names, latex_names=latex_names, - index_set=index_set,weights=weights, + index_set=index_set, + weights=weights, parity=parity, central_elements=('K',)) self._gram_matrix = gram_matrix - def _repr_(self): + def _repr_(self) -> str: """ String representation. @@ -149,8 +148,8 @@ def _repr_(self): The free Fermions super Lie conformal algebra with generators (psi, K) over Rational Field """ return "The free Fermions super Lie conformal algebra "\ - "with generators {} over {}".format(self.gens(), - self.base_ring()) + "with generators {} over {}".format(self.gens(), + self.base_ring()) def gram_matrix(self): r""" diff --git a/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py index 0b77dd91854..803c2997271 100644 --- a/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/freely_generated_lie_conformal_algebra.py @@ -81,8 +81,8 @@ def lie_conformal_algebra_generators(self): (B[alpha[1]], B[alphacheck[1]], B[-alpha[1]], B['K']) """ F = Family(self._generators, - lambda i: self.monomial((i,Integer(0))), - name="generator map") + lambda i: self.monomial((i, Integer(0))), + name="generator map") from sage.categories.sets_cat import Sets if F in Sets().Finite(): return tuple(F) diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py index 528a587d795..9248927e242 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra.py @@ -331,7 +331,7 @@ def __classcall_private__(cls, R=None, arg0=None, index_set=None, if key not in known_keywords: raise ValueError("got an unexpected keyword argument '%s'" % key) - if isinstance(arg0,dict) and arg0: + if isinstance(arg0, dict) and arg0: graded = kwds.pop("graded", False) if weights is not None or graded: from .graded_lie_conformal_algebra import \ diff --git a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py index 3cb8f645cd5..2e7f31cee27 100644 --- a/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py +++ b/src/sage/algebras/lie_conformal_algebras/lie_conformal_algebra_with_structure_coefs.py @@ -87,9 +87,11 @@ class LieConformalAlgebraWithStructureCoefficients( `\lambda`-brackets of the generators:: sage: betagamma_dict = {('b','a'):{0:{('K',0):1}}} - sage: V = LieConformalAlgebra(QQ, betagamma_dict, names=('a','b'), weights=(1,0), central_elements=('K',)) + sage: V = LieConformalAlgebra(QQ, betagamma_dict, names=('a','b'), + ....: weights=(1,0), central_elements=('K',)) sage: V.category() - Category of H-graded finitely generated Lie conformal algebras with basis over Rational Field + Category of H-graded finitely generated Lie conformal algebras + with basis over Rational Field sage: V.inject_variables() Defining a, b, K sage: a.bracket(b) @@ -148,9 +150,8 @@ def _standardize_s_coeff(s_coeff, index_set, ce, parity=None): index_to_parity = dict(zip(index_set, parity)) sc = {} # mypair has a pair of generators - for mypair in s_coeff.keys(): + for mypair, v in s_coeff.items(): # e.g. v = { 0: { (L,2):3, (G,3):1}, 1:{(L,1),2} } - v = s_coeff[mypair] key = tuple(mypair) vals = {} for l in v: @@ -186,7 +187,7 @@ def _standardize_s_coeff(s_coeff, index_set, ce, parity=None): kth_product[(i[0], i[1] + j)] = \ kth_product.get((i[0], i[1] + j), 0) kth_product[(i[0], i[1] + j)] += parsgn *\ - v[k+j][i]*(-1)**(k+j+1)*binomial(i[1]+j,j) + v[k+j][i]*(-1)**(k+j+1)*binomial(i[1]+j, j) kth_product = {k: v for k, v in kth_product.items() if v} if kth_product: vals[k] = kth_product @@ -212,7 +213,7 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) sage: TestSuite(V).run() """ - names, index_set = standardize_names_index_set(names,index_set) + names, index_set = standardize_names_index_set(names, index_set) if central_elements is None: central_elements = () @@ -220,13 +221,14 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, names2 = names + tuple(central_elements) index_set2 = DisjointUnionEnumeratedSets((index_set, Family(tuple(central_elements)))) - d = {x:index_set2[i] for i,x in enumerate(names2)} + d = {x: index_set2[i] for i, x in enumerate(names2)} try: - #If we are given a dictionary with names as keys, - #convert to index_set as keys - s_coeff = {(d[k[0]],d[k[1]]):{a:{(d[x[1]],x[2]): - s_coeff[k][a][x] for x in - s_coeff[k][a]} for a in s_coeff[k]} for k in s_coeff.keys()} + # If we are given a dictionary with names as keys, + # convert to index_set as keys + s_coeff = {(d[k[0]], d[k[1]]): + {a: {(d[x[1]], x[2]): sck[a][x] for x in sck[a]} + for a in s_coeff[k]} + for k, sck in s_coeff.items()} except KeyError: # We assume the dictionary was given with keys in the @@ -274,9 +276,12 @@ def __init__(self, R, s_coeff, index_set=None, central_elements=None, prefix=prefix, names=names, latex_names=latex_names, **kwds) s_coeff = dict(s_coeff) - self._s_coeff = Family({k: tuple((j, sum(c*self.monomial(i) - for i,c in v)) for j,v in s_coeff[k]) for k in s_coeff}) - self._parity = dict(zip(self.gens(),parity+(0,)*len(central_elements))) + self._s_coeff = Family({k: + tuple((j, sum(c * self.monomial(i) + for i, c in v)) for j, v in sck) + for k, sck in s_coeff.items()}) + self._parity = dict(zip(self.gens(), + parity + (0,) * len(central_elements))) def structure_coefficients(self): """ @@ -289,11 +294,14 @@ def structure_coefficients(self): Finite family {('L', 'L'): ((0, TL), (1, 2*L), (3, 1/2*C))} sage: lie_conformal_algebras.NeveuSchwarz(QQ).structure_coefficients() - Finite family {('G', 'G'): ((0, 2*L), (2, 2/3*C)), ('G', 'L'): ((0, 1/2*TG), (1, 3/2*G)), ('L', 'G'): ((0, TG), (1, 3/2*G)), ('L', 'L'): ((0, TL), (1, 2*L), (3, 1/2*C))} + Finite family {('G', 'G'): ((0, 2*L), (2, 2/3*C)), + ('G', 'L'): ((0, 1/2*TG), (1, 3/2*G)), + ('L', 'G'): ((0, TG), (1, 3/2*G)), + ('L', 'L'): ((0, TL), (1, 2*L), (3, 1/2*C))} """ return self._s_coeff - def _repr_generator(self, x): + def _repr_generator(self, x) -> str: """ String representation of the generator ``x``. @@ -316,4 +324,4 @@ def _repr_generator(self, x): """ if x in self: return repr(x) - return IndexedGenerators._repr_generator(self,x) + return IndexedGenerators._repr_generator(self, x) diff --git a/src/sage/algebras/meson.build b/src/sage/algebras/meson.build index a7e74474c6b..bad93c41abf 100644 --- a/src/sage/algebras/meson.build +++ b/src/sage/algebras/meson.build @@ -1,6 +1,6 @@ py.install_sources( + '__init__.py', 'affine_nil_temperley_lieb.py', - 'algebra.py', 'all.py', 'askey_wilson.py', 'associated_graded.py', diff --git a/src/sage/algebras/quantum_groups/fock_space.py b/src/sage/algebras/quantum_groups/fock_space.py index d1d98d3c184..605ed217f2f 100644 --- a/src/sage/algebras/quantum_groups/fock_space.py +++ b/src/sage/algebras/quantum_groups/fock_space.py @@ -1751,7 +1751,7 @@ def __init__(self, F): self._removable = lambda la,i: [x for x in la.corners() if la.content(*x, multicharge=F._multicharge) == i] - indices = Partitions(F._n, max_length=F._k) + indices = Partitions(max_length=F._k) CombinatorialFreeModule.__init__(self, F.base_ring(), indices, prefix='', bracket=['|', '>'], latex_bracket=['\\lvert', '\\rangle'], diff --git a/src/sage/algebras/quatalg/meson.build b/src/sage/algebras/quatalg/meson.build index 2ec5cd31f22..25c4adfc46c 100644 --- a/src/sage/algebras/quatalg/meson.build +++ b/src/sage/algebras/quatalg/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'quaternion_algebra.py', 'quaternion_algebra_element.pxd', diff --git a/src/sage/algebras/rational_cherednik_algebra.py b/src/sage/algebras/rational_cherednik_algebra.py index 1ded26a1112..537f39e8f68 100644 --- a/src/sage/algebras/rational_cherednik_algebra.py +++ b/src/sage/algebras/rational_cherednik_algebra.py @@ -369,18 +369,19 @@ def commute_w_hd(w, al): # al is given as a dictionary # so we must commute Lac Rs = Rs Lac' # and obtain La (Ls Rs) (Lac' Rac) ret = P.one() - for k in dl: + r1_red = right[1].reduced_word() + for k, dlk in dl.items(): x = sum(c * gens_dict[i] - for i,c in alphacheck[k].weyl_action(right[1].reduced_word(), - inverse=True)) - ret *= x**dl[k] + for i, c in alphacheck[k].weyl_action(r1_red, + inverse=True)) + ret *= x**dlk ret = ret.monomial_coefficients() - w = left[1]*right[1] + w = left[1] * right[1] return self._from_dict({(left[0], w, - self._h({I[i]: e for i,e in enumerate(k) - if e != 0}) * right[2] + self._h({I[i]: e for i, e in enumerate(k) + if e != 0}) * right[2] ): ret[k] - for k in ret}) + for k in ret}) # Otherwise dr is non-trivial and we have La Ls Ra Rs Rac, # so we must commute Ls Ra = Ra' Ls diff --git a/src/sage/algebras/splitting_algebra.py b/src/sage/algebras/splitting_algebra.py index 43d72ed7470..eac48c03dfb 100644 --- a/src/sage/algebras/splitting_algebra.py +++ b/src/sage/algebras/splitting_algebra.py @@ -102,7 +102,7 @@ def is_unit(self): return super().is_unit() - def monomial_coefficients(self): + def monomial_coefficients(self, copy=True): r""" Return the dictionary of ``self`` according to its lift to the cover. @@ -119,13 +119,15 @@ def monomial_coefficients(self): sage: f.dict() {0: 42, 1: 1} """ - return self.lift().monomial_coefficients() + return self.lift().monomial_coefficients(copy=copy) dict = monomial_coefficients # ------------------------------------------------------------------------------------------------------------------ # Parent class of the splitting algebra # -------------------------------------------------------------------------------------------------------- + + class SplittingAlgebra(PolynomialQuotientRing_domain): r""" For a given monic polynomial `p(t)` of degree `n` over a commutative diff --git a/src/sage/algebras/steenrod/steenrod_algebra.py b/src/sage/algebras/steenrod/steenrod_algebra.py index 540cb6ee92d..e9b86a59098 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra.py +++ b/src/sage/algebras/steenrod/steenrod_algebra.py @@ -1346,10 +1346,9 @@ def coprod_list(t): right_q = sorted(all_q - a) sign = Permutation(convert_perm(left_q + right_q)).signature() tens_q[(tuple(left_q), tuple(right_q))] = sign - tens = {} - for l, r in zip(left_p, right_p): - for q in tens_q: - tens[((q[0], l), (q[1], r))] = tens_q[q] + tens = {((q[0], l), (q[1], r)): tq + for l, r in zip(left_p, right_p) + for q, tq in tens_q.items()} return self.tensor_square()._from_dict(tens, coerce=True) elif basis == 'serre-cartan': result = self.tensor_square().one() @@ -2827,10 +2826,12 @@ def gen(self, i=0): tot += 1 return test - def is_commutative(self): + def is_commutative(self) -> bool: r""" Return ``True`` if ``self`` is graded commutative, as determined by the - profile function. In particular, a sub-Hopf algebra of the + profile function. + + In particular, a sub-Hopf algebra of the mod 2 Steenrod algebra is commutative if and only if there is an integer `n>0` so that its profile function `e` satisfies diff --git a/src/sage/algebras/steenrod/steenrod_algebra_misc.py b/src/sage/algebras/steenrod/steenrod_algebra_misc.py index 1bf8e278502..1aeeab27050 100644 --- a/src/sage/algebras/steenrod/steenrod_algebra_misc.py +++ b/src/sage/algebras/steenrod/steenrod_algebra_misc.py @@ -567,7 +567,7 @@ def normalize_profile(profile, precision=None, truncation_type='auto', p=2, gene def milnor_mono_to_string(mono, latex=False, generic=False): - """ + r""" String representation of element of the Milnor basis. This is used by the _repr_ and _latex_ methods. @@ -720,7 +720,7 @@ def serre_cartan_mono_to_string(mono, latex=False, generic=False): def wood_mono_to_string(mono, latex=False): - """ + r""" String representation of element of Wood's Y and Z bases. This is used by the _repr_ and _latex_ methods. @@ -806,7 +806,7 @@ def wall_mono_to_string(mono, latex=False): def wall_long_mono_to_string(mono, latex=False): - """ + r""" Alternate string representation of element of Wall's basis. This is used by the _repr_ and _latex_ methods. @@ -891,7 +891,7 @@ def arnonA_mono_to_string(mono, latex=False, p=2): def arnonA_long_mono_to_string(mono, latex=False, p=2): - """ + r""" Alternate string representation of element of Arnon's A basis. This is used by the _repr_ and _latex_ methods. diff --git a/src/sage/algebras/weyl_algebra.py b/src/sage/algebras/weyl_algebra.py index 8eae4797c7d..b5554d901f5 100644 --- a/src/sage/algebras/weyl_algebra.py +++ b/src/sage/algebras/weyl_algebra.py @@ -21,7 +21,6 @@ from sage.misc.latex import latex, LatexExpr from sage.misc.lazy_attribute import lazy_attribute from sage.misc.misc_c import prod -from sage.structure.element import Element from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.categories.action import Action @@ -29,7 +28,7 @@ from sage.categories.algebras_with_basis import AlgebrasWithBasis from sage.sets.family import Family import sage.data_structures.blas_dict as blas -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.global_options import GlobalOptions @@ -677,7 +676,7 @@ def __classcall__(cls, R, names=None): sage: W1 is W2 True """ - if isinstance(R, (PolynomialRing_general, MPolynomialRing_base)): + if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): if names is None: names = R.variable_names() R = R.base_ring() diff --git a/src/sage/algebras/yokonuma_hecke_algebra.py b/src/sage/algebras/yokonuma_hecke_algebra.py index 7de8ff07798..f8e8f724adc 100644 --- a/src/sage/algebras/yokonuma_hecke_algebra.py +++ b/src/sage/algebras/yokonuma_hecke_algebra.py @@ -447,13 +447,17 @@ def inverse_g(self, i): sage: Y = algebras.YokonumaHecke(2, 4) sage: [2*Y.inverse_g(i) for i in range(1, 4)] - [(q^-1+q) + 2*g[1] + (q^-1+q)*t1*t2, - (q^-1+q) + 2*g[2] + (q^-1+q)*t2*t3, - (q^-1+q) + 2*g[3] + (q^-1+q)*t3*t4] + [(q^-1-q) + 2*g[1] + (q^-1-q)*t1*t2, + (q^-1-q) + 2*g[2] + (q^-1-q)*t2*t3, + (q^-1-q) + 2*g[3] + (q^-1-q)*t3*t4] + sage: all(Y.inverse_g(i) * Y.g(i) == Y.one() for i in range(1, 4)) + True + sage: all(Y.g(i) * Y.inverse_g(i) == Y.one() for i in range(1, 4)) + True """ if i < 1 or i >= self._n: raise ValueError("invalid index") - return self.g(i) + (~self._q + self._q) * self.e(i) + return self.g(i) + (~self._q - self._q) * self.e(i) class Element(CombinatorialFreeModule.Element): def __invert__(self): @@ -468,10 +472,15 @@ def __invert__(self): sage: t.inverse() # indirect doctest t1^2*t2^2*t3^2 sage: [3*~(t*g) for g in Y.g()] - [(q^-1+q)*t2*t3^2 + (q^-1+q)*t1*t3^2 - + (q^-1+q)*t1^2*t2^2*t3^2 + 3*t1^2*t2^2*t3^2*g[1], - (q^-1+q)*t1^2*t3 + (q^-1+q)*t1^2*t2 - + (q^-1+q)*t1^2*t2^2*t3^2 + 3*t1^2*t2^2*t3^2*g[2]] + [(q^-1-q)*t2*t3^2 + (q^-1-q)*t1*t3^2 + + (q^-1-q)*t1^2*t2^2*t3^2 + 3*t1^2*t2^2*t3^2*g[1], + (q^-1-q)*t1^2*t3 + (q^-1-q)*t1^2*t2 + + (q^-1-q)*t1^2*t2^2*t3^2 + 3*t1^2*t2^2*t3^2*g[2]] + sage: g = prod(Y.g()) + sage: ~g * g == Y.one() + True + sage: g * ~g == Y.one() + True TESTS: diff --git a/src/sage/arith/meson.build b/src/sage/arith/meson.build index 3c3656c5738..500b49edf85 100644 --- a/src/sage/arith/meson.build +++ b/src/sage/arith/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'all__sagemath_objects.py', 'constants.pxd', diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index 14fe466ccd9..637ed9192bd 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -6375,6 +6375,7 @@ def dedekind_psi(N): N = Integer(N) return Integer(N * prod(1 + 1 / p for p in N.prime_divisors())) + def smooth_part(x, base): r""" Given an element ``x`` of a Euclidean domain and a factor base ``base``, @@ -6423,6 +6424,7 @@ def smooth_part(x, base): from sage.structure.factorization import Factorization return Factorization(fs) + def coprime_part(x, base): r""" Given an element ``x`` of a Euclidean domain and a factor base ``base``, diff --git a/src/sage/calculus/calculus.py b/src/sage/calculus/calculus.py index ef4854db676..64881aba812 100644 --- a/src/sage/calculus/calculus.py +++ b/src/sage/calculus/calculus.py @@ -387,6 +387,7 @@ Ensure that :issue:`25626` is fixed. As the form of the answer is dependent of the giac version, we simplify it (see :issue:`34037`):: + sage: # needs sage.libs.giac sage: t = SR.var('t') sage: integrate(exp(t)/(t + 1)^2, t, algorithm='giac').full_simplify() ((t + 1)*Ei(t + 1) - e^(t + 1))/(t*e + e) diff --git a/src/sage/calculus/desolvers.py b/src/sage/calculus/desolvers.py index d17f5a14e90..6a8d8fbe2bb 100644 --- a/src/sage/calculus/desolvers.py +++ b/src/sage/calculus/desolvers.py @@ -741,7 +741,7 @@ def desolve_laplace(de, dvar, ics=None, ivar=None): # maxima("de:"+de._repr_()+"=0;") # if ics is not None: # d = len(ics) - # for i in range(0,d-1): + # for i in range(d-1): # ic = "atvalue(diff("+vars[1]+"("+vars[0]+"),"+str(vars[0])+","+str(i)+"),"+str(vars[0])+"="+str(ics[0])+","+str(ics[1+i])+")" # maxima(ic) # diff --git a/src/sage/calculus/integration.pyx b/src/sage/calculus/integration.pyx index 179e5751894..f71695926aa 100644 --- a/src/sage/calculus/integration.pyx +++ b/src/sage/calculus/integration.pyx @@ -31,7 +31,10 @@ from cysignals.signals cimport sig_on, sig_off from memory_allocator cimport MemoryAllocator from sage.rings.real_double import RDF -from sage.libs.gsl.all cimport * +from sage.libs.gsl.errno cimport gsl_set_error_handler_off +from sage.libs.gsl.integration cimport * +from sage.libs.gsl.monte cimport * +from sage.libs.gsl.rng cimport * from sage.misc.sageinspect import sage_getargspec from sage.ext.interpreters.wrapper_rdf cimport Wrapper_rdf from sage.ext.fast_callable import fast_callable @@ -56,7 +59,13 @@ cdef double c_f(double t, void *params) noexcept: else: value = wrapper.the_function(t) except Exception as msg: - print(msg) + try: + if str(msg).strip(): + print(msg) + else: + print(f"Unable to evaluate function at {t}") + except Exception: + pass return 0 return value @@ -141,17 +150,19 @@ def numerical_integral(func, a, b=None, For a Python function with parameters:: sage: f(x,a) = 1/(a+x^2) - sage: [numerical_integral(f, 1, 2, max_points=100, params=[n]) for n in range(10)] # random output (architecture and os dependent) - [(0.49999999999998657, 5.5511151231256336e-15), - (0.32175055439664557, 3.5721487367706477e-15), - (0.24030098317249229, 2.6678768435816325e-15), - (0.19253082576711697, 2.1375215571674764e-15), - (0.16087527719832367, 1.7860743683853337e-15), - (0.13827545676349412, 1.5351659583939151e-15), - (0.12129975935702741, 1.3466978571966261e-15), - (0.10806674191683065, 1.1997818507228991e-15), - (0.09745444625548845, 1.0819617008493815e-15), - (0.088750683050217577, 9.8533051773561173e-16)] + sage: [numerical_integral(f, 1, 2, max_points=100, params=[n])[0] # abs tol 1.0e-6 + ....: for n in range(10)] + [0.5000000000000000, + 0.3217505543966422, + 0.24030098317248832, + 0.19253082576711372, + 0.1608752771983211, + 0.138275456763492, + 0.1212997593570257, + 0.10806674191683492, + 0.09745444625553161, + 0.08875068305030848] + sage: y = var('y') sage: numerical_integral(x*y, 0, 1) Traceback (most recent call last): @@ -320,6 +331,9 @@ def numerical_integral(func, a, b=None, if ell.is_numeric() and not ell.is_zero(): raise ValueError('integral does not converge at infinity') func = fast_callable(func, vars=[v], domain=float) + # `func` is now a function of one variable, + # so it no longer needs any parameters + params = [] if not isinstance(func, compiled_integrand): wrapper = PyFunctionWrapper() diff --git a/src/sage/calculus/meson.build b/src/sage/calculus/meson.build index 541d7d86d75..3bedeb2220a 100644 --- a/src/sage/calculus/meson.build +++ b/src/sage/calculus/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'calculus.py', 'desolvers.py', diff --git a/src/sage/calculus/ode.pyx b/src/sage/calculus/ode.pyx index 2addf3e7f81..80eaf228533 100644 --- a/src/sage/calculus/ode.pyx +++ b/src/sage/calculus/ode.pyx @@ -22,7 +22,8 @@ from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_on, sig_off from sage.misc.sageinspect import sage_getargspec -from sage.libs.gsl.all cimport * +from sage.libs.gsl.types cimport * +from sage.libs.gsl.odeiv cimport * import sage.calculus.interpolation diff --git a/src/sage/calculus/transforms/meson.build b/src/sage/calculus/transforms/meson.build index 05d3fb59637..11ffa9f8ec1 100644 --- a/src/sage/calculus/transforms/meson.build +++ b/src/sage/calculus/transforms/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'dft.py', 'dwt.pxd', diff --git a/src/sage/calculus/wester.py b/src/sage/calculus/wester.py index e33409a49ac..21c6865d0cb 100644 --- a/src/sage/calculus/wester.py +++ b/src/sage/calculus/wester.py @@ -484,17 +484,18 @@ sage: # (YES) Find the eigenvalues of a 3x3 integer matrix. sage: m = matrix(QQ, 3, [5,-3,-7, -2,1,2, 2,-3,-4]) sage: m.eigenspaces_left() - [ - (3, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 0 -1]), - (1, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 1 -1]), - (-2, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [0 1 1]) - ] + [(3, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 0 -1]), + (1, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 1 -1]), + (-2, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [0 1 1])] :: diff --git a/src/sage/categories/affine_weyl_groups.py b/src/sage/categories/affine_weyl_groups.py index 71dfcd2350a..b904c96319e 100644 --- a/src/sage/categories/affine_weyl_groups.py +++ b/src/sage/categories/affine_weyl_groups.py @@ -130,7 +130,7 @@ def succ(pair): if (length < k and i == u1.first_descent(side='left') and u1.is_affine_grassmannian()): yield (u1, length + 1) - return + return RecursivelyEnumeratedSet_forest(((self.one(), 0),), succ, algorithm='breadth', category=FiniteEnumeratedSets(), post_process=select_length) diff --git a/src/sage/categories/basic.py b/src/sage/categories/basic.py index cfc385513cb..30c4b0fa9e7 100644 --- a/src/sage/categories/basic.py +++ b/src/sage/categories/basic.py @@ -47,7 +47,6 @@ from sage.categories.principal_ideal_domains import PrincipalIdealDomains from sage.categories.euclidean_domains import EuclideanDomains from sage.categories.unique_factorization_domains import UniqueFactorizationDomains -from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationRings from sage.categories.fields import Fields from sage.categories.quotient_fields import QuotientFields diff --git a/src/sage/categories/bialgebras_with_basis.py b/src/sage/categories/bialgebras_with_basis.py index 10e829fd7fb..2589773dd31 100644 --- a/src/sage/categories/bialgebras_with_basis.py +++ b/src/sage/categories/bialgebras_with_basis.py @@ -402,7 +402,7 @@ def convolution_product(self, *maps): for mor in T[:-1]: # ALGORITHM: - # `split_convolve` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. + # ``split_convolve`` moves terms of the form x # y to x*Ti(y1) # y2 in Sweedler notation. def split_convolve(x_y): x, y = x_y return (((xy1, y2), c * d) diff --git a/src/sage/categories/category_types.py b/src/sage/categories/category_types.py index de62a0109f0..7f0d44c0f32 100644 --- a/src/sage/categories/category_types.py +++ b/src/sage/categories/category_types.py @@ -202,12 +202,13 @@ def _test_category_over_bases(self, **options): """ tester = self._tester(**options) from sage.categories.category_singleton import Category_singleton - + from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring from .bimodules import Bimodules from .schemes import Schemes for cat in self.super_categories(): tester.assertTrue(isinstance(cat, (Category_singleton, Category_over_base, - Bimodules, Schemes)), + CategoryWithAxiom_over_base_ring, + Bimodules, Schemes)), "The super categories of a category over base should" " be a category over base (or the related Bimodules)" " or a singleton category") @@ -458,7 +459,7 @@ def _subcategory_hook_(self, C): ....: VectorSpaces(GF(3)).parent_class) True - Check that :issue:`16618` is fixed: this `_subcategory_hook_` + Check that :issue:`16618` is fixed: this ``_subcategory_hook_`` method is only valid for :class:`Category_over_base_ring`, not :class:`Category_over_base`:: diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 014ac68d369..5e5b7ec8aff 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -2525,7 +2525,7 @@ def __init__(self, base_category): Category_over_base_ring.__init__(self, base_category.base_ring()) -class CategoryWithAxiom_singleton(Category_singleton, CategoryWithAxiom):#, Category_singleton, FastHashable_class): +class CategoryWithAxiom_singleton(Category_singleton, CategoryWithAxiom): # Category_singleton, FastHashable_class): pass diff --git a/src/sage/categories/commutative_rings.py b/src/sage/categories/commutative_rings.py index 6c47efacfe0..f67990df978 100644 --- a/src/sage/categories/commutative_rings.py +++ b/src/sage/categories/commutative_rings.py @@ -46,6 +46,17 @@ class CommutativeRings(CategoryWithAxiom): sage: GroupAlgebra(CyclicPermutationGroup(3), QQ) in CommutativeRings() # not implemented, needs sage.groups sage.modules True + + Some tests for the method ``is_commutative``:: + + sage: QQ.is_commutative() + True + sage: ZpCA(7).is_commutative() # needs sage.rings.padics + True + sage: A = QuaternionAlgebra(QQ, -1, -3, names=('i','j','k')); A # needs sage.combinat sage.modules + Quaternion Algebra (-1, -3) with base ring Rational Field + sage: A.is_commutative() # needs sage.combinat sage.modules + False """ class ParentMethods: def is_commutative(self) -> bool: diff --git a/src/sage/categories/drinfeld_modules.py b/src/sage/categories/drinfeld_modules.py index aca5675497a..1e9bd910c70 100644 --- a/src/sage/categories/drinfeld_modules.py +++ b/src/sage/categories/drinfeld_modules.py @@ -29,7 +29,7 @@ from sage.rings.integer import Integer lazy_import('sage.rings.polynomial.ore_polynomial_ring', 'OrePolynomialRing') -lazy_import('sage.rings.polynomial.polynomial_ring', 'PolynomialRing_general') +lazy_import('sage.rings.polynomial.polynomial_ring', 'PolynomialRing_generic') lazy_import('sage.rings.ring_extension', 'RingExtension_generic') @@ -251,7 +251,7 @@ def __init__(self, base_field, name='t'): self._function_ring = base_morphism.domain() # Check domain of base morphism is Fq[T] function_ring = self._function_ring - if not isinstance(function_ring, PolynomialRing_general): + if not isinstance(function_ring, PolynomialRing_generic): raise NotImplementedError('function ring must be a polynomial ' 'ring') function_ring_base = function_ring.base_ring() diff --git a/src/sage/categories/examples/meson.build b/src/sage/categories/examples/meson.build index ecb63c913ba..966962d1b7d 100644 --- a/src/sage/categories/examples/meson.build +++ b/src/sage/categories/examples/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'algebras_with_basis.py', 'all.py', 'commutative_additive_monoids.py', @@ -28,6 +29,7 @@ py.install_sources( 'monoids.py', 'posets.py', 'semigroups.py', + 'semirings.py', 'sets_cat.py', 'sets_with_grading.py', 'with_realizations.py', diff --git a/src/sage/categories/examples/semirings.py b/src/sage/categories/examples/semirings.py new file mode 100644 index 00000000000..eb5c02c2be7 --- /dev/null +++ b/src/sage/categories/examples/semirings.py @@ -0,0 +1,249 @@ +# sage_setup: distribution = sagemath-categories +r""" +Examples of semirings +""" +# **************************************************************************** +# Copyright (C) 2024 F. Chapoton +# +# Distributed under the terms of the GNU General Public License (GPL) +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.categories.semirings import Semirings +from sage.structure.element import Element +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation + +# semantic : +# 0 => 0, empty; +# 1 => 1, unique; +# 2 => at least 2 +_ADD = [[0, 1, 2], [1, 2, 2], [2, 2, 2]] +_PROD = [[0, 0, 0], [0, 1, 2], [0, 2, 2]] + + +class Ternary(Element): + """ + Elements of the ternary-logic ring. + + The semantic is as follows: + + - 0 -- the integer 0 + - 1 -- the integer 1 + - 2 -- some integer greater than 1 + + An alternative semantic is: + + - 0 -- an empty set + - 1 -- a connected set + - 2 -- a disconnected set + + The same semantic works for graphs instead of sets. + """ + def __init__(self, parent, n): + """ + Initialize one element. + + TESTS:: + + sage: from sage.categories.examples.semirings import TernaryLogic + sage: S = TernaryLogic() + sage: S(4) + Traceback (most recent call last): + ... + ValueError: input not in (0,1,2) + """ + if n not in [0, 1, 2]: + raise ValueError("input not in (0,1,2)") + self._n = n + Element.__init__(self, parent) + + def _repr_(self): + """ + Return the string representation. + + TESTS:: + + sage: from sage.categories.examples.semirings import TernaryLogic + sage: S = TernaryLogic() + sage: [S(i) for i in range(3)] + [0, 1, many] + """ + return ["0", "1", "many"][self._n] + + def __eq__(self, other): + """ + Test for equality. + + TESTS:: + + sage: from sage.categories.examples.semirings import TernaryLogic + sage: S = TernaryLogic() + sage: S(1) == S(2) + False + sage: S(0) == 3 + False + """ + if not isinstance(other, Ternary): + return False + return self._n == other._n + + def __ne__(self, other): + """ + Test for non-equality. + + TESTS:: + + sage: from sage.categories.examples.semirings import TernaryLogic + sage: S = TernaryLogic() + sage: S(1) != S(2) + True + """ + return not (self == other) + + +class TernaryLogic(UniqueRepresentation, Parent): + r""" + An example of a semiring. + + This class illustrates a minimal implementation of a semiring. + + EXAMPLES:: + + sage: S = Semirings().example(); S + An example of a semiring: the ternary-logic semiring + + This is the semiring that contains 3 objects:: + + sage: S.some_elements() + [0, 1, many] + + The product rule is as expected:: + + sage: S(1) * S(1) + 1 + sage: S(1) + S(1) + many + + TESTS:: + + sage: TestSuite(S).run(verbose=True) + running ._test_additive_associativity() . . . pass + running ._test_an_element() . . . pass + running ._test_associativity() . . . pass + running ._test_cardinality() . . . pass + running ._test_category() . . . pass + running ._test_construction() . . . pass + running ._test_distributivity() . . . pass + running ._test_elements() . . . + Running the test suite of self.an_element() + running ._test_category() . . . pass + running ._test_eq() . . . pass + running ._test_new() . . . pass + running ._test_nonzero_equal() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_pickling() . . . pass + pass + running ._test_elements_eq_reflexive() . . . pass + running ._test_elements_eq_symmetric() . . . pass + running ._test_elements_eq_transitive() . . . pass + running ._test_elements_neq() . . . pass + running ._test_eq() . . . pass + running ._test_new() . . . pass + running ._test_not_implemented_methods() . . . pass + running ._test_one() . . . pass + running ._test_pickling() . . . pass + running ._test_prod() . . . pass + running ._test_some_elements() . . . pass + running ._test_zero() . . . pass + """ + def __init__(self): + r""" + The ternary-logic semiring. + + EXAMPLES:: + + sage: S = Semirings().example(); S + An example of a semiring: the ternary-logic semiring + """ + Parent.__init__(self, category=Semirings()) + + def _repr_(self): + r""" + Return the string representation. + + EXAMPLES:: + + sage: Semirings().example()._repr_() + 'An example of a semiring: the ternary-logic semiring' + """ + return "An example of a semiring: the ternary-logic semiring" + + def summation(self, x, y): + r""" + Return the sum of ``x`` and ``y`` in the semiring as per + :meth:`Semirings.ParentMethods.summation`. + + EXAMPLES:: + + sage: S = Semirings().example() + sage: S(1) + S(1) + many + """ + assert x in self + assert y in self + return self(_ADD[x._n][y._n]) + + def one(self): + """ + Return the unit of ``self``. + + EXAMPLES:: + + sage: S = Semirings().example() + sage: S.one() + 1 + """ + return self(1) + + def product(self, x, y): + r""" + Return the product of ``x`` and ``y`` in the semiring as per + :meth:`Semirings.ParentMethods.product`. + + EXAMPLES:: + + sage: S = Semirings().example() + sage: S(1) * S(2) + many + """ + assert x in self + assert y in self + return self(_PROD[x._n][y._n]) + + def an_element(self): + r""" + Return an element of the semiring. + + EXAMPLES:: + + sage: Semirings().example().an_element() + many + """ + return self(2) + + def some_elements(self): + r""" + Return a list of some elements of the semiring. + + EXAMPLES:: + + sage: Semirings().example().some_elements() + [0, 1, many] + """ + return [self(i) for i in [0, 1, 2]] + + Element = Ternary + + +Example = TernaryLogic diff --git a/src/sage/categories/fields.py b/src/sage/categories/fields.py index e1f5c3d68f6..98251904607 100644 --- a/src/sage/categories/fields.py +++ b/src/sage/categories/fields.py @@ -206,11 +206,12 @@ def is_field(self, proof=True): """ return True - def is_integrally_closed(self): + def is_integrally_closed(self) -> bool: r""" - Return ``True``, as per :meth:`IntegralDomain.is_integrally_closed`: - for every field `F`, `F` is its own field of fractions, - hence every element of `F` is integral over `F`. + Return whether ``self`` is integrally closed. + + For every field `F`, `F` is its own field of fractions. + Therefore every element of `F` is integral over `F`. EXAMPLES:: @@ -222,6 +223,8 @@ def is_integrally_closed(self): Finite Field of size 5 sage: Z5.is_integrally_closed() True + sage: Frac(ZZ['x,y']).is_integrally_closed() + True """ return True diff --git a/src/sage/categories/finite_dimensional_algebras_with_basis.py b/src/sage/categories/finite_dimensional_algebras_with_basis.py index 187fe3d675a..20ec2f2747a 100644 --- a/src/sage/categories/finite_dimensional_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_algebras_with_basis.py @@ -1143,7 +1143,7 @@ def is_identity_decomposition_into_orthogonal_idempotents(self, l): for f in l[:i])) @cached_method - def is_commutative(self): + def is_commutative(self) -> bool: """ Return whether ``self`` is a commutative algebra. @@ -1158,7 +1158,7 @@ def is_commutative(self): True """ B = list(self.basis()) - try: # See if 1 is a basis element, if so, remove it + try: # See if 1 is a basis element, if so, remove it B.remove(self.one()) except ValueError: pass diff --git a/src/sage/categories/finite_enumerated_sets.py b/src/sage/categories/finite_enumerated_sets.py index d3438e43d37..e3243937b5a 100644 --- a/src/sage/categories/finite_enumerated_sets.py +++ b/src/sage/categories/finite_enumerated_sets.py @@ -474,7 +474,7 @@ def _random_element_from_unrank(self): sage: n in C True - TODO: implement _test_random which checks uniformness + TODO: implement _test_random which checks uniformity """ from sage.misc.prandom import randint c = self.cardinality() diff --git a/src/sage/categories/graded_algebras_with_basis.py b/src/sage/categories/graded_algebras_with_basis.py index 793e19c848b..254020f09ff 100644 --- a/src/sage/categories/graded_algebras_with_basis.py +++ b/src/sage/categories/graded_algebras_with_basis.py @@ -13,6 +13,7 @@ from sage.categories.graded_modules import GradedModulesCategory from sage.categories.signed_tensor import SignedTensorProductsCategory, tensor_signed from sage.misc.cachefunc import cached_method +from sage.categories.category_with_axiom import CategoryWithAxiom_over_base_ring class GradedAlgebrasWithBasis(GradedModulesCategory): @@ -154,6 +155,24 @@ def formal_series_ring(self): class ElementMethods: pass + class FiniteDimensional(CategoryWithAxiom_over_base_ring): + class ParentMethods: + @cached_method + def top_degree(self): + r""" + Return the top degree of the finite dimensional graded algebra. + + EXAMPLES:: + + sage: ch = matroids.Uniform(4,6).chow_ring(QQ, False) + sage: ch.top_degree() + 3 + sage: ch = matroids.Wheel(3).chow_ring(QQ, True, 'atom-free') + sage: ch.top_degree() + 3 + """ + return max(b.degree() for b in self.basis()) + class SignedTensorProducts(SignedTensorProductsCategory): """ The category of algebras with basis constructed by signed tensor diff --git a/src/sage/categories/groupoid.py b/src/sage/categories/groupoid.py index b197c092be5..4833b4e6f57 100644 --- a/src/sage/categories/groupoid.py +++ b/src/sage/categories/groupoid.py @@ -40,7 +40,7 @@ def __init__(self, G=None): sage: C = Groupoid(S8) sage: TestSuite(C).run() """ - CategoryWithParameters.__init__(self) #, "Groupoid") + CategoryWithParameters.__init__(self) # "Groupoid") if G is None: from sage.groups.perm_gps.permgroup_named import SymmetricGroup G = SymmetricGroup(8) @@ -56,8 +56,8 @@ def _repr_(self): """ return "Groupoid with underlying set %s" % self.__G - #def construction(self): - # return (self.__class__, self.__G) + # def construction(self): + # return (self.__class__, self.__G) def _make_named_class_key(self, name): """ diff --git a/src/sage/categories/integral_domains.py b/src/sage/categories/integral_domains.py index 173a14cf25f..c66b609a5e3 100644 --- a/src/sage/categories/integral_domains.py +++ b/src/sage/categories/integral_domains.py @@ -1,6 +1,27 @@ # sage_setup: distribution = sagemath-categories r""" Integral domains + +TEST: + +A few tests for the method ``is_integrally_closed``:: + + sage: ZZ.is_integrally_closed() + True + sage: QQ.is_integrally_closed() + True + sage: QQbar.is_integrally_closed() # needs sage.rings.number_field + True + sage: GF(5).is_integrally_closed() + True + sage: Z5 = Integers(5); Z5 + Ring of integers modulo 5 + sage: Z5.is_integrally_closed() + Traceback (most recent call last): + ... + NotImplementedError + +Note that this raises a :exc:`NotImplementedError` if the answer is not known. """ # **************************************************************************** # Copyright (C) 2008 Teresa Gomez-Diaz (CNRS) @@ -122,6 +143,37 @@ def is_integral_domain(self, proof=True): """ return True + def is_field(self, proof=True): + r""" + Return ``True`` if this ring is a field. + + EXAMPLES:: + + sage: ZZ['x'].is_field() + False + """ + if self.is_finite(): + return True + if proof: + raise NotImplementedError(f"unable to determine whether or not {self} is a field.") + return False + + def localization(self, additional_units, names=None, normalize=True, category=None): + """ + Return the localization of ``self`` at the given additional units. + + EXAMPLES:: + + sage: R. = GF(3)[] + sage: R.localization((x*y, x**2 + y**2)) # needs sage.rings.finite_rings + Multivariate Polynomial Ring in x, y over Finite Field of size 3 + localized at (y, x, x^2 + y^2) + sage: ~y in _ # needs sage.rings.finite_rings + True + """ + from sage.rings.localization import Localization + return Localization(self, additional_units, names=names, normalize=normalize, category=category) + def _test_fraction_field(self, **options): r""" Test that the fraction field, if it is implemented, works diff --git a/src/sage/categories/kahler_algebras.py b/src/sage/categories/kahler_algebras.py new file mode 100644 index 00000000000..d8791ae78fb --- /dev/null +++ b/src/sage/categories/kahler_algebras.py @@ -0,0 +1,200 @@ +r""" +Kähler Algebras + +AUTHORS: + +- Shriya M +""" +# **************************************************************************** +# Copyright (C) 2024 Shriya M <25shriya at gmail.com> +# +# 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.categories.category_types import Category_over_base_ring +from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis +from sage.categories.finite_dimensional_algebras_with_basis import FiniteDimensionalAlgebrasWithBasis +from sage.categories.filtered_modules_with_basis import FilteredModulesWithBasis +from sage.misc.abstract_method import abstract_method +from sage.quadratic_forms.quadratic_form import QuadraticForm +from sage.misc.cachefunc import cached_method + + +class KahlerAlgebras(Category_over_base_ring): + r""" + The category of graded algebras satisfying the Kähler package. + A finite-dimensional graded algebra `\bigoplus_{k=1}^{r}A^k` satisfies + the *Kähler package* if the following properties hold: + + - Poincaré duality: There exists a perfect `\ZZ`-bilinear pairing + given by + + .. MATH:: + + A^k \times A^{r-k} \longrightarrow \ZZ \\ + (a,b) \mapsto \deg(a \cdot b). + + - Hard-Lefschetz Theorem: The graded algebra contains *Lefschetz elements* + `\omega \in A^{1}_{\RR}` such that multiplication by `\omega` is + an injection from `A^k_{\RR} \longrightarrow A^{k+1}_{\RR}` + for all `k < \frac{r}{2}`. + + - Hodge-Riemann-Minikowski Relations: Every Lefchetz element `\omega`, + define quadratic forms on `A^{k}_{\RR}` given by + + .. MATH:: + + a \mapsto (-1)^k \deg(a \cdot \omega^{r-2k} \cdot a) + + This quadratic form becomes positive definite upon restriction to the + kernel of the following map + + .. MATH:: + + A^k_\RR \longrightarrow A^{r-k+1}_\RR \\ + a \mapsto a \cdot \omega^{r-2k+1}. + + REFERENCES: + + - [ANR2023]_ + + TESTS:: + + sage: from sage.categories.kahler_algebras import KahlerAlgebras + + sage: C = KahlerAlgebras(QQ) + sage: TestSuite(C).run() + """ + def super_categories(self): + r""" + Return the super categories of ``self``. + + EXAMPLES:: + + sage: from sage.categories.kahler_algebras import KahlerAlgebras + + sage: C = KahlerAlgebras(QQ); C + Category of kahler algebras over Rational Field + sage: sorted(C.super_categories(), key=str) + [Category of finite dimensional graded algebras with basis over + Rational Field] + """ + return [GradedAlgebrasWithBasis(self.base_ring()).FiniteDimensional()] + + class ParentMethods: + @abstract_method + def poincare_pairing(self, a, b): + r""" + Return the Poincaré pairing of two elements of the Kähler algebra. + + EXAMPLES:: + + sage: ch = matroids.catalog.Fano().chow_ring(QQ, True, 'fy') + sage: Ba, Bb, Bc, Bd, Be, Bf, Bg, Babf, Bace, Badg, Bbcd, Bbeg, Bcfg, Bdef, Babcdefg = ch.gens()[8:] + sage: u = ch(-Babf^2 + Bcfg^2 - 8/7*Bc*Babcdefg + 1/2*Bd*Babcdefg - Bf*Babcdefg - Bg*Babcdefg); u + -Babf^2 + Bcfg^2 - 8/7*Bc*Babcdefg + 1/2*Bd*Babcdefg - Bf*Babcdefg - Bg*Babcdefg + sage: v = ch(Bg - 2/37*Babf + Badg + Bbeg + Bcfg + Babcdefg); v + Bg - 2/37*Babf + Badg + Bbeg + Bcfg + Babcdefg + sage: ch.poincare_pairing(v, u) + 3 + """ + + @abstract_method + def lefschetz_element(self): + r""" + Return one Lefschetz element of the given Kähler algebra. + + EXAMPLES:: + + sage: U46 = matroids.Uniform(4, 6) + sage: C = U46.chow_ring(QQ, False) + sage: w = C.lefschetz_element(); w + -2*A01 - 2*A02 - 2*A03 - 2*A04 - 2*A05 - 2*A12 - 2*A13 - 2*A14 + - 2*A15 - 2*A23 - 2*A24 - 2*A25 - 2*A34 - 2*A35 - 2*A45 - 6*A012 + - 6*A013 - 6*A014 - 6*A015 - 6*A023 - 6*A024 - 6*A025 - 6*A034 + - 6*A035 - 6*A045 - 6*A123 - 6*A124 - 6*A125 - 6*A134 - 6*A135 + - 6*A145 - 6*A234 - 6*A235 - 6*A245 - 6*A345 - 30*A012345 + sage: basis_deg = {} + sage: for b in C.basis(): + ....: deg = b.homogeneous_degree() + ....: if deg not in basis_deg: + ....: basis_deg[deg] = [] + ....: basis_deg[deg].append(b) + sage: m = max(basis_deg); m + 3 + sage: len(basis_deg[1]) == len(basis_deg[2]) + True + sage: matrix([(w*b).to_vector() for b in basis_deg[1]]).rank() + 36 + sage: len(basis_deg[2]) + 36 + """ + + def hodge_riemann_relations(self, k): + r""" + Return the quadratic form for the corresponding ``k`` + (`< \frac{r}{2}`) for the Kähler algebra, where `r` is the top degree. + + EXAMPLES:: + + sage: ch = matroids.Uniform(4, 6).chow_ring(QQ, False) + sage: ch.hodge_riemann_relations(1) + Quadratic form in 36 variables over Rational Field with coefficients: + [ 3 -1 -1 3 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 3 ] + [ * 3 -1 3 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 -1 3 ] + [ * * 3 3 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 3 ] + [ * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * 3 -1 3 -1 3 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 3 ] + [ * * * * * 3 3 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 -1 -1 3 ] + [ * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * 3 3 3 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 ] + [ * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * 3 -1 3 -1 -1 3 -1 -1 3 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 ] + [ * * * * * * * * * * * 3 3 -1 3 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 ] + [ * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * 3 3 3 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 3 -1 -1 -1 -1 -1 -1 -1 3 ] + [ * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * 3 3 3 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 3 -1 -1 -1 3 ] + [ * * * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * * 3 -1 3 -1 3 -1 -1 -1 -1 3 -1 -1 -1 3 -1 3 ] + [ * * * * * * * * * * * * * * * * * * * * * 3 3 -1 -1 3 -1 -1 3 -1 -1 -1 3 -1 -1 3 ] + [ * * * * * * * * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * * * * * 3 3 3 -1 3 -1 -1 -1 3 -1 -1 -1 3 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * * 3 3 3 3 -1 -1 -1 -1 3 3 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 3 3 3 3 3 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 -1 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 -1 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 -1 -1 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 -1 ] + [ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3 ] + sage: ch.hodge_riemann_relations(3) + Traceback (most recent call last): + ... + ValueError: k must be less than r/2 < 2 + """ + r = self.top_degree() + if k > (r/2): + raise ValueError("k must be less than r/2 < 2") + basis_k = [] + lefschetz_el = self.lefschetz_element() + for b in self.basis(): + if b.homogeneous_degree() == k: + basis_k.append(b) + coeff = [] + for i,el in enumerate(basis_k): + for j in range(i, len(basis_k)): + coeff.append((el * (lefschetz_el ** (r-(2*k)) * basis_k[j])).degree()) + return QuadraticForm(self.base_ring(), len(basis_k), coeff) \ No newline at end of file diff --git a/src/sage/categories/lie_algebras.py b/src/sage/categories/lie_algebras.py index f134cfded5b..3a3e1a7cd5b 100644 --- a/src/sage/categories/lie_algebras.py +++ b/src/sage/categories/lie_algebras.py @@ -589,10 +589,11 @@ def is_abelian(self): zero = self.zero() return all(x._bracket_(y) == zero for x in G for y in G) - def is_commutative(self): + def is_commutative(self) -> bool: """ - Return if ``self`` is commutative. This is equivalent to ``self`` - being abelian. + Return if ``self`` is commutative. + + This is equivalent to ``self`` being abelian. EXAMPLES:: diff --git a/src/sage/categories/magmas.py b/src/sage/categories/magmas.py index ea491b2caf7..5bad4ffb775 100644 --- a/src/sage/categories/magmas.py +++ b/src/sage/categories/magmas.py @@ -398,7 +398,7 @@ def is_field(self, proof=True): class Commutative(CategoryWithAxiom): class ParentMethods: - def is_commutative(self): + def is_commutative(self) -> bool: """ Return ``True``, since commutative magmas are commutative. diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index 43e476847d0..0007555326a 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -275,7 +275,7 @@ cdef class Map(Element): maps:: sage: phi.domain # needs sage.rings.number_field - + sage: phi._make_strong_references() # needs sage.rings.number_field sage: print(phi.domain) # needs sage.rings.number_field The constant function (...) -> Number Field in a @@ -343,7 +343,7 @@ cdef class Map(Element): maps:: sage: phi.domain # needs sage.rings.number_field - + sage: phi._make_strong_references() # needs sage.rings.number_field sage: print(phi.domain) # needs sage.rings.number_field The constant function (...) -> Number Field in a diff --git a/src/sage/categories/meson.build b/src/sage/categories/meson.build index 132037fe7fd..b5c6a46f038 100644 --- a/src/sage/categories/meson.build +++ b/src/sage/categories/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'action.pxd', 'additive_groups.py', 'additive_magmas.py', @@ -119,6 +120,7 @@ py.install_sources( 'isomorphic_objects.py', 'j_trivial_semigroups.py', 'kac_moody_algebras.py', + 'kahler_algebras.py', 'l_trivial_semigroups.py', 'lambda_bracket_algebras.py', 'lambda_bracket_algebras_with_basis.py', diff --git a/src/sage/categories/modules.py b/src/sage/categories/modules.py index f9bc036910f..0f7ec03001a 100644 --- a/src/sage/categories/modules.py +++ b/src/sage/categories/modules.py @@ -967,16 +967,10 @@ def construction(self): (Free Algebra on 2 generators (None0, None1) over Rational Field, Free Algebra on 2 generators (None0, None1) over Rational Field)) """ - try: - factors = self.tensor_factors() - except (TypeError, NotImplementedError): - from sage.misc.superseded import deprecation - deprecation(34393, "implementations of Modules().TensorProducts() now must define the method tensor_factors") - return None - return (TensorProductFunctor(), - factors) - - @abstract_method(optional=True) + factors = self.tensor_factors() + return (TensorProductFunctor(), factors) + + @abstract_method def tensor_factors(self): """ Return the tensor factors of this tensor product. @@ -992,16 +986,4 @@ def tensor_factors(self): F # G sage: T.tensor_factors() (F, G) - - TESTS:: - - sage: Cat = ModulesWithBasis(ZZ).FiniteDimensional().TensorProducts() - sage: M = CombinatorialFreeModule(ZZ, # needs sage.modules - ....: ((1, 1), (1, 2), (2, 1), (2, 2)), - ....: category=Cat) - sage: M.construction() # needs sage.modules - doctest:warning... - DeprecationWarning: implementations of Modules().TensorProducts() now must define the method tensor_factors - See https://github.com/sagemath/sage/issues/34393 for details. - (VectorFunctor, Integer Ring) """ diff --git a/src/sage/categories/modules_with_basis.py b/src/sage/categories/modules_with_basis.py index 489f2f97dbb..cda4ecdca68 100644 --- a/src/sage/categories/modules_with_basis.py +++ b/src/sage/categories/modules_with_basis.py @@ -1860,6 +1860,18 @@ def leading_item(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.leading_item() # needs sage.combinat sage.modules ([3], -5) + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_item() + ((0, 4, 0), 1) + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_item() + ((1, 2, 0), 3) + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_item() + ((0, 1, 3), 2) """ k = self.leading_support(*args, **kwds) return k, self[k] @@ -1890,6 +1902,18 @@ def leading_monomial(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.leading_monomial() # needs sage.combinat sage.modules s[3] + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_monomial() + y^4 + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_monomial() + x*y^2 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_monomial() + y*z^3 """ return self.parent().monomial(self.leading_support(*args, **kwds)) @@ -1919,6 +1943,18 @@ def leading_coefficient(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.leading_coefficient() # needs sage.combinat sage.modules -5 + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_coefficient() + 1 + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_coefficient() + 3 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_coefficient() + 2 """ return self.leading_item(*args, **kwds)[1] @@ -1948,6 +1984,18 @@ def leading_term(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.leading_term() # needs sage.combinat sage.modules -5*s[3] + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_term() + y^4 + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_term() + 3*x*y^2 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_term() + 2*y*z^3 """ return self.parent().term(*self.leading_item(*args, **kwds)) @@ -2005,6 +2053,18 @@ def trailing_item(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.trailing_item() # needs sage.combinat sage.modules ([1], 2) + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_item() + ((1, 1, 1), 4) + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_item() + ((0, 1, 3), 2) + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_item() + ((1, 2, 0), 3) """ k = self.trailing_support(*args, **kwds) return k, self[k] @@ -2035,6 +2095,18 @@ def trailing_monomial(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.trailing_monomial() # needs sage.combinat sage.modules s[1] + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_monomial() + x*y*z + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_monomial() + y*z^3 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_monomial() + x*y^2 """ return self.parent().monomial(self.trailing_support(*args, **kwds)) @@ -2064,6 +2136,18 @@ def trailing_coefficient(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.trailing_coefficient() # needs sage.combinat sage.modules 2 + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_coefficient() + 4 + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_coefficient() + 2 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_coefficient() + 3 """ return self.trailing_item(*args, **kwds)[1] @@ -2093,6 +2177,18 @@ def trailing_term(self, *args, **kwds): sage: f = 2*s[1] + 3*s[2,1] - 5*s[3] # needs sage.combinat sage.modules sage: f.trailing_term() # needs sage.combinat sage.modules 2*s[1] + + The term ordering of polynomial rings is taken into account:: + + sage: R. = QQ[] + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_term() + 4*x*y*z + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_term() + 2*y*z^3 + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_term() + 3*x*y^2 """ return self.parent().term(*self.trailing_item(*args, **kwds)) diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index b67f37ed524..a2b5e910257 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -2263,25 +2263,13 @@ def __eq__(self, other): sage: # needs sage.modules sage: F1.basis - [ - (1, 0, 4), - (0, 1, 2) - ] + [(1, 0, 4), (0, 1, 2)] sage: F2.basis - [ - (1, 2, 3), - (0, 3, 6) - ] + [(1, 2, 3), (0, 3, 6)] sage: F3.basis - [ - (1, 0, -1), - (0, 1, 2) - ] + [(1, 0, -1), (0, 1, 2)] sage: F4.basis - [ - (1, 0, -1), - (0, 1, 2) - ] + [(1, 0, -1), (0, 1, 2)] The basis of ``F2`` is modulo 5 different from the other bases. diff --git a/src/sage/categories/rings.py b/src/sage/categories/rings.py index 8db71edfb9c..e0769336c6f 100644 --- a/src/sage/categories/rings.py +++ b/src/sage/categories/rings.py @@ -423,6 +423,29 @@ def is_integral_domain(self, proof=True) -> bool: return False + def is_integrally_closed(self) -> bool: + r""" + Return whether this ring is integrally closed. + + This is the default implementation that + raises a :exc:`NotImplementedError`. + + EXAMPLES:: + + sage: x = polygen(ZZ, 'x') + sage: K. = NumberField(x^2 + 189*x + 394) + sage: R = K.order(2*a) + sage: R.is_integrally_closed() + False + sage: R + Order of conductor 2 generated by 2*a in Number Field in a with defining polynomial x^2 + 189*x + 394 + sage: S = K.maximal_order(); S + Maximal Order generated by a in Number Field in a with defining polynomial x^2 + 189*x + 394 + sage: S.is_integrally_closed() + True + """ + raise NotImplementedError + def is_noetherian(self): """ Return ``True`` if this ring is Noetherian. @@ -531,6 +554,22 @@ def is_subring(self, other): except (TypeError, AttributeError): return False + def localization(self, *args, **kwds): + """ + Return the localization of ``self``. + + This only works for integral domains. + + EXAMPLES:: + + sage: R = Zmod(6) + sage: R.localization((4)) + Traceback (most recent call last): + ... + TypeError: self must be an integral domain + """ + raise TypeError("self must be an integral domain") + def bracket(self, x, y): """ Return the Lie bracket `[x, y] = x y - y x` of `x` and `y`. @@ -621,8 +660,8 @@ def _mul_(self, x, switch_sides=False): INPUT: - - `x`, an object to multiply with. - - `switch_sides` (optional bool): If ``False``, + - ``x``, an object to multiply with. + - ``switch_sides`` (optional bool): If ``False``, the product is ``self*x``; if ``True``, the product is ``x*self``. diff --git a/src/sage/categories/semirings.py b/src/sage/categories/semirings.py index 6ba7dbec342..2bf0ea988dc 100644 --- a/src/sage/categories/semirings.py +++ b/src/sage/categories/semirings.py @@ -1,13 +1,13 @@ # sage_setup: distribution = sagemath-categories r""" -Semirngs +Semirings """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Nicolas Borie # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.magmas_and_additive_magmas import MagmasAndAdditiveMagmas @@ -32,11 +32,13 @@ class Semirings(CategoryWithAxiom): sage: Semirings() Category of semirings sage: Semirings().super_categories() - [Category of associative additive commutative additive associative additive unital distributive magmas and additive magmas, + [Category of associative additive commutative additive + associative additive unital distributive magmas and additive magmas, Category of monoids] sage: sorted(Semirings().axioms()) - ['AdditiveAssociative', 'AdditiveCommutative', 'AdditiveUnital', 'Associative', 'Distributive', 'Unital'] + ['AdditiveAssociative', 'AdditiveCommutative', 'AdditiveUnital', + 'Associative', 'Distributive', 'Unital'] sage: Semirings() is (CommutativeAdditiveMonoids() & Monoids()).Distributive() True @@ -48,5 +50,7 @@ class Semirings(CategoryWithAxiom): TESTS:: sage: TestSuite(Semirings()).run() + sage: Semirings().example() + An example of a semiring: the ternary-logic semiring """ _base_category_class_and_axiom = (MagmasAndAdditiveMagmas.Distributive.AdditiveAssociative.AdditiveCommutative.AdditiveUnital.Associative, "Unital") diff --git a/src/sage/categories/simplicial_sets.py b/src/sage/categories/simplicial_sets.py index 76030be831b..f30ed0ffeb2 100644 --- a/src/sage/categories/simplicial_sets.py +++ b/src/sage/categories/simplicial_sets.py @@ -444,29 +444,31 @@ def covering_map(self, character): sage: # needs sage.graphs sage.groups sage: S1 = simplicial_sets.Sphere(1) - sage: W = S1.wedge(S1) + sage: S1_ = simplicial_sets.Sphere(1) + sage: S1_.n_cells(1)[0].rename("sigma_1'") + sage: W = S1.wedge(S1_) sage: G = CyclicPermutationGroup(3) sage: a, b = W.n_cells(1) sage: C = W.covering_map({a : G.gen(0), b : G.one()}); C Simplicial set morphism: From: Simplicial set with 9 non-degenerate simplices To: Wedge: (S^1 v S^1) - Defn: [(*, ()), (*, (1,2,3)), (*, (1,3,2)), (sigma_1, ()), - (sigma_1, ()), (sigma_1, (1,2,3)), (sigma_1, (1,2,3)), - (sigma_1, (1,3,2)), (sigma_1, (1,3,2))] - --> [*, *, *, sigma_1, sigma_1, sigma_1, sigma_1, sigma_1, sigma_1] + Defn: [(*, ()), (*, (1,2,3)), (*, (1,3,2)), (sigma_1', ()), + (sigma_1', (1,2,3)), (sigma_1', (1,3,2)), (sigma_1, ()), + (sigma_1, (1,2,3)), (sigma_1, (1,3,2))] + --> [*, *, *, sigma_1', sigma_1', sigma_1', sigma_1, sigma_1, sigma_1] sage: C.domain() Simplicial set with 9 non-degenerate simplices sage: C.domain().face_data() {(*, ()): None, (*, (1,2,3)): None, (*, (1,3,2)): None, + (sigma_1', ()): ((*, ()), (*, ())), + (sigma_1', (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))), + (sigma_1', (1,3,2)): ((*, (1,3,2)), (*, (1,3,2))), (sigma_1, ()): ((*, (1,2,3)), (*, ())), - (sigma_1, ()): ((*, ()), (*, ())), (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))), - (sigma_1, (1,2,3)): ((*, (1,2,3)), (*, (1,2,3))), - (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), - (sigma_1, (1,3,2)): ((*, (1,3,2)), (*, (1,3,2)))} + (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2)))} """ from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet from sage.topology.simplicial_set_morphism import SimplicialSetMorphism @@ -530,7 +532,9 @@ def cover(self, character): sage: # needs sage.graphs sage.groups sage: S1 = simplicial_sets.Sphere(1) - sage: W = S1.wedge(S1) + sage: S1_ = simplicial_sets.Sphere(1) + sage: S1_.n_cells(1)[0].rename("sigma_1'") + sage: W = S1.wedge(S1_) sage: G = CyclicPermutationGroup(3) sage: (a, b) = W.n_cells(1) sage: C = W.cover({a : G.gen(0), b : G.gen(0)^2}) @@ -538,12 +542,12 @@ def cover(self, character): {(*, ()): None, (*, (1,2,3)): None, (*, (1,3,2)): None, + (sigma_1', ()): ((*, (1,3,2)), (*, ())), + (sigma_1', (1,2,3)): ((*, ()), (*, (1,2,3))), + (sigma_1', (1,3,2)): ((*, (1,2,3)), (*, (1,3,2))), (sigma_1, ()): ((*, (1,2,3)), (*, ())), - (sigma_1, ()): ((*, (1,3,2)), (*, ())), (sigma_1, (1,2,3)): ((*, (1,3,2)), (*, (1,2,3))), - (sigma_1, (1,2,3)): ((*, ()), (*, (1,2,3))), - (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2))), - (sigma_1, (1,3,2)): ((*, (1,2,3)), (*, (1,3,2)))} + (sigma_1, (1,3,2)): ((*, ()), (*, (1,3,2)))} sage: C.homology(1) # needs sage.modules Z x Z x Z x Z sage: C.fundamental_group() diff --git a/src/sage/categories/unital_algebras.py b/src/sage/categories/unital_algebras.py index b5c0dd73e86..33c10cf2c4a 100644 --- a/src/sage/categories/unital_algebras.py +++ b/src/sage/categories/unital_algebras.py @@ -319,7 +319,7 @@ def one_from_one_basis(self): sage: Aone().parent() is A # needs sage.combinat sage.modules True """ - return self.monomial(self.one_basis()) #. + return self.monomial(self.one_basis()) @lazy_attribute def one(self): diff --git a/src/sage/coding/abstract_code.py b/src/sage/coding/abstract_code.py index d94eb1ca309..3d1fe305dbc 100644 --- a/src/sage/coding/abstract_code.py +++ b/src/sage/coding/abstract_code.py @@ -324,9 +324,9 @@ def __iter__(self): r""" Return an error message requiring to override ``__iter__`` in ``self``. - As one has to implement specific category related methods (`__iter__` and - `__contains__`) when writing a new code class which inherits from - :class:`AbstractCode`, the generic call to `__iter__` has to fail. + As one has to implement specific category related methods (``__iter__`` and + ``__contains__``) when writing a new code class which inherits from + :class:`AbstractCode`, the generic call to ``__iter__`` has to fail. EXAMPLES: @@ -352,9 +352,9 @@ def __contains__(self, c): r""" Return an error message requiring to override ``__contains__`` in ``self``. - As one has to implement specific category related methods (`__iter__` and - `__contains__`) when writing a new code class which inherits from - :class:`AbstractCode`, the generic call to `__contains__` has to fail. + As one has to implement specific category related methods (``__iter__`` and + ``__contains__``) when writing a new code class which inherits from + :class:`AbstractCode`, the generic call to ``__contains__`` has to fail. EXAMPLES: @@ -448,9 +448,9 @@ def _repr_(self): r""" Return an error message requiring to override ``_repr_`` in ``self``. - As one has to implement specific representation methods (`_repr_` and - `_latex_`) when writing a new code class which inherits from - :class:`AbstractCode`, the generic call to `_repr_` has to fail. + As one has to implement specific representation methods (``_repr_`` and + ``_latex_``) when writing a new code class which inherits from + :class:`AbstractCode`, the generic call to ``_repr_`` has to fail. EXAMPLES: @@ -476,9 +476,9 @@ def _latex_(self): r""" Return an error message requiring to override ``_latex_`` in ``self``. - As one has to implement specific representation methods (`_repr_` and - `_latex_`) when writing a new code class which inherits from - :class:`AbstractCode`, the generic call to `_latex_` has to fail. + As one has to implement specific representation methods (``_repr_`` and + ``_latex_``) when writing a new code class which inherits from + :class:`AbstractCode`, the generic call to ``_latex_`` has to fail. EXAMPLES: diff --git a/src/sage/coding/binary_code.pxd b/src/sage/coding/binary_code.pxd index 38be220c731..6331dc84693 100644 --- a/src/sage/coding/binary_code.pxd +++ b/src/sage/coding/binary_code.pxd @@ -1,3 +1,5 @@ +from memory_allocator cimport MemoryAllocator + cdef int *hamming_weights() noexcept ctypedef unsigned int codeword @@ -11,6 +13,7 @@ cdef struct WordPermutation: codeword gate cdef class BinaryCode: + cdef MemoryAllocator mem cdef codeword *basis cdef codeword *words cdef int ncols @@ -34,6 +37,7 @@ cdef codeword permute_word_by_wp(WordPermutation *, codeword) noexcept cdef codeword *expand_to_ortho_basis(BinaryCode, int) noexcept cdef class OrbitPartition: + cdef MemoryAllocator mem cdef int nwords cdef int ncols cdef int *wd_parent @@ -52,6 +56,7 @@ cdef class OrbitPartition: cdef int merge_perm(self, int *, int *) noexcept cdef class PartitionStack: + cdef MemoryAllocator mem cdef int *wd_ents cdef int *wd_lvls cdef int *col_ents @@ -89,6 +94,7 @@ cdef class PartitionStack: cdef void get_permutation(self, PartitionStack, int *, int *) noexcept cdef class BinaryCodeClassifier: + cdef MemoryAllocator mem cdef int *ham_wts cdef int L cdef unsigned int *Phi @@ -115,4 +121,3 @@ cdef class BinaryCodeClassifier: cdef void record_automorphism(self, int *, int) noexcept cdef void aut_gp_and_can_label(self, BinaryCode, int) noexcept - diff --git a/src/sage/coding/binary_code.pyx b/src/sage/coding/binary_code.pyx index 3c73e0f7176..f2eb22c046a 100644 --- a/src/sage/coding/binary_code.pyx +++ b/src/sage/coding/binary_code.pyx @@ -62,9 +62,9 @@ cdef inline int min(int a, int b) noexcept: else: return a -## NOTE - Since most of the functions are used from within the module, cdef'd -## functions come without an underscore, and the def'd equivalents, which are -## essentially only for doctesting and debugging, have underscores. +# NOTE - Since most of the functions are used from within the module, cdef'd +# functions come without an underscore, and the def'd equivalents, which are +# essentially only for doctesting and debugging, have underscores. cdef int *hamming_weights() noexcept: cdef int *ham_wts @@ -123,8 +123,9 @@ def weight_dist(M): cdef bitset_t word cdef int i,j,k, dim=M.nrows(), deg=M.ncols() cdef list L - cdef int *LL = sig_malloc((deg+1) * sizeof(int)) - cdef bitset_s *basis = sig_malloc(dim * sizeof(bitset_s)) + cdef MemoryAllocator mem = MemoryAllocator() + cdef int *LL = mem.malloc((deg+1) * sizeof(int)) + cdef bitset_s *basis = mem.malloc(dim * sizeof(bitset_s)) for i from 0 <= i < dim: bitset_init(&basis[i], deg) bitset_zero(&basis[i]) @@ -150,8 +151,6 @@ def weight_dist(M): L = [int(LL[i]) for i from 0 <= i < deg+1] for i from 0 <= i < dim: bitset_free(&basis[i]) - sig_free(LL) - sig_free(basis) return L @@ -785,12 +784,9 @@ cdef class BinaryCode: if self.nrows >= self.radix or self.ncols > self.radix: raise NotImplementedError("Columns and rows are stored as ints. This code is too big.") - self.words = sig_malloc( nwords * sizeof(int) ) - self.basis = sig_malloc( nrows * sizeof(int) ) - if self.words is NULL or self.basis is NULL: - if self.words is not NULL: sig_free(self.words) - if self.basis is not NULL: sig_free(self.basis) - raise MemoryError("Memory.") + self.mem = MemoryAllocator() + self.words = self.mem.malloc(nwords * sizeof(int)) + self.basis = self.mem.malloc(nrows * sizeof(int)) self_words = self.words self_basis = self.basis @@ -829,10 +825,6 @@ cdef class BinaryCode: for combination from 0 <= combination < other_nwords: self_words[combination+other_nwords] = self_words[combination] ^ glue_word - def __dealloc__(self): - sig_free(self.words) - sig_free(self.basis) - def __reduce__(self): """ Method for pickling and unpickling BinaryCodes. @@ -1279,26 +1271,15 @@ cdef class OrbitPartition: nwords = (1 << nrows) self.nwords = nwords self.ncols = ncols - self.wd_parent = sig_malloc( nwords * sizeof(int) ) - self.wd_rank = sig_malloc( nwords * sizeof(int) ) - self.wd_min_cell_rep = sig_malloc( nwords * sizeof(int) ) - self.wd_size = sig_malloc( nwords * sizeof(int) ) - self.col_parent = sig_malloc( ncols * sizeof(int) ) - self.col_rank = sig_malloc( ncols * sizeof(int) ) - self.col_min_cell_rep = sig_malloc( ncols * sizeof(int) ) - self.col_size = sig_malloc( ncols * sizeof(int) ) - if self.wd_parent is NULL or self.wd_rank is NULL or self.wd_min_cell_rep is NULL \ - or self.wd_size is NULL or self.col_parent is NULL or self.col_rank is NULL \ - or self.col_min_cell_rep is NULL or self.col_size is NULL: - if self.wd_parent is not NULL: sig_free(self.wd_parent) - if self.wd_rank is not NULL: sig_free(self.wd_rank) - if self.wd_min_cell_rep is not NULL: sig_free(self.wd_min_cell_rep) - if self.wd_size is not NULL: sig_free(self.wd_size) - if self.col_parent is not NULL: sig_free(self.col_parent) - if self.col_rank is not NULL: sig_free(self.col_rank) - if self.col_min_cell_rep is not NULL: sig_free(self.col_min_cell_rep) - if self.col_size is not NULL: sig_free(self.col_size) - raise MemoryError("Memory.") + self.mem = MemoryAllocator() + self.wd_parent = self.mem.malloc(nwords * sizeof(int)) + self.wd_rank = self.mem.malloc(nwords * sizeof(int)) + self.wd_min_cell_rep = self.mem.malloc(nwords * sizeof(int)) + self.wd_size = self.mem.malloc(nwords * sizeof(int)) + self.col_parent = self.mem.malloc(ncols * sizeof(int)) + self.col_rank = self.mem.malloc(ncols * sizeof(int)) + self.col_min_cell_rep = self.mem.malloc(ncols * sizeof(int)) + self.col_size = self.mem.malloc(ncols * sizeof(int)) for word from 0 <= word < nwords: self.wd_parent[word] = word self.wd_rank[word] = 0 @@ -1310,16 +1291,6 @@ cdef class OrbitPartition: self.col_min_cell_rep[col] = col self.col_size[col] = 1 - def __dealloc__(self): - sig_free(self.wd_parent) - sig_free(self.wd_rank) - sig_free(self.wd_min_cell_rep) - sig_free(self.wd_size) - sig_free(self.col_parent) - sig_free(self.col_rank) - sig_free(self.col_min_cell_rep) - sig_free(self.col_size) - def __repr__(self): """ Return a string representation of the orbit partition. @@ -1605,34 +1576,19 @@ cdef class PartitionStack: self.flag = (1 << (self.radix-1)) # data - self.wd_ents = sig_malloc( self.nwords * sizeof_int ) - self.wd_lvls = sig_malloc( self.nwords * sizeof_int ) - self.col_ents = sig_malloc( self.ncols * sizeof_int ) - self.col_lvls = sig_malloc( self.ncols * sizeof_int ) + self.mem = MemoryAllocator() + self.wd_ents = self.mem.malloc(self.nwords * sizeof_int) + self.wd_lvls = self.mem.malloc(self.nwords * sizeof_int) + self.col_ents = self.mem.malloc(self.ncols * sizeof_int) + self.col_lvls = self.mem.malloc(self.ncols * sizeof_int) # scratch space - self.col_degs = sig_malloc( self.ncols * sizeof_int ) - self.col_counts = sig_malloc( self.nwords * sizeof_int ) - self.col_output = sig_malloc( self.ncols * sizeof_int ) - self.wd_degs = sig_malloc( self.nwords * sizeof_int ) - self.wd_counts = sig_malloc( (self.ncols+1) * sizeof_int ) - self.wd_output = sig_malloc( self.nwords * sizeof_int ) - - if self.wd_ents is NULL or self.wd_lvls is NULL or self.col_ents is NULL \ - or self.col_lvls is NULL or self.col_degs is NULL or self.col_counts is NULL \ - or self.col_output is NULL or self.wd_degs is NULL or self.wd_counts is NULL \ - or self.wd_output is NULL: - if self.wd_ents is not NULL: sig_free(self.wd_ents) - if self.wd_lvls is not NULL: sig_free(self.wd_lvls) - if self.col_ents is not NULL: sig_free(self.col_ents) - if self.col_lvls is not NULL: sig_free(self.col_lvls) - if self.col_degs is not NULL: sig_free(self.col_degs) - if self.col_counts is not NULL: sig_free(self.col_counts) - if self.col_output is not NULL: sig_free(self.col_output) - if self.wd_degs is not NULL: sig_free(self.wd_degs) - if self.wd_counts is not NULL: sig_free(self.wd_counts) - if self.wd_output is not NULL: sig_free(self.wd_output) - raise MemoryError("Memory.") + self.col_degs = self.mem.malloc( self.ncols * sizeof_int ) + self.col_counts = self.mem.malloc( self.nwords * sizeof_int ) + self.col_output = self.mem.malloc( self.ncols * sizeof_int ) + self.wd_degs = self.mem.malloc( self.nwords * sizeof_int ) + self.wd_counts = self.mem.malloc( (self.ncols+1) * sizeof_int ) + self.wd_output = self.mem.malloc( self.nwords * sizeof_int ) nwords = self.nwords ncols = self.ncols @@ -1675,17 +1631,8 @@ cdef class PartitionStack: wd_output[k]=0 def __dealloc__(self): - if self.basis_locations: sig_free(self.basis_locations) - sig_free(self.wd_ents) - sig_free(self.wd_lvls) - sig_free(self.col_ents) - sig_free(self.col_lvls) - sig_free(self.col_degs) - sig_free(self.col_counts) - sig_free(self.col_output) - sig_free(self.wd_degs) - sig_free(self.wd_counts) - sig_free(self.wd_output) + if self.basis_locations: + sig_free(self.basis_locations) def print_data(self): """ @@ -3026,17 +2973,12 @@ cdef class PartitionStack: ([0, 1, 2, 3, 4, 5, 6, 7, 12, 13, 14, 15, 8, 9, 10, 11], [0, 1, 2, 3, 5, 4, 7, 6]) """ cdef int i - cdef int *word_g = sig_malloc( self.nwords * sizeof(int) ) - cdef int *col_g = sig_malloc( self.ncols * sizeof(int) ) - if word_g is NULL or col_g is NULL: - if word_g is not NULL: sig_free(word_g) - if col_g is not NULL: sig_free(col_g) - raise MemoryError("Memory.") + cdef MemoryAllocator loc_mem = MemoryAllocator() + cdef int *word_g = loc_mem.malloc(self.nwords * sizeof(int)) + cdef int *col_g = loc_mem.malloc(self.ncols * sizeof(int)) self.get_permutation(other, word_g, col_g) word_l = [word_g[i] for i from 0 <= i < self.nwords] col_l = [col_g[i] for i from 0 <= i < self.ncols] - sig_free(word_g) - sig_free(col_g) return word_l, col_l cdef void get_permutation(self, PartitionStack other, int *word_gamma, int *col_gamma) noexcept: @@ -3073,66 +3015,28 @@ cdef class BinaryCodeClassifier: self.alpha_size = self.w_gamma_size + self.radix self.Phi_size = self.w_gamma_size/self.radix + 1 - self.w_gamma = sig_malloc( self.w_gamma_size * sizeof(int) ) - self.alpha = sig_malloc( self.alpha_size * sizeof(int) ) - self.Phi = sig_malloc( self.Phi_size * (self.L+1) * sizeof(unsigned int) ) - self.Omega = sig_malloc( self.Phi_size * self.L * sizeof(unsigned int) ) - self.W = sig_malloc( self.Phi_size * self.radix * 2 * sizeof(unsigned int) ) - - self.base = sig_malloc( self.radix * sizeof(int) ) - self.aut_gp_gens = sig_malloc( self.aut_gens_size * sizeof(int) ) - self.c_gamma = sig_malloc( self.radix * sizeof(int) ) - self.labeling = sig_malloc( self.radix * 3 * sizeof(int) ) - self.Lambda1 = sig_malloc( self.radix * 2 * sizeof(int) ) - self.Lambda2 = sig_malloc( self.radix * 2 * sizeof(int) ) - self.Lambda3 = sig_malloc( self.radix * 2 * sizeof(int) ) - self.v = sig_malloc( self.radix * 2 * sizeof(int) ) - self.e = sig_malloc( self.radix * 2 * sizeof(int) ) - - if self.Phi is NULL or self.Omega is NULL or self.W is NULL or self.Lambda1 is NULL \ - or self.Lambda2 is NULL or self.Lambda3 is NULL or self.w_gamma is NULL \ - or self.c_gamma is NULL or self.alpha is NULL or self.v is NULL or self.e is NULL \ - or self.aut_gp_gens is NULL or self.labeling is NULL or self.base is NULL: - if self.Phi is not NULL: sig_free(self.Phi) - if self.Omega is not NULL: sig_free(self.Omega) - if self.W is not NULL: sig_free(self.W) - if self.Lambda1 is not NULL: sig_free(self.Lambda1) - if self.Lambda2 is not NULL: sig_free(self.Lambda2) - if self.Lambda3 is not NULL: sig_free(self.Lambda3) - if self.w_gamma is not NULL: sig_free(self.w_gamma) - if self.c_gamma is not NULL: sig_free(self.c_gamma) - if self.alpha is not NULL: sig_free(self.alpha) - if self.v is not NULL: sig_free(self.v) - if self.e is not NULL: sig_free(self.e) - if self.aut_gp_gens is not NULL: sig_free(self.aut_gp_gens) - if self.labeling is not NULL: sig_free(self.labeling) - if self.base is not NULL: sig_free(self.base) - raise MemoryError("Memory.") - - def __dealloc__(self): - sig_free(self.ham_wts) - sig_free(self.Phi) - sig_free(self.Omega) - sig_free(self.W) - sig_free(self.Lambda1) - sig_free(self.Lambda2) - sig_free(self.Lambda3) - sig_free(self.c_gamma) - sig_free(self.w_gamma) - sig_free(self.alpha) - sig_free(self.v) - sig_free(self.e) - sig_free(self.aut_gp_gens) - sig_free(self.labeling) - sig_free(self.base) + self.mem = MemoryAllocator() + self.w_gamma = self.mem.malloc(self.w_gamma_size * sizeof(int)) + self.alpha = self.mem.malloc(self.alpha_size * sizeof(int)) + self.Phi = self.mem.malloc(self.Phi_size * (self.L+1) * sizeof(unsigned int)) + self.Omega = self.mem.malloc(self.Phi_size * self.L * sizeof(unsigned int)) + self.W = self.mem.malloc(self.Phi_size * self.radix * 2 * sizeof(unsigned int)) + + self.base = self.mem.malloc(self.radix * sizeof(int)) + self.aut_gp_gens = self.mem.malloc(self.aut_gens_size * sizeof(int)) + self.c_gamma = self.mem.malloc(self.radix * sizeof(int)) + self.labeling = self.mem.malloc(self.radix * 3 * sizeof(int)) + self.Lambda1 = self.mem.malloc(self.radix * 2 * sizeof(int)) + self.Lambda2 = self.mem.malloc(self.radix * 2 * sizeof(int)) + self.Lambda3 = self.mem.malloc(self.radix * 2 * sizeof(int)) + self.v = self.mem.malloc(self.radix * 2 * sizeof(int)) + self.e = self.mem.malloc(self.radix * 2 * sizeof(int)) cdef void record_automorphism(self, int *gamma, int ncols) noexcept: cdef int i, j if self.aut_gp_index + ncols > self.aut_gens_size: self.aut_gens_size *= 2 - self.aut_gp_gens = sig_realloc( self.aut_gp_gens, self.aut_gens_size * sizeof(int) ) - if self.aut_gp_gens is NULL: - raise MemoryError("Memory.") + self.aut_gp_gens = self.mem.realloc(self.aut_gp_gens, self.aut_gens_size * sizeof(int)) j = self.aut_gp_index for i from 0 <= i < ncols: self.aut_gp_gens[i+j] = gamma[i] @@ -3371,27 +3275,21 @@ cdef class BinaryCodeClassifier: self.w_gamma_size *= 2 self.alpha_size = self.w_gamma_size + self.radix self.Phi_size = self.w_gamma_size/self.radix + 1 - self.w_gamma = sig_realloc(self.w_gamma, self.w_gamma_size * sizeof(int) ) - self.alpha = sig_realloc(self.alpha, self.alpha_size * sizeof(int) ) - self.Phi = sig_realloc(self.Phi, self.Phi_size * self.L * sizeof(int) ) - self.Omega = sig_realloc(self.Omega, self.Phi_size * self.L * sizeof(int) ) - self.W = sig_realloc(self.W, self.Phi_size * self.radix * 2 * sizeof(int) ) - if self.w_gamma is NULL or self.alpha is NULL or self.Phi is NULL or self.Omega is NULL or self.W is NULL: - if self.w_gamma is not NULL: sig_free(self.w_gamma) - if self.alpha is not NULL: sig_free(self.alpha) - if self.Phi is not NULL: sig_free(self.Phi) - if self.Omega is not NULL: sig_free(self.Omega) - if self.W is not NULL: sig_free(self.W) - raise MemoryError("Memory.") + self.w_gamma = self.mem.realloc(self.w_gamma, self.w_gamma_size * sizeof(int)) + self.alpha = self.mem.realloc(self.alpha, self.alpha_size * sizeof(int)) + self.Phi = self.mem.realloc(self.Phi, self.Phi_size * self.L * sizeof(int)) + self.Omega = self.mem.realloc(self.Omega, self.Phi_size * self.L * sizeof(int)) + self.W = self.mem.realloc(self.W, self.Phi_size * self.radix * 2 * sizeof(int)) + for i from 0 <= i < self.Phi_size * self.L: self.Omega[i] = 0 word_gamma = self.w_gamma alpha = self.alpha # think of alpha as of length exactly nwords + ncols - Phi = self.Phi + Phi = self.Phi Omega = self.Omega - W = self.W - e = self.e - nu = PartitionStack(nrows, ncols) + W = self.W + e = self.e + nu = PartitionStack(nrows, ncols) Theta = OrbitPartition(nrows, ncols) # trivial case diff --git a/src/sage/coding/codecan/meson.build b/src/sage/coding/codecan/meson.build index 8749207de4b..1ccaca09b2a 100644 --- a/src/sage/coding/codecan/meson.build +++ b/src/sage/coding/codecan/meson.build @@ -1,4 +1,9 @@ -py.install_sources('all.py', 'codecan.pxd', subdir: 'sage/coding/codecan') +py.install_sources( + '__init__.py', + 'all.py', + 'codecan.pxd', + subdir: 'sage/coding/codecan', +) extension_data = { 'autgroup_can_label' : files('autgroup_can_label.pyx'), diff --git a/src/sage/coding/delsarte_bounds.py b/src/sage/coding/delsarte_bounds.py index a7cc35e058d..f3dedb7a720 100644 --- a/src/sage/coding/delsarte_bounds.py +++ b/src/sage/coding/delsarte_bounds.py @@ -201,9 +201,8 @@ def _delsarte_LP_building(n, d, d_star, q, isinteger, solver, maxc=0): constraint_1: 0 <= x_1 <= 0 constraint_2: 0 <= x_2 <= 0 constraint_3: -7 x_0 - 5 x_1 - 3 x_2 - x_3 + x_4 + 3 x_5 + 5 x_6 + 7 x_7 <= 0 - constraint_4: -7 x_0 - 5 x_1 - 3 x_2 - x_3 + x_4 + 3 x_5 + 5 x_6 + 7 x_7 <= 0 ... - constraint_16: - x_0 + x_1 - x_2 + x_3 - x_4 + x_5 - x_6 + x_7 <= 0 + constraint_9: - x_0 + x_1 - x_2 + x_3 - x_4 + x_5 - x_6 + x_7 <= 0 Variables: x_0 is a continuous variable (min=0, max=+oo) ... @@ -213,21 +212,20 @@ def _delsarte_LP_building(n, d, d_star, q, isinteger, solver, maxc=0): p = MixedIntegerLinearProgram(maximization=True, solver=solver) A = p.new_variable(integer=isinteger, nonnegative=True) - p.set_objective(sum([A[r] for r in range(n + 1)])) + p.set_objective(p.sum([A[r] for r in range(n + 1)])) p.add_constraint(A[0] == 1) for i in range(1, d): p.add_constraint(A[i] == 0) for j in range(1, n + 1): - rhs = sum([krawtchouk(n, q, j, r, check=False) * A[r] + rhs = p.sum([krawtchouk(n, q, j, r, check=False) * A[r] for r in range(n + 1)]) - p.add_constraint(0 <= rhs) if j >= d_star: p.add_constraint(0 <= rhs) else: # rhs is proportional to j-th weight of the dual code p.add_constraint(0 == rhs) if maxc > 0: - p.add_constraint(sum([A[r] for r in range(n + 1)]), max=maxc) + p.add_constraint(p.sum([A[r] for r in range(n + 1)]), max=maxc) return A, p @@ -275,7 +273,7 @@ def _delsarte_cwc_LP_building(n, d, w, solver, isinteger): p = MixedIntegerLinearProgram(maximization=True, solver=solver) A = p.new_variable(integer=isinteger, nonnegative=True) - p.set_objective(sum([A[2*r] for r in range(d//2, w+1)]) + 1) + p.set_objective(p.sum([A[2*r] for r in range(d//2, w+1)]) + 1) def _q(k, i): mu_i = 1 @@ -283,7 +281,7 @@ def _q(k, i): return mu_i*eberlein(n, w, i, k)/v_i for k in range(1, w+1): - p.add_constraint(sum([A[2*i]*_q(k, i) for i in range(d//2, w+1)]), + p.add_constraint(p.sum([A[2*i]*_q(k, i) for i in range(d//2, w+1)]), min=-1) return A, p @@ -622,7 +620,7 @@ def _delsarte_Q_LP_building(q, d, solver, isinteger): p = MixedIntegerLinearProgram(maximization=True, solver=solver) A = p.new_variable(integer=isinteger, nonnegative=True) - p.set_objective(sum([A[i] for i in range(n)])) + p.set_objective(p.sum([A[i] for i in range(n)])) p.add_constraint(A[0] == 1) @@ -634,7 +632,7 @@ def _delsarte_Q_LP_building(q, d, solver, isinteger): p.add_constraint(A[i] == 0) for k in range(1, n): - p.add_constraint(sum([q[k][i] * A[i] for i in range(n)]), min=0) + p.add_constraint(p.sum([q[k][i] * A[i] for i in range(n)]), min=0) return A, p diff --git a/src/sage/coding/grs_code.py b/src/sage/coding/grs_code.py index 2fada75c4a9..aead68b0bb3 100644 --- a/src/sage/coding/grs_code.py +++ b/src/sage/coding/grs_code.py @@ -1525,7 +1525,7 @@ def _polynomial_vanishing_at_alphas(self, PolRing): """ G = PolRing.one() x = PolRing.gen() - for i in range(0, self.code().length()): + for i in range(self.code().length()): G = G*(x-self.code().evaluation_points()[i]) return G @@ -1612,11 +1612,10 @@ def _decode_to_code_and_message(self, r): if n == C.dimension() or r in C: return r, self.connected_encoder().unencode_nocheck(r) - points = [(alphas[i], r[i]/col_mults[i]) for i in - range(0, n)] + points = [(alphas[i], r[i]/col_mults[i]) for i in range(n)] R = PolRing.lagrange_polynomial(points) - (Q1, Q0) = self._partial_xgcd(G, R, PolRing) + Q1, Q0 = self._partial_xgcd(G, R, PolRing) h, rem = Q1.quo_rem(Q0) if not rem.is_zero(): @@ -1915,6 +1914,12 @@ def decode_to_message(self, word_and_erasure_vector): sage: y = Chan(c) sage: D.connected_encoder().unencode(c) == D.decode_to_message(y) True + sage: n_era = C.minimum_distance() - 1 + sage: Chan = channels.ErrorErasureChannel(C.ambient_space(), + ....: D.decoding_radius(n_era), n_era) + sage: y = Chan(c) + sage: D.connected_encoder().unencode(c) == D.decode_to_message(y) + True TESTS: @@ -1958,14 +1963,14 @@ def decode_to_message(self, word_and_erasure_vector): [word[i] for i in range(len(word)) if not erasure_vector[i]]) C1_length = len(punctured_word) - if C1_length == k: - return self.connected_encoder().unencode_nocheck(word) C1_evaluation_points = [self.code().evaluation_points()[i] for i in range(n) if erasure_vector[i] != 1] C1_column_multipliers = [self.code().column_multipliers()[i] for i in range(n) if erasure_vector[i] != 1] C1 = GeneralizedReedSolomonCode(C1_evaluation_points, k, C1_column_multipliers) + if C1_length == k: + return C1.unencode(punctured_word, nocheck=True) return C1.decode_to_message(punctured_word) def decoding_radius(self, number_erasures): @@ -1997,7 +2002,7 @@ def decoding_radius(self, number_erasures): ValueError: The number of erasures exceed decoding capability """ diff = self.code().minimum_distance() - 1 - number_erasures - if diff <= 0: + if diff < 0: raise ValueError("The number of erasures exceed decoding capability") else: return diff // 2 diff --git a/src/sage/coding/guruswami_sudan/gs_decoder.py b/src/sage/coding/guruswami_sudan/gs_decoder.py index a5bf1cf345f..6d8e6d7944b 100644 --- a/src/sage/coding/guruswami_sudan/gs_decoder.py +++ b/src/sage/coding/guruswami_sudan/gs_decoder.py @@ -14,7 +14,7 @@ - David Lucas, ported the original implementation in Sage """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 David Lucas # 2015 Johan S. R. Nielsen # @@ -22,10 +22,9 @@ # 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 integer_floor as floor from sage.coding.grs_code import GeneralizedReedSolomonCode from sage.rings.integer_ring import ZZ from sage.coding.decoder import Decoder @@ -389,7 +388,7 @@ def get_tau(s, l): # Either s or l is set, but not both. First a shared local function def find_integral_max(real_max, f): """Given a real (local) maximum of a function `f`, return that of - the integers around `real_max` which gives the (local) integral + the integers around ``real_max`` which gives the (local) integral maximum, and the value of at that point.""" if real_max in ZZ: int_max = ZZ(real_max) @@ -849,15 +848,15 @@ def decode_to_code(self, r): s = self.multiplicity() l = self.list_size() tau = self.decoding_radius() - ## SETUP INTERPOLATION PROBLEM + # SETUP INTERPOLATION PROBLEM wy = k-1 - points = [(alphas[i], r[i]/colmults[i]) for i in range(0,len(alphas))] - ## SOLVE INTERPOLATION + points = [(alphas[i], r[i]/colmults[i]) for i in range(len(alphas))] + # SOLVE INTERPOLATION try: Q = self.interpolation_algorithm()(points, tau, (s,l), wy) except TypeError: raise ValueError("The provided interpolation algorithm has a wrong signature. See the documentation of `codes.decoders.GRSGuruswamiSudanDecoder.interpolation_algorithm()` for details") - ## EXAMINE THE FACTORS AND CONVERT TO CODEWORDS + # EXAMINE THE FACTORS AND CONVERT TO CODEWORDS try: polynomials = self.rootfinding_algorithm()(Q, maxd=wy) except TypeError: diff --git a/src/sage/coding/guruswami_sudan/interpolation.py b/src/sage/coding/guruswami_sudan/interpolation.py index b1334307e79..bfeb0efd2a9 100644 --- a/src/sage/coding/guruswami_sudan/interpolation.py +++ b/src/sage/coding/guruswami_sudan/interpolation.py @@ -24,7 +24,7 @@ from sage.matrix.constructor import matrix from sage.misc.misc_c import prod -####################### Linear algebra system solving ############################### +# ###################### Linear algebra system solving ############################### def _flatten_once(lstlst): @@ -50,9 +50,9 @@ def _flatten_once(lstlst): for lst in lstlst: yield from lst -#************************************************************* +# ************************************************************* # Linear algebraic Interpolation algorithm, helper functions -#************************************************************* +# ************************************************************* def _monomial_list(maxdeg, l, wy): @@ -137,9 +137,9 @@ def eqs_affine(x0, y0): jhat = monomial[1] if ihat >= i and jhat >= j: icoeff = binomial(ihat, i) * x0**(ihat-i) \ - if ihat > i else 1 + if ihat > i else 1 jcoeff = binomial(jhat, j) * y0**(jhat-j) \ - if jhat > j else 1 + if jhat > j else 1 eq[monomial] = jcoeff * icoeff eqs.append([eq.get(monomial, 0) for monomial in monomials]) return eqs @@ -284,12 +284,12 @@ def gs_interpolation_linalg(points, tau, parameters, wy): # Pick a nonzero element from the right kernel sol = Ker.basis()[0] # Construct the Q polynomial - PF = M.base_ring()['x', 'y'] #make that ring a ring in + PF = M.base_ring()['x', 'y'] # make that ring a ring in x, y = PF.gens() - Q = sum([x**monomials[i][0] * y**monomials[i][1] * sol[i] for i in range(0, len(monomials))]) - return Q + return sum([x**m[0] * y**m[1] * sol[i] + for i, m in enumerate(monomials)]) -####################### Lee-O'Sullivan's method ############################### +# ###################### Lee-O'Sullivan's method ############################### def lee_osullivan_module(points, parameters, wy): @@ -342,14 +342,15 @@ def lee_osullivan_module(points, parameters, wy): PF = F['x'] x = PF.gens()[0] R = PF.lagrange_polynomial(points) - G = prod(x - points[i][0] for i in range(0, len(points))) + G = prod(x - points[i][0] for i in range(len(points))) PFy = PF['y'] y = PFy.gens()[0] - ybasis = [(y-R)**i * G**(s-i) for i in range(0, s+1)] \ - + [y**(i-s) * (y-R)**s for i in range(s+1, l+1)] + ybasis = [(y-R)**i * G**(s-i) for i in range(s + 1)] \ + + [y**(i-s) * (y-R)**s for i in range(s + 1, l + 1)] def pad(lst): return lst + [0]*(l+1-len(lst)) + modbasis = [pad(yb.coefficients(sparse=False)) for yb in ybasis] return matrix(PF, modbasis) @@ -397,12 +398,11 @@ def gs_interpolation_lee_osullivan(points, tau, parameters, wy): from .utils import _degree_of_vector s, l = parameters[0], parameters[1] F = points[0][0].parent() - M = lee_osullivan_module(points, (s,l), wy) - shifts = [i * wy for i in range(0,l+1)] + M = lee_osullivan_module(points, (s, l), wy) + shifts = [i * wy for i in range(l + 1)] Mnew = M.reduced_form(shifts=shifts) # Construct Q as the element of the row with the lowest weighted degree Qlist = min(Mnew.rows(), key=lambda r: _degree_of_vector(r, shifts)) PFxy = F['x,y'] xx, yy = PFxy.gens() - Q = sum(yy**i * PFxy(Qlist[i]) for i in range(0,l+1)) - return Q + return sum(yy**i * PFxy(Qlist[i]) for i in range(l + 1)) diff --git a/src/sage/coding/linear_code.py b/src/sage/coding/linear_code.py index 3e9d388c434..0a7fdd5080b 100644 --- a/src/sage/coding/linear_code.py +++ b/src/sage/coding/linear_code.py @@ -80,12 +80,10 @@ class should inherit from this class. Also ``AbstractLinearCode`` should never sage: G = MS([[1,1,1,0,0,0,0], [1,0,0,1,1,0,0], [0,1,0,1,0,1,0], [1,1,0,1,0,0,1]]) sage: C = LinearCode(G) sage: C.basis() - [ - (1, 1, 1, 0, 0, 0, 0), - (1, 0, 0, 1, 1, 0, 0), - (0, 1, 0, 1, 0, 1, 0), - (1, 1, 0, 1, 0, 0, 1) - ] + [(1, 1, 1, 0, 0, 0, 0), + (1, 0, 0, 1, 1, 0, 0), + (0, 1, 0, 1, 0, 1, 0), + (1, 1, 0, 1, 0, 0, 1)] sage: c = C.basis()[1] sage: c in C True @@ -2301,11 +2299,9 @@ def __init__(self, generator, d=None): ....: [a, a + 1, 1, a + 1, 1, 0, 0]]) sage: C = LinearCode(G) sage: C.basis() - [ - (1, 0, 0, a + 1, 0, 1, 0), - (0, 1, 0, 0, a + 1, 0, 1), - (0, 0, 1, a, a + 1, a, a + 1) - ] + [(1, 0, 0, a + 1, 0, 1, 0), + (0, 1, 0, 0, a + 1, 0, 1), + (0, 0, 1, a, a + 1, a, a + 1)] sage: C.minimum_distance() # needs sage.libs.gap 3 diff --git a/src/sage/coding/linear_code_no_metric.py b/src/sage/coding/linear_code_no_metric.py index 49c30a415c8..9bf754db170 100644 --- a/src/sage/coding/linear_code_no_metric.py +++ b/src/sage/coding/linear_code_no_metric.py @@ -191,7 +191,7 @@ def __init__(self, base_field, length, default_encoder_name, default_decoder_nam super().__init__(length, default_encoder_name, default_decoder_name, metric) cat = Modules(base_field).FiniteDimensional().WithBasis().Finite() facade_for = VectorSpace(base_field, self._length) - self.Element = type(facade_for.an_element()) # for when we made this a non-facade parent + self.Element = facade_for.Element Parent.__init__(self, base=base_field, facade=facade_for, category=cat) def base_field(self): @@ -397,12 +397,10 @@ def basis(self): sage: C = codes.HammingCode(GF(2), 3) sage: C.basis() - [ - (1, 0, 0, 0, 0, 1, 1), - (0, 1, 0, 0, 1, 0, 1), - (0, 0, 1, 0, 1, 1, 0), - (0, 0, 0, 1, 1, 1, 1) - ] + [(1, 0, 0, 0, 0, 1, 1), + (0, 1, 0, 0, 1, 0, 1), + (0, 0, 1, 0, 1, 1, 0), + (0, 0, 0, 1, 1, 1, 1)] sage: C.basis().universe() Vector space of dimension 7 over Finite Field of size 2 """ diff --git a/src/sage/coding/meson.build b/src/sage/coding/meson.build index 65b2e0d8eb1..b311c8df5d5 100644 --- a/src/sage/coding/meson.build +++ b/src/sage/coding/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'abstract_code.py', 'ag_code.py', 'all.py', diff --git a/src/sage/coding/reed_muller_code.py b/src/sage/coding/reed_muller_code.py index e690534c5e3..4f7759440ab 100644 --- a/src/sage/coding/reed_muller_code.py +++ b/src/sage/coding/reed_muller_code.py @@ -396,11 +396,22 @@ class directly, as :meth:`ReedMullerCode` creates either a binary or a EXAMPLES: - A binary Reed-Muller code can be constructed by simply giving the order of the code and the number of variables:: + A binary Reed-Muller code can be constructed by simply giving the order of + the code and the number of variables:: sage: C = codes.BinaryReedMullerCode(2, 4) sage: C Binary Reed-Muller Code of order 2 and number of variables 4 + + Very large Reed-Muller codes can be constructed without building + the generator matrix or elements of the code (fixes :issue:`33229`, + see also :issue:`39110`):: + + sage: C = codes.BinaryReedMullerCode(16, 32) + sage: C + Binary Reed-Muller Code of order 16 and number of variables 32 + sage: C.dimension(), C.length() + (2448023843, 4294967296) """ _registered_encoders = {} diff --git a/src/sage/combinat/abstract_tree.py b/src/sage/combinat/abstract_tree.py index 8ea604428f1..8359b3a8198 100644 --- a/src/sage/combinat/abstract_tree.py +++ b/src/sage/combinat/abstract_tree.py @@ -1857,7 +1857,7 @@ def __setitem__(self, idx, value): The tree ``self`` must be in a mutable state. See :mod:`sage.structure.list_clone` for more details about mutability. The default implementation here assume that the - container of the node implement a method `_setitem` with signature + container of the node implement a method ``_setitem`` with signature `self._setitem(idx, value)`. It is usually provided by inheriting from :class:`~sage.structure.list_clone.ClonableArray`. diff --git a/src/sage/combinat/bijectionist.py b/src/sage/combinat/bijectionist.py index ce1bf8aca13..2020b729917 100644 --- a/src/sage/combinat/bijectionist.py +++ b/src/sage/combinat/bijectionist.py @@ -69,52 +69,52 @@ sage: a, b = bij.statistics_table() sage: table(a, header_row=True, frame=True) ┌───────────┬────────┬────────┬────────┐ - │ a | α_1(a) | α_2(a) | α_3(a) | + │ a │ α_1(a) │ α_2(a) │ α_3(a) │ ╞═══════════╪════════╪════════╪════════╡ - │ [] | 0 | 0 | 0 | + │ [] │ 0 │ 0 │ 0 │ ├───────────┼────────┼────────┼────────┤ - │ [1] | 1 | 1 | 1 | + │ [1] │ 1 │ 1 │ 1 │ ├───────────┼────────┼────────┼────────┤ - │ [1, 2] | 2 | 2 | 2 | + │ [1, 2] │ 2 │ 2 │ 2 │ ├───────────┼────────┼────────┼────────┤ - │ [2, 1] | 2 | 1 | 0 | + │ [2, 1] │ 2 │ 1 │ 0 │ ├───────────┼────────┼────────┼────────┤ - │ [1, 2, 3] | 3 | 3 | 3 | + │ [1, 2, 3] │ 3 │ 3 │ 3 │ ├───────────┼────────┼────────┼────────┤ - │ [1, 3, 2] | 3 | 2 | 1 | + │ [1, 3, 2] │ 3 │ 2 │ 1 │ ├───────────┼────────┼────────┼────────┤ - │ [2, 1, 3] | 3 | 2 | 1 | + │ [2, 1, 3] │ 3 │ 2 │ 1 │ ├───────────┼────────┼────────┼────────┤ - │ [2, 3, 1] | 3 | 2 | 0 | + │ [2, 3, 1] │ 3 │ 2 │ 0 │ ├───────────┼────────┼────────┼────────┤ - │ [3, 1, 2] | 3 | 1 | 0 | + │ [3, 1, 2] │ 3 │ 1 │ 0 │ ├───────────┼────────┼────────┼────────┤ - │ [3, 2, 1] | 3 | 2 | 1 | + │ [3, 2, 1] │ 3 │ 2 │ 1 │ └───────────┴────────┴────────┴────────┘ sage: table(b, header_row=True, frame=True) ┌───────────┬───┬────────┬────────┬────────┐ - │ b | τ | β_1(b) | β_2(b) | β_3(b) | + │ b │ τ │ β_1(b) │ β_2(b) │ β_3(b) │ ╞═══════════╪═══╪════════╪════════╪════════╡ - │ [] | 0 | 0 | 0 | 0 | + │ [] │ 0 │ 0 │ 0 │ 0 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [1] | 1 | 1 | 1 | 1 | + │ [1] │ 1 │ 1 │ 1 │ 1 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [1, 2] | 2 | 2 | 1 | 0 | + │ [1, 2] │ 2 │ 2 │ 1 │ 0 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [2, 1] | 1 | 2 | 2 | 2 | + │ [2, 1] │ 1 │ 2 │ 2 │ 2 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [1, 2, 3] | 3 | 3 | 1 | 0 | + │ [1, 2, 3] │ 3 │ 3 │ 1 │ 0 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [1, 3, 2] | 2 | 3 | 2 | 1 | + │ [1, 3, 2] │ 2 │ 3 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [2, 1, 3] | 2 | 3 | 2 | 1 | + │ [2, 1, 3] │ 2 │ 3 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [2, 3, 1] | 2 | 3 | 2 | 1 | + │ [2, 3, 1] │ 2 │ 3 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [3, 1, 2] | 2 | 3 | 2 | 0 | + │ [3, 1, 2] │ 2 │ 3 │ 2 │ 0 │ ├───────────┼───┼────────┼────────┼────────┤ - │ [3, 2, 1] | 1 | 3 | 3 | 3 | + │ [3, 2, 1] │ 1 │ 3 │ 3 │ 3 │ └───────────┴───┴────────┴────────┴────────┘ sage: from sage.combinat.cyclic_sieving_phenomenon import orbit_decomposition @@ -849,51 +849,51 @@ def statistics_table(self, header=True): sage: a, b = bij.statistics_table() sage: table(a, header_row=True, frame=True) ┌───────────┬────────┬────────┐ - │ a | α_1(a) | α_2(a) | + │ a │ α_1(a) │ α_2(a) │ ╞═══════════╪════════╪════════╡ - │ [] | 0 | 0 | + │ [] │ 0 │ 0 │ ├───────────┼────────┼────────┤ - │ [1] | 1 | 1 | + │ [1] │ 1 │ 1 │ ├───────────┼────────┼────────┤ - │ [1, 2] | 2 | 2 | + │ [1, 2] │ 2 │ 2 │ ├───────────┼────────┼────────┤ - │ [2, 1] | 1 | 0 | + │ [2, 1] │ 1 │ 0 │ ├───────────┼────────┼────────┤ - │ [1, 2, 3] | 3 | 3 | + │ [1, 2, 3] │ 3 │ 3 │ ├───────────┼────────┼────────┤ - │ [1, 3, 2] | 2 | 1 | + │ [1, 3, 2] │ 2 │ 1 │ ├───────────┼────────┼────────┤ - │ [2, 1, 3] | 2 | 1 | + │ [2, 1, 3] │ 2 │ 1 │ ├───────────┼────────┼────────┤ - │ [2, 3, 1] | 2 | 0 | + │ [2, 3, 1] │ 2 │ 0 │ ├───────────┼────────┼────────┤ - │ [3, 1, 2] | 1 | 0 | + │ [3, 1, 2] │ 1 │ 0 │ ├───────────┼────────┼────────┤ - │ [3, 2, 1] | 2 | 1 | + │ [3, 2, 1] │ 2 │ 1 │ └───────────┴────────┴────────┘ sage: table(b, header_row=True, frame=True) ┌───────────┬───┬────────┬────────┐ - │ b | τ | β_1(b) | β_2(b) | + │ b │ τ │ β_1(b) │ β_2(b) │ ╞═══════════╪═══╪════════╪════════╡ - │ [] | 0 | 0 | 0 | + │ [] │ 0 │ 0 │ 0 │ ├───────────┼───┼────────┼────────┤ - │ [1] | 1 | 1 | 1 | + │ [1] │ 1 │ 1 │ 1 │ ├───────────┼───┼────────┼────────┤ - │ [1, 2] | 2 | 1 | 0 | + │ [1, 2] │ 2 │ 1 │ 0 │ ├───────────┼───┼────────┼────────┤ - │ [2, 1] | 1 | 2 | 2 | + │ [2, 1] │ 1 │ 2 │ 2 │ ├───────────┼───┼────────┼────────┤ - │ [1, 2, 3] | 3 | 1 | 0 | + │ [1, 2, 3] │ 3 │ 1 │ 0 │ ├───────────┼───┼────────┼────────┤ - │ [1, 3, 2] | 2 | 2 | 1 | + │ [1, 3, 2] │ 2 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┤ - │ [2, 1, 3] | 2 | 2 | 1 | + │ [2, 1, 3] │ 2 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┤ - │ [2, 3, 1] | 2 | 2 | 1 | + │ [2, 3, 1] │ 2 │ 2 │ 1 │ ├───────────┼───┼────────┼────────┤ - │ [3, 1, 2] | 2 | 2 | 0 | + │ [3, 1, 2] │ 2 │ 2 │ 0 │ ├───────────┼───┼────────┼────────┤ - │ [3, 2, 1] | 1 | 3 | 3 | + │ [3, 2, 1] │ 1 │ 3 │ 3 │ └───────────┴───┴────────┴────────┘ TESTS: @@ -906,27 +906,27 @@ def statistics_table(self, header=True): sage: a, b = bij.statistics_table() sage: table(a, header_row=True, frame=True) ┌────────┐ - │ a | + │ a │ ╞════════╡ - │ [] | + │ [] │ ├────────┤ - │ [1] | + │ [1] │ ├────────┤ - │ [1, 2] | + │ [1, 2] │ ├────────┤ - │ [2, 1] | + │ [2, 1] │ └────────┘ sage: table(b, header_row=True, frame=True) ┌────────┬───┐ - │ b | τ | + │ b │ τ │ ╞════════╪═══╡ - │ [] | 0 | + │ [] │ 0 │ ├────────┼───┤ - │ [1] | 1 | + │ [1] │ 1 │ ├────────┼───┤ - │ [1, 2] | 2 | + │ [1, 2] │ 2 │ ├────────┼───┤ - │ [2, 1] | 1 | + │ [2, 1] │ 1 │ └────────┴───┘ We can omit the header:: diff --git a/src/sage/combinat/binary_recurrence_sequences.py b/src/sage/combinat/binary_recurrence_sequences.py index df8de0ada86..fd695c83e0d 100644 --- a/src/sage/combinat/binary_recurrence_sequences.py +++ b/src/sage/combinat/binary_recurrence_sequences.py @@ -729,8 +729,8 @@ def pthpowers(self, p, Bound): # Check how long each element has persisted, if it is for at least 7 cycles, # then we check to see if it is actually a perfect power - for i in Possible_count: - if Possible_count[i] == 7: + for i, pci in Possible_count.items(): + if pci == 7: n = Integer(i) if n < Bound: if _is_p_power(self(n), p): diff --git a/src/sage/combinat/chas/wqsym.py b/src/sage/combinat/chas/wqsym.py index 50811f08cb8..8e100ebcf2e 100644 --- a/src/sage/combinat/chas/wqsym.py +++ b/src/sage/combinat/chas/wqsym.py @@ -986,12 +986,12 @@ def union(X, Y): cur = {data[0]: 1} for B in data[1:]: ret = {} - for A in cur: + for A, curA in cur.items(): for C in ShuffleProduct_overlapping(A, B, element_constructor=OSP, add=union): if C in ret: - ret[C] += cur[A] + ret[C] += curA else: - ret[C] = cur[A] + ret[C] = curA cur = ret # Return the result in the X basis diff --git a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py index c9f06a4761f..76be4d8bf02 100644 --- a/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +++ b/src/sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py @@ -1985,7 +1985,7 @@ def __init__(self, *args): """ data = args if len(data) < 2 or not all(isinstance(comp, QuiverMutationType_Irreducible) for comp in data): - return _mutation_type_error(data) + _mutation_type_error(data) # _info is initialized self._info = {} diff --git a/src/sage/combinat/crystals/meson.build b/src/sage/combinat/crystals/meson.build index 96ff9f4e19e..5c6b864d04a 100644 --- a/src/sage/combinat/crystals/meson.build +++ b/src/sage/combinat/crystals/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'affine.py', 'affine_factorization.py', 'affinization.py', diff --git a/src/sage/combinat/crystals/pbw_datum.pyx b/src/sage/combinat/crystals/pbw_datum.pyx index 03a7aee51d9..fa3be1ca72e 100644 --- a/src/sage/combinat/crystals/pbw_datum.pyx +++ b/src/sage/combinat/crystals/pbw_datum.pyx @@ -167,7 +167,7 @@ class PBWDatum(): def star(self): """ Return the starred version of ``self``, i.e., - with reversed `long_word` and `lusztig_datum` + with reversed ``long_word`` and ``lusztig_datum`` EXAMPLES:: diff --git a/src/sage/combinat/crystals/spins.pyx b/src/sage/combinat/crystals/spins.pyx index 5ff109602d0..28729fc93c0 100644 --- a/src/sage/combinat/crystals/spins.pyx +++ b/src/sage/combinat/crystals/spins.pyx @@ -65,7 +65,7 @@ def CrystalOfSpins(ct): Return the spin crystal of the given type `B`. This is a combinatorial model for the crystal with highest weight - `Lambda_n` (the `n`-th fundamental weight). It has + `\Lambda_n` (the `n`-th fundamental weight). It has `2^n` elements, here called Spins. See also :func:`~sage.combinat.crystals.letters.CrystalOfLetters`, :func:`~sage.combinat.crystals.spins.CrystalOfSpinsPlus`, @@ -108,7 +108,7 @@ def CrystalOfSpinsPlus(ct): r""" Return the plus spin crystal of the given type D. - This is the crystal with highest weight `Lambda_n` (the + This is the crystal with highest weight `\Lambda_n` (the `n`-th fundamental weight). INPUT: @@ -141,7 +141,7 @@ def CrystalOfSpinsMinus(ct): r""" Return the minus spin crystal of the given type D. - This is the crystal with highest weight `Lambda_{n-1}` + This is the crystal with highest weight `\Lambda_{n-1}` (the `(n-1)`-st fundamental weight). INPUT: diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index 09785c3d1da..02391553032 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -1277,14 +1277,14 @@ def BIBD_5q_5_for_q_prime_power(q): d = (q-1)//4 B = [] - F = FiniteField(q,'x') + F = FiniteField(q, 'x') a = F.primitive_element() - L = {b:i for i,b in enumerate(F)} - for b in L: - B.append([i*q + L[b] for i in range(5)]) + L = {b: i for i, b in enumerate(F)} + for b, Lb in L.items(): + B.append([i*q + Lb for i in range(5)]) for i in range(5): for j in range(d): - B.append([ i*q + L[b ], + B.append([ i*q + Lb, ((i+1) % 5)*q + L[ a**j+b ], ((i+1) % 5)*q + L[-a**j+b ], ((i+4) % 5)*q + L[ a**(j+d)+b], diff --git a/src/sage/combinat/designs/designs_pyx.pyx b/src/sage/combinat/designs/designs_pyx.pyx index 790111d4326..571d7e27c35 100644 --- a/src/sage/combinat/designs/designs_pyx.pyx +++ b/src/sage/combinat/designs/designs_pyx.pyx @@ -11,7 +11,8 @@ from sage.data_structures.bitset_base cimport * from libc.string cimport memset -from cysignals.memory cimport sig_malloc, sig_calloc, sig_realloc, sig_free +from cysignals.memory cimport sig_malloc, sig_realloc, sig_free +from memory_allocator cimport MemoryAllocator from sage.misc.unknown import Unknown @@ -305,7 +306,8 @@ def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology='O cdef int i,j,l # A copy of OA - cdef unsigned short * OAc = sig_malloc(k*n2*sizeof(unsigned short)) + cdef MemoryAllocator mem = MemoryAllocator() + cdef unsigned short * OAc = mem.malloc(k*n2*sizeof(unsigned short)) cdef unsigned short * C1 cdef unsigned short * C2 @@ -321,7 +323,6 @@ def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology='O if verbose: print({"OA": "{} is not in the interval [0..{}]".format(x,n-1), "MOLS": "Entry {} was expected to be in the interval [0..{}]".format(x,n-1)}[terminology]) - sig_free(OAc) return False OAc[j*n2+i] = x @@ -338,14 +339,12 @@ def is_orthogonal_array(OA, int k, int n, int t=2, verbose=False, terminology='O bitset_add(seen,n*C1[l]+C2[l]) if bitset_len(seen) != n2: # Have we seen all pairs ? - sig_free(OAc) bitset_free(seen) if verbose: print({"OA": "Columns {} and {} are not orthogonal".format(i,j), "MOLS": "Squares {} and {} are not orthogonal".format(i,j)}[terminology]) return False - sig_free(OAc) bitset_free(seen) return True @@ -469,9 +468,8 @@ def is_group_divisible_design(groups, blocks, v, G=None, K=None, lambd=1, verbos print("{} does not belong to [0,...,{}]".format(x, n-1)) return False - cdef unsigned short * matrix = sig_calloc(n*n, sizeof(unsigned short)) - if matrix is NULL: - raise MemoryError + cdef MemoryAllocator mem = MemoryAllocator() + cdef unsigned short * matrix = mem.calloc(n*n, sizeof(unsigned short)) # Counts the number of occurrences of each pair of points for b in blocks: @@ -500,7 +498,6 @@ def is_group_divisible_design(groups, blocks, v, G=None, K=None, lambd=1, verbos if not len(g) in G: if verbose: print("a group has size {} while G={}".format(len(g),list(G))) - sig_free(matrix) return False # Checks that two points of the same group were never covered @@ -513,7 +510,6 @@ def is_group_divisible_design(groups, blocks, v, G=None, K=None, lambd=1, verbos if matrix[ii*n+jj] != 0: if verbose: print("the pair ({},{}) belongs to a group but appears in some block".format(ii, jj)) - sig_free(matrix) return False # We fill the entries with what is expected by the next loop @@ -526,11 +522,8 @@ def is_group_divisible_design(groups, blocks, v, G=None, K=None, lambd=1, verbos if matrix[i*n+j] != l: if verbose: print("the pair ({},{}) has been seen {} times but lambda={}".format(i,j,matrix[i*n+j],l)) - sig_free(matrix) return False - sig_free(matrix) - return True if not guess_groups else (True, groups) @@ -822,9 +815,9 @@ def is_quasi_difference_matrix(M, G, int k, int lmbda, int mu, int u, verbose=Fa # Width of the matrix for R in M: - if len(R)!=k: + if len(R) != k: if verbose: - print("The matrix has {} columns but k={}".format(len(R),k)) + print("The matrix has {} columns but k={}".format(len(R), k)) return False # When |G|=0 @@ -836,16 +829,11 @@ def is_quasi_difference_matrix(M, G, int k, int lmbda, int mu, int u, verbose=Fa cdef dict group_to_int = {v:i for i,v in enumerate(int_to_group)} # Allocations - cdef int ** x_minus_y = sig_malloc((n+1)*sizeof(int *)) - cdef int * x_minus_y_data = sig_malloc((n+1)*(n+1)*sizeof(int)) - cdef int * M_c = sig_malloc(k*M_nrows*sizeof(int)) - cdef int * G_seen = sig_malloc((n+1)*sizeof(int)) - if (x_minus_y == NULL or x_minus_y_data == NULL or M_c == NULL or G_seen == NULL): - sig_free(x_minus_y) - sig_free(x_minus_y_data) - sig_free(G_seen) - sig_free(M_c) - raise MemoryError + cdef MemoryAllocator mem = MemoryAllocator() + cdef int ** x_minus_y = mem.malloc((n+1)*sizeof(int *)) + cdef int * x_minus_y_data = mem.malloc((n+1)*(n+1)*sizeof(int)) + cdef int * M_c = mem.malloc(k*M_nrows*sizeof(int)) + cdef int * G_seen = mem.malloc((n+1)*sizeof(int)) # The "x-y" table. If g_i, g_j \in G, then x_minus_y[i][j] is equal to # group_to_int[g_i-g_j]. @@ -883,10 +871,6 @@ def is_quasi_difference_matrix(M, G, int k, int lmbda, int mu, int u, verbose=Fa if bit: if verbose: print("Row {} contains more than one empty entry".format(i)) - sig_free(x_minus_y_data) - sig_free(x_minus_y) - sig_free(G_seen) - sig_free(M_c) return False bit = True @@ -900,10 +884,6 @@ def is_quasi_difference_matrix(M, G, int k, int lmbda, int mu, int u, verbose=Fa if verbose: print("Column {} contains {} empty entries instead of the expected " "lambda.u={}.{}={}".format(j, ii, lmbda, u, lmbda*u)) - sig_free(x_minus_y_data) - sig_free(x_minus_y) - sig_free(G_seen) - sig_free(M_c) return False # We are now ready to test every pair of columns @@ -917,10 +897,6 @@ def is_quasi_difference_matrix(M, G, int k, int lmbda, int mu, int u, verbose=Fa if verbose: print("Columns {} and {} generate 0 exactly {} times " "instead of the expected mu(={})".format(i,j,G_seen[0],mu)) - sig_free(x_minus_y_data) - sig_free(x_minus_y) - sig_free(G_seen) - sig_free(M_c) return False for ii in range(1,n): # bad number of g_ii\in G @@ -929,16 +905,8 @@ def is_quasi_difference_matrix(M, G, int k, int lmbda, int mu, int u, verbose=Fa print("Columns {} and {} do not generate all elements of G " "exactly lambda(={}) times. The element {} appeared {} " "times as a difference.".format(i,j,lmbda,int_to_group[ii],G_seen[ii])) - sig_free(x_minus_y_data) - sig_free(x_minus_y) - sig_free(G_seen) - sig_free(M_c) return False - sig_free(x_minus_y_data) - sig_free(x_minus_y) - sig_free(G_seen) - sig_free(M_c) return True diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index a74634d32cf..3cb8c96d827 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -292,8 +292,8 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): # Normalized number of occurrences added to counter stabi = len(stab[i]) - for gg in tmp_counter: - counter[gg] += tmp_counter[gg]//stabi + for gg, tmp_gg in tmp_counter.items(): + counter[gg] += tmp_gg // stabi # Check the counter and report any error too_few = [] @@ -1579,7 +1579,7 @@ def is_relative_difference_set(R, G, H, params, verbose=False): - ``H`` -- list; a submodule of ``G`` of order `n` - ``params`` -- tuple in the form `(m, n, k, d)` - ``verbose`` -- boolean (default: ``False``); if ``True``, the function - will be verbose when the sequences do not satisfy the contraints + will be verbose when the sequences do not satisfy the constraints EXAMPLES:: @@ -1659,7 +1659,7 @@ def is_supplementary_difference_set(Ks, v=None, lmbda=None, G=None, verbose=Fals - ``lmbda`` -- integer; the parameter `\lambda` of the supplementary difference sets - ``G`` -- a group of order `v` - ``verbose`` -- boolean (default: ``False``); if ``True``, the function will - be verbose when the sets do not satisfy the contraints + be verbose when the sets do not satisfy the constraints EXAMPLES:: @@ -1757,7 +1757,7 @@ def supplementary_difference_set_from_rel_diff_set(q, existence=False, check=Tru OUTPUT: If ``existence=False``, the function returns the 4 sets (containing integers), - or raises an error if ``q`` does not satify the constraints. + or raises an error if ``q`` does not satisfy the constraints. If ``existence=True``, the function returns a boolean representing whether supplementary difference sets can be constructed. @@ -3084,7 +3084,7 @@ def are_complementary_difference_sets(G, A, B, verbose=False): - ``A`` -- set of elements of ``G`` - ``B`` -- set of elements of ``G`` - ``verbose`` -- boolean (default: ``False``); if ``True`` the function will - be verbose when the sets do not satisfy the contraints + be verbose when the sets do not satisfy the constraints EXAMPLES:: diff --git a/src/sage/combinat/designs/evenly_distributed_sets.pyx b/src/sage/combinat/designs/evenly_distributed_sets.pyx index 8fdf10c0bf1..61b44cc5da1 100644 --- a/src/sage/combinat/designs/evenly_distributed_sets.pyx +++ b/src/sage/combinat/designs/evenly_distributed_sets.pyx @@ -18,14 +18,15 @@ Classes and methods cimport cython -from sage.categories.fields import Fields from libc.limits cimport UINT_MAX from libc.string cimport memset, memcpy - -from cysignals.memory cimport check_malloc, check_calloc, sig_free +from memory_allocator cimport MemoryAllocator from sage.rings.integer cimport smallInteger +from sage.categories.fields import Fields + + cdef class EvenlyDistributedSetsBacktracker: r""" Set of evenly distributed subsets in finite fields. @@ -168,17 +169,8 @@ cdef class EvenlyDistributedSetsBacktracker: cdef unsigned int * cosets # e array: cosets of differences of elts in B cdef unsigned int * t # e array: temporary variable for updates - def __dealloc__(self): - if self.diff != NULL: - sig_free(self.diff[0]) - sig_free(self.diff) - if self.ratio != NULL: - sig_free(self.ratio[0]) - sig_free(self.ratio) - sig_free(self.min_orb) - sig_free(self.B) - sig_free(self.cosets) - sig_free(self.t) + # MANAGEMENT OF MEMORY + cdef MemoryAllocator mem def __init__(self, K, k, up_to_isomorphism=True, check=False): r""" @@ -228,20 +220,21 @@ cdef class EvenlyDistributedSetsBacktracker: self.m = (q - 1) // e self.K = K - self.diff = check_calloc(q, sizeof(unsigned int *)) - self.diff[0] = check_malloc(q*q*sizeof(unsigned int)) + self.mem = MemoryAllocator() + self.diff = self.mem.calloc(q, sizeof(unsigned int *)) + self.diff[0] = self.mem.malloc(q*q*sizeof(unsigned int)) for i in range(1, self.q): self.diff[i] = self.diff[i-1] + q - self.ratio = check_calloc(q, sizeof(unsigned int *)) - self.ratio[0] = check_malloc(q*q*sizeof(unsigned int)) + self.ratio = self.mem.calloc(q, sizeof(unsigned int *)) + self.ratio[0] = self.mem.malloc(q*q*sizeof(unsigned int)) for i in range(1, self.q): self.ratio[i] = self.ratio[i-1] + q - self.B = check_malloc(k*sizeof(unsigned int)) - self.min_orb = check_malloc(q*sizeof(unsigned int)) - self.cosets = check_malloc(e*sizeof(unsigned int)) - self.t = check_malloc(e*sizeof(unsigned int)) + self.B = self.mem.malloc(k*sizeof(unsigned int)) + self.min_orb = self.mem.malloc(q*sizeof(unsigned int)) + self.cosets = self.mem.malloc(e*sizeof(unsigned int)) + self.t = self.mem.malloc(e*sizeof(unsigned int)) x = K.multiplicative_generator() list_K = [] @@ -408,7 +401,7 @@ cdef class EvenlyDistributedSetsBacktracker: whether the set `f_{ij}(B)` is smaller than `B`. This is an internal function and should only be call by the backtracker - implemented in the method `__iter__`. + implemented in the method ``__iter__``. OUTPUT: ``False`` if ``self.B`` is not minimal diff --git a/src/sage/combinat/designs/incidence_structures.py b/src/sage/combinat/designs/incidence_structures.py index e9964af900c..3c6170e1ea3 100644 --- a/src/sage/combinat/designs/incidence_structures.py +++ b/src/sage/combinat/designs/incidence_structures.py @@ -1592,6 +1592,13 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): sage: I = IncidenceStructure(2, [[0],[0,1]]) sage: I.is_t_design(return_parameters=True) (False, (0, 0, 0, 0)) + + Verify that :issue:`38454` is fixed:: + + sage: I = IncidenceStructure(points=[0,1,2,3,4,5], + ....: blocks=[[0,1], [1,2], [0,2]]) + sage: I.is_t_design(return_parameters=True) + (True, (0, 6, 2, 3)) """ from sage.arith.misc import binomial @@ -1653,7 +1660,7 @@ def is_t_design(self, t=None, v=None, k=None, l=None, return_parameters=False): for i in combinations(block, tt): s[i] = s.get(i, 0) + 1 - if len(set(s.values())) != 1: + if (len(s) != binomial(v, tt)) or (len(set(s.values())) != 1): tt -= 1 break diff --git a/src/sage/combinat/designs/meson.build b/src/sage/combinat/designs/meson.build index fd3a8896bb3..019b62be54e 100644 --- a/src/sage/combinat/designs/meson.build +++ b/src/sage/combinat/designs/meson.build @@ -1,5 +1,6 @@ py.install_sources( 'MOLS_handbook_data.py', + '__init__.py', 'all.py', 'bibd.py', 'block_design.py', diff --git a/src/sage/combinat/designs/subhypergraph_search.pyx b/src/sage/combinat/designs/subhypergraph_search.pyx index 82be44dcd13..6ec0048610f 100644 --- a/src/sage/combinat/designs/subhypergraph_search.pyx +++ b/src/sage/combinat/designs/subhypergraph_search.pyx @@ -178,21 +178,21 @@ cdef hypergraph h_init(int n, list H) noexcept: """ cdef int x,i cdef hypergraph h - h.n = n - h.m = len(H) - h.limbs = (n+63) // 64 # =ceil(n/64) - h.names = sig_malloc(sizeof(int)*n) - h.sets = sig_malloc(h.m*sizeof(uint64_t *)) - h.set_space = sig_calloc(h.m*(h.limbs+1),sizeof(uint64_t)) + h.n = n + h.m = len(H) + h.limbs = (n+63) // 64 # =ceil(n/64) + h.names = sig_malloc(sizeof(int)*n) + h.sets = sig_malloc(h.m*sizeof(uint64_t *)) + h.set_space = sig_calloc(h.m*(h.limbs+1),sizeof(uint64_t)) # Consistency check for S in H: for x in S: - if x<0 or x>=n: + if x < 0 or x >= n: h.n = -1 - if (h.names == NULL or - h.sets == NULL or + if (h.names == NULL or + h.sets == NULL or h.set_space == NULL or h.n == -1): h.n = -1 diff --git a/src/sage/combinat/diagram_algebras.py b/src/sage/combinat/diagram_algebras.py index 6410a4a93ea..841c9efe9d3 100644 --- a/src/sage/combinat/diagram_algebras.py +++ b/src/sage/combinat/diagram_algebras.py @@ -129,14 +129,14 @@ def brauer_diagrams(k): {{-3, 3}, {-2, 2}, {-1, 1}}] """ if k in ZZ: - s = list(range(1,k+1)) + list(range(-k,0)) + s = list(range(1, k+1)) + list(range(-k,0)) for p in perfect_matchings_iterator(k): yield [(s[a],s[b]) for a,b in p] - elif k + ZZ(1) / ZZ(2) in ZZ: # Else k in 1/2 ZZ - k = ZZ(k + ZZ(1) / ZZ(2)) + elif k + ZZ.one() / 2 in ZZ: # Else k in 1/2 ZZ + k = ZZ(k + ZZ.one() / 2) s = list(range(1, k)) + list(range(-k+1,0)) for p in perfect_matchings_iterator(k-1): - yield [(s[a],s[b]) for a,b in p] + [[k, -k]] + yield [(s[a], s[b]) for a, b in p] + [[k, -k]] def temperley_lieb_diagrams(k): @@ -1203,7 +1203,7 @@ def __init__(self, order, category=None): self.order = ZZ(order) base_set = frozenset(list(range(1,order+1)) + list(range(-order,0))) else: - #order is a half-integer. + # order is a half-integer. self.order = QQ(order) base_set = frozenset(list(range(1,ZZ(ZZ(1)/ZZ(2) + order)+1)) + list(range(ZZ(-ZZ(1)/ZZ(2) - order),0))) @@ -4795,7 +4795,7 @@ def insert_pairing(cur, intervals): # Singleton intervals are vertical lines, # so we don't need to worry about them if len(I) > 1 and I[0] < cur[0]: - cur, level[j] = level[j], cur + cur, level[j] = I, cur level.append([cur[0]]) level.append([cur[1]]) break @@ -4865,7 +4865,7 @@ def key_func(P): count_left += 1 for j in range(i): prop_intervals[j].append([bot]) - for j in range(i+1,total_prop): + for j in range(i+1, total_prop): prop_intervals[j].append([top]) if not left_moving: top, bot = bot, top @@ -4964,10 +4964,10 @@ def sgn(x): for i in list(diagram): l1.append(list(i)) l2.extend(list(i)) - output = "\\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] \n\\tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] \n" #setup beginning of picture - for i in l2: #add nodes + output = "\\begin{tikzpicture}[scale = 0.5,thick, baseline={(0,-1ex/2)}] \n\\tikzstyle{vertex} = [shape = circle, minimum size = 7pt, inner sep = 1pt] \n" # setup beginning of picture + for i in l2: # add nodes output = output + "\\node[vertex] (G-{}) at ({}, {}) [shape = circle, draw{}] {{}}; \n".format(i, (abs(i)-1)*1.5, sgn(i), filled_str) - for i in l1: #add edges + for i in l1: # add edges if len(i) > 1: l4 = list(i) posList = [] @@ -4980,21 +4980,21 @@ def sgn(x): posList.sort() negList.sort() l4 = posList + negList - l5 = l4[:] #deep copy + l5 = l4[:] # deep copy for j in range(len(l5)): - l5[j-1] = l4[j] #create a permuted list + l5[j-1] = l4[j] # create a permuted list if len(l4) == 2: l4.pop() - l5.pop() #pops to prevent duplicating edges + l5.pop() # pops to prevent duplicating edges for j in zip(l4, l5): xdiff = abs(j[1])-abs(j[0]) y1 = sgn(j[0]) y2 = sgn(j[1]) - if y2-y1 == 0 and abs(xdiff) < 5: #if nodes are close to each other on same row - diffCo = (0.5+0.1*(abs(xdiff)-1)) #gets bigger as nodes are farther apart; max value of 1; min value of 0.5. + if y2-y1 == 0 and abs(xdiff) < 5: # if nodes are close to each other on same row + diffCo = (0.5+0.1*(abs(xdiff)-1)) # gets bigger as nodes are farther apart; max value of 1; min value of 0.5. outVec = (sgn(xdiff)*diffCo, -1*diffCo*y1) inVec = (-1*diffCo*sgn(xdiff), -1*diffCo*y2) - elif y2-y1 != 0 and abs(xdiff) == 1: #if nodes are close enough curviness looks bad. + elif y2-y1 != 0 and abs(xdiff) == 1: # if nodes are close enough curviness looks bad. outVec = (sgn(xdiff)*0.75, -1*y1) inVec = (-1*sgn(xdiff)*0.75, -1*y2) else: @@ -5002,7 +5002,7 @@ def sgn(x): inVec = (-1*sgn(xdiff), -1*y2) output = output + "\\draw[{}] (G-{}) .. controls +{} and +{} .. {}(G-{}); \n".format( edge_options(j), j[0], outVec, inVec, edge_additions(j), j[1]) - output = output + "\\end{tikzpicture}" #end picture + output = output + "\\end{tikzpicture}" # end picture return output diff --git a/src/sage/combinat/finite_state_machine.py b/src/sage/combinat/finite_state_machine.py index 2750ea15e9c..ee5feb4815d 100644 --- a/src/sage/combinat/finite_state_machine.py +++ b/src/sage/combinat/finite_state_machine.py @@ -14717,7 +14717,7 @@ def __init__(self, *args, **kwargs): self.TapeCache = _FSMTapeCacheDetectEpsilon_ self.visited_states = {} kwargs['check_epsilon_transitions'] = False - return super().__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def _push_branch_(self, state, tape_cache, outputs): """ @@ -14842,7 +14842,7 @@ def __init__(self, *args, **kwargs): self.TapeCache = _FSMTapeCacheDetectAll_ self.visited_states = {} kwargs['check_epsilon_transitions'] = False - return super().__init__(*args, **kwargs) + super().__init__(*args, **kwargs) # **************************************************************************** diff --git a/src/sage/combinat/fully_packed_loop.py b/src/sage/combinat/fully_packed_loop.py index 74a14fa1ecd..81e3a30508f 100644 --- a/src/sage/combinat/fully_packed_loop.py +++ b/src/sage/combinat/fully_packed_loop.py @@ -1361,8 +1361,8 @@ def _element_constructor_(self, generator): """ if isinstance(generator, AlternatingSignMatrix): SVM = generator.to_six_vertex_model() - elif isinstance(generator, SquareIceModel.Element) or \ - isinstance(generator, SixVertexConfiguration): + elif isinstance(generator, (SquareIceModel.Element, + SixVertexConfiguration)): SVM = generator else: # Not ASM nor SVM try: diff --git a/src/sage/combinat/growth.py b/src/sage/combinat/growth.py index 958b664e7cd..542d4dfb280 100644 --- a/src/sage/combinat/growth.py +++ b/src/sage/combinat/growth.py @@ -2592,11 +2592,11 @@ def forward_rule(self, y, e, t, f, x, content): z, h = x, e elif x == t != y: z, h = y, e - else: # x != t and y != t + else: # x != t and y != t qx = SkewPartition([x.to_partition(), t.to_partition()]) qy = SkewPartition([y.to_partition(), t.to_partition()]) if not all(c in qx.cells() for c in qy.cells()): - res = [(j-i) % self.k for i,j in qx.cells()] + res = [(j-i) % self.k for i, j in qx.cells()] assert len(set(res)) == 1 r = res[0] z = y.affine_symmetric_group_simple_action(r) diff --git a/src/sage/combinat/integer_lists/base.pyx b/src/sage/combinat/integer_lists/base.pyx index d2bd5da3b92..4eaa6c51f58 100644 --- a/src/sage/combinat/integer_lists/base.pyx +++ b/src/sage/combinat/integer_lists/base.pyx @@ -83,7 +83,7 @@ cdef class IntegerListsBackend(): self.max_length = Integer(max_length) if max_length != Infinity else Infinity self.min_slope = Integer(min_slope) if min_slope != -Infinity else -Infinity - self.max_slope = Integer(max_slope) if max_slope != Infinity else Infinity + self.max_slope = Integer(max_slope) if max_slope != Infinity else Infinity self.min_part = Integer(min_part) if min_part != -Infinity else -Infinity self.max_part = Integer(max_part) if max_part != Infinity else Infinity diff --git a/src/sage/combinat/integer_lists/invlex.pyx b/src/sage/combinat/integer_lists/invlex.pyx index 6bef85031ce..bfb4c8dc3d7 100644 --- a/src/sage/combinat/integer_lists/invlex.pyx +++ b/src/sage/combinat/integer_lists/invlex.pyx @@ -860,14 +860,18 @@ If you know what you are doing, you can set check=False to skip this warning.""" OUTPUT: - ``None`` if this method finds a proof that there + ``True`` if this method finds a proof that there exists an upper bound on the length. Otherwise a :exc:`ValueError` is raised. + Note that :func:`cached_method` does not work with methods + returning ``None``, so ``True`` is returned instead. + EXAMPLES:: sage: L = IntegerListsLex(4, max_length=4) sage: L._check_finiteness() + True The following example is infinite:: @@ -1002,20 +1006,20 @@ If you know what you are doing, you can set check=False to skip this warning.""" """ # Trivial cases if self.max_length < Infinity: - return + return True if self.max_sum < self.min_sum: - return + return True if self.min_slope > self.max_slope: - return + return True if self.max_slope < 0: - return + return True if self.ceiling.limit() < self.floor.limit(): - return + return True if self.ceiling.limit() == 0: # This assumes no trailing zeroes - return + return True if self.min_slope > 0 and self.ceiling.limit() < Infinity: - return + return True # Compute a lower bound on the sum of floor(i) for i=1 to infinity if self.floor.limit() > 0 or self.min_slope > 0: @@ -1028,10 +1032,10 @@ If you know what you are doing, you can set check=False to skip this warning.""" floor_sum_lower_bound = Infinity if self.max_sum < floor_sum_lower_bound: - return + return True if self.max_sum == floor_sum_lower_bound and self.max_sum < Infinity: # This assumes no trailing zeroes - return + return True # Variant on ceiling.limit() ==0 where we actually discover that the ceiling limit is 0 if ( self.max_slope == 0 and @@ -1039,13 +1043,13 @@ If you know what you are doing, you can set check=False to skip this warning.""" (self.ceiling.limit_start() < Infinity and any(self.ceiling(i) == 0 for i in range(self.ceiling.limit_start()+1))) ) ): - return + return True limit_start = max(self.ceiling.limit_start(), self.floor.limit_start()) if limit_start < Infinity: for i in range(limit_start+1): if self.ceiling(i) < self.floor(i): - return + return True raise ValueError("could not prove that the specified constraints yield a finite set") diff --git a/src/sage/combinat/k_tableau.py b/src/sage/combinat/k_tableau.py index de6b783f15b..cb6d6fbc087 100644 --- a/src/sage/combinat/k_tableau.py +++ b/src/sage/combinat/k_tableau.py @@ -1625,12 +1625,12 @@ def from_core_tableau(cls, t, k): [[None, 2], [3]] """ t = SkewTableau(list(t)) - shapes = [ Core(p, k+1).to_bounded_partition() for p in intermediate_shapes(t) ]#.to_chain() ] + shapes = [ Core(p, k+1).to_bounded_partition() for p in intermediate_shapes(t) ] # .to_chain() ] if t.inner_shape() == Partition([]): l = [] else: l = [[None]*i for i in shapes[0]] - for i in range(1,len(shapes)): + for i in range(1, len(shapes)): p = shapes[i] if len(l) < len(p): l += [[]] @@ -2068,8 +2068,10 @@ def from_core_tableau(cls, t, k): [s0*s3, s2*s1] """ t = SkewTableau(list(t)) - shapes = [ Core(p, k+1).to_grassmannian() for p in intermediate_shapes(t) ] #t.to_chain() ] - perms = [ shapes[i]*(shapes[i-1].inverse()) for i in range(len(shapes)-1,0,-1)] + shapes = [Core(p, k + 1).to_grassmannian() + for p in intermediate_shapes(t)] # t.to_chain() ] + perms = [shapes[i] * (shapes[i - 1].inverse()) + for i in range(len(shapes) - 1, 0, -1)] return cls(perms, k, inner_shape=t.inner_shape()) def k_charge(self, algorithm='I'): @@ -4222,16 +4224,16 @@ def _left_action_list( cls, Tlist, tij, v, k ): """ innershape = Core([len(r) for r in Tlist], k + 1) outershape = innershape.affine_symmetric_group_action(tij, transposition=True) - if outershape.length() == innershape.length()+1: + if outershape.length() == innershape.length() + 1: for c in SkewPartition([outershape.to_partition(),innershape.to_partition()]).cells(): while c[0] >= len(Tlist): Tlist.append([]) - Tlist[c[0]].append( v ) + Tlist[c[0]].append(v) if len(Tlist[c[0]])-c[0] == tij[1]: - Tlist[c[0]][-1] = -Tlist[c[0]][-1] #mark the cell that is on the j-1 diagonal + Tlist[c[0]][-1] = -Tlist[c[0]][-1] # mark the cell that is on the j-1 diagonal return Tlist - else: - raise ValueError("%s is not a single step up in the strong lattice" % tij) + + raise ValueError("%s is not a single step up in the strong lattice" % tij) @classmethod def follows_tableau_unsigned_standard( cls, Tlist, k ): diff --git a/src/sage/combinat/matrices/dancing_links.pyx b/src/sage/combinat/matrices/dancing_links.pyx index 475b5ef3e1b..d016f3495ea 100644 --- a/src/sage/combinat/matrices/dancing_links.pyx +++ b/src/sage/combinat/matrices/dancing_links.pyx @@ -154,7 +154,7 @@ cdef class dancing_linksWrapper: Initialization of the search algorithm. This adds the rows to the instance of dancing_links. This method is - used by `__init__` and `reinitialize` methods and should not be + used by ``__init__`` and ``reinitialize`` methods and should not be used directly. EXAMPLES:: diff --git a/src/sage/combinat/matrices/hadamard_matrix.py b/src/sage/combinat/matrices/hadamard_matrix.py index 5f9f24239d4..b8124220914 100644 --- a/src/sage/combinat/matrices/hadamard_matrix.py +++ b/src/sage/combinat/matrices/hadamard_matrix.py @@ -1503,7 +1503,7 @@ def hadamard_matrix_spence_construction(n, existence=False, check=True): - ``n`` -- integer; the order of the matrix to be constructed - ``existence`` -- boolean (default: ``False``); if ``True``, only check if the matrix exists - - ``check`` -- bolean (default: ``True``); if ``True``, check that the matrix + - ``check`` -- boolean (default: ``True``); if ``True``, check that the matrix is a Hadamard matrix before returning OUTPUT: diff --git a/src/sage/combinat/matrices/latin.py b/src/sage/combinat/matrices/latin.py index 29fbe2f960e..18c006e7aed 100644 --- a/src/sage/combinat/matrices/latin.py +++ b/src/sage/combinat/matrices/latin.py @@ -1212,7 +1212,8 @@ def disjoint_mate_dlxcpp_rows_and_map(self, allow_subtrade): dlx_rows.append([c_OFFSET, r_OFFSET, xy_OFFSET]) - max_column_nr = max(max_column_nr, max(c_OFFSET, r_OFFSET, xy_OFFSET)) + max_column_nr = max(max_column_nr, c_OFFSET, + r_OFFSET, xy_OFFSET) # We will have missed some columns. We # have to add 'dummy' rows so that the C++ DLX solver will find diff --git a/src/sage/combinat/matrices/meson.build b/src/sage/combinat/matrices/meson.build index 86021f8d376..d316252bca0 100644 --- a/src/sage/combinat/matrices/meson.build +++ b/src/sage/combinat/matrices/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'dlxcpp.py', 'hadamard_matrix.py', diff --git a/src/sage/combinat/meson.build b/src/sage/combinat/meson.build index 8c1aba5bd50..441caadca17 100644 --- a/src/sage/combinat/meson.build +++ b/src/sage/combinat/meson.build @@ -1,5 +1,6 @@ py.install_sources( 'SJT.py', + '__init__.py', 'abstract_tree.py', 'affine_permutation.py', 'algebraic_combinatorics.py', diff --git a/src/sage/combinat/multiset_partition_into_sets_ordered.py b/src/sage/combinat/multiset_partition_into_sets_ordered.py old mode 100755 new mode 100644 index 67fbcb4e70a..49131e3a5c7 --- a/src/sage/combinat/multiset_partition_into_sets_ordered.py +++ b/src/sage/combinat/multiset_partition_into_sets_ordered.py @@ -1885,7 +1885,7 @@ def __iter__(self): # iterate over blocks of letters over an alphabet if "alphabet" in self.constraints: A = self.constraints["alphabet"] - # establish a cutoff order `max_ell` + # establish a cutoff order ``max_ell`` max = self.constraints.get("max_length", infinity) max = self.constraints.get("length", max) max = max * len(A) diff --git a/src/sage/combinat/necklace.py b/src/sage/combinat/necklace.py index 3ac4bccf5e2..f3e8ccfd32d 100644 --- a/src/sage/combinat/necklace.py +++ b/src/sage/combinat/necklace.py @@ -360,12 +360,11 @@ def _fast_fixed_content(a, content, t, p, k, r, s, dll, equality=False): content[j] += 1 j = dll.next(j) a[t - 1] = k - 1 - return -################################ -# List Fixed Content Algorithm # -################################ +# ############################### +# List Fixed Content Algorithm # +# ############################### def _lfc(content, equality=False): """ EXAMPLES:: diff --git a/src/sage/combinat/non_decreasing_parking_function.py b/src/sage/combinat/non_decreasing_parking_function.py index dc6bf59e3e2..b8f9c9b825f 100644 --- a/src/sage/combinat/non_decreasing_parking_function.py +++ b/src/sage/combinat/non_decreasing_parking_function.py @@ -629,6 +629,5 @@ def iterator_rec(n): return for res in iterator_rec(self.n): yield NonDecreasingParkingFunction(res) - return Element = NonDecreasingParkingFunction diff --git a/src/sage/combinat/parallelogram_polyomino.py b/src/sage/combinat/parallelogram_polyomino.py index ac2e7ea6e4d..bbc599aed0c 100644 --- a/src/sage/combinat/parallelogram_polyomino.py +++ b/src/sage/combinat/parallelogram_polyomino.py @@ -311,8 +311,7 @@ def __call__(self, *get_values, **options): {'diagram': 'diagram representation', 'list': 'list representation'}} """ - for key in options: - value = options[key] + for key, value in options.items(): self.__setitem__(key, value) for key in get_values: return self.__getitem__(key) diff --git a/src/sage/combinat/partition.py b/src/sage/combinat/partition.py index 6b6a7edfa4c..927f1da8ec5 100644 --- a/src/sage/combinat/partition.py +++ b/src/sage/combinat/partition.py @@ -169,7 +169,7 @@ that the difference between two consecutive parts is between `-3` and `-1`:: - sage: Partitions(11,min_slope=-3,max_slope=-1,min_length=2,max_length=4).list() + sage: Partitions(11, min_slope=-3, max_slope=-1, min_length=2, max_length=4).list() [[7, 4], [6, 5], [6, 4, 1], [6, 3, 2], [5, 4, 2], [5, 3, 2, 1]] Partition objects can also be created individually with :class:`Partition`:: @@ -1716,24 +1716,22 @@ def next_within_bounds(self, min=[], max=None, partition_type=None): def condition(a, b): if partition_type in ('strict', 'strictly decreasing'): return a < b - 1 - elif partition_type in (None, 'weak', 'weakly decreasing'): + if partition_type in (None, 'weak', 'weakly decreasing'): return a < b - else: - raise ValueError('unrecognized partition type') + raise ValueError('unrecognized partition type') + for r in range(len(p) - 1, -1, -1): - if r == 0: - if (max is None or p[r] < max[r]): - next_p[r] += 1 - break - else: - return None - else: - if (max is None or p[r] < max[r]) and condition(p[r], p[r-1]): + if not r: + if max is None or p[r] < max[r]: next_p[r] += 1 break - else: - next_p[r] = min[r] - continue + return None + elif (max is None or p[r] < max[r]) and condition(p[r], p[r-1]): + next_p[r] += 1 + break + next_p[r] = min[r] + continue + return _Partitions(next_p) def row_standard_tableaux(self): @@ -5319,7 +5317,10 @@ def character_polynomial(self): # Replace each p_i by i*x_i-1 items = ps_mu.monomial_coefficients().items() # items contains a list of (partition, coeff) pairs - partition_to_monomial = lambda part: prod([i*x[i-1] - 1 for i in part]) + + def partition_to_monomial(part): + return prod([i*x[i-1] - 1 for i in part]) + res = [[partition_to_monomial(mc[0]), mc[1]] for mc in items] # Write things in the monomial basis @@ -5420,40 +5421,40 @@ def dimension(self, smaller=None, k=1): smaller = Partition([]) if k == 1: if smaller == Partition([]): # In this case, use the hook dimension formula - return factorial(larger.size())/prod(larger.hooks()) - else: - if not larger.contains(smaller): # easy case - return 0 - else: - # relative dimension - # Uses a formula of Olshanski, Regev, Vershik (see reference) - def inv_factorial(i): - if i < 0: - return 0 - return 1/factorial(i) - - len_range = range(larger.length()) - from sage.matrix.constructor import matrix - M = matrix(QQ, [[inv_factorial(larger.get_part(i)-smaller.get_part(j)-i+j) for i in len_range] for j in len_range]) - return factorial(larger.size()-smaller.size())*M.determinant() - else: - larger_core = larger.core(k) - smaller_core = smaller.core(k) - if smaller_core != larger_core: # easy case + return factorial(larger.size()) / prod(larger.hooks()) + if not larger.contains(smaller): # easy case return 0 - larger_quotients = larger.quotient(k) - smaller_quotients = smaller.quotient(k) - def multinomial_with_partitions(sizes, path_counts): - # count the number of ways of performing the k paths in parallel, - # if we know the total length allotted for each of the paths (sizes), and the number - # of paths for each component. A multinomial picks the ordering of the components where - # each step is taken. - return prod(path_counts) * multinomial(sizes) + # relative dimension + # Uses a formula of Olshanski, Regev, Vershik (see reference) + def inv_factorial(i): + if i < 0: + return 0 + return 1 / factorial(i) + + len_range = range(larger.length()) + from sage.matrix.constructor import matrix + M = matrix(QQ, [[inv_factorial(larger.get_part(i) - smaller.get_part(j) - i + j) + for i in len_range] for j in len_range]) + return factorial(larger.size() - smaller.size()) * M.determinant() + + larger_core = larger.core(k) + smaller_core = smaller.core(k) + if smaller_core != larger_core: # easy case + return 0 + larger_quotients = larger.quotient(k) + smaller_quotients = smaller.quotient(k) + + def multinomial_with_partitions(sizes, path_counts): + # count the number of ways of performing the k paths in parallel, + # if we know the total length allotted for each of the paths (sizes), and the number + # of paths for each component. A multinomial picks the ordering of the components where + # each step is taken. + return prod(path_counts) * multinomial(sizes) - sizes = [larger_quotients[i].size()-smaller_quotients[i].size() for i in range(k)] - path_counts = [larger_quotients[i].dimension(smaller_quotients[i]) for i in range(k)] - return multinomial_with_partitions(sizes, path_counts) + sizes = [larger_quotients[i].size() - smaller_quotients[i].size() for i in range(k)] + path_counts = [larger_quotients[i].dimension(smaller_quotients[i]) for i in range(k)] + return multinomial_with_partitions(sizes, path_counts) def plancherel_measure(self): r""" @@ -5484,7 +5485,7 @@ def plancherel_measure(self): sage: all(sum(mu.plancherel_measure() for mu in Partitions(n))==1 for n in range(10)) True """ - return self.dimension()**2/factorial(self.size()) + return self.dimension()**2 / factorial(self.size()) def outline(self, variable=None): r""" @@ -5500,7 +5501,7 @@ def outline(self, variable=None): EXAMPLES:: sage: # needs sage.symbolic - sage: [Partition([5,4]).outline()(x=i) for i in range(-10,11)] + sage: [Partition([5,4]).outline()(x=i) for i in range(-10, 11)] [10, 9, 8, 7, 6, 5, 6, 5, 6, 5, 4, 3, 2, 3, 4, 5, 6, 7, 8, 9, 10] sage: Partition([]).outline() abs(x) @@ -5513,7 +5514,7 @@ def outline(self, variable=None): TESTS:: - sage: integrate(Partition([1]).outline()-abs(x),(x,-10,10)) # needs sage.symbolic + sage: integrate(Partition([1]).outline() - abs(x), (x, -10, 10)) # needs sage.symbolic 2 """ if variable is None: @@ -5533,7 +5534,7 @@ def dual_equivalence_graph(self, directed=False, coloring=None): following two conditions are satisfied: - In the one-line notation of the permutation `p`, the letter - `i` does not appear inbetween `i-1` and `i+1`. + `i` does not appear between `i-1` and `i+1`. - The permutation `q` is obtained from `p` by switching two of the three letters `i-1, i, i+1` (in its one-line @@ -5938,7 +5939,7 @@ class Partitions(UniqueRepresentation, Parent): and ``length``:: sage: Partitions(5, min_part=2) - Partitions of the integer 5 satisfying constraints min_part=2 + Partitions of 5 whose parts are at least 2 sage: Partitions(5, min_part=2).list() [[5], [3, 2]] @@ -6028,8 +6029,8 @@ class Partitions(UniqueRepresentation, Parent): sage: TestSuite(Partitions(5)).run() # needs sage.libs.flint sage: TestSuite(Partitions(5, min_part=2)).run() # needs sage.libs.flint - sage: repr( Partitions(5, min_part=2) ) - 'Partitions of the integer 5 satisfying constraints min_part=2' + sage: repr(Partitions(5, min_part=2)) + 'Partitions of 5 whose parts are at least 2' sage: P = Partitions(5, min_part=2) sage: P.first().parent() @@ -6055,7 +6056,7 @@ class Partitions(UniqueRepresentation, Parent): sage: Partitions(length=2, max_slope=-1).list() Traceback (most recent call last): ... - ValueError: the size must be specified with any keyword argument + NotImplementedError: cannot list an infinite set sage: Partitions(max_part=3) 3-Bounded Partitions @@ -6067,22 +6068,29 @@ class Partitions(UniqueRepresentation, Parent): Check :issue:`15467`:: - sage: Partitions(5,parts_in=[1,2,3,4], length=4) + 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 - sage: Partitions(5,starting=[3,2], length=2) + ValueError: the parameters 'parts_in', 'starting', 'ending', 'regular' and 'restricted' 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 - sage: Partitions(5,ending=[3,2], length=2) + ValueError: the parameters 'parts_in', 'starting', 'ending', 'regular' and 'restricted' 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 - sage: Partitions(NN, length=2) + ValueError: the parameters 'parts_in', 'starting', 'ending', 'regular' and 'restricted' cannot be combined with anything else + sage: Partitions(5, restricted=2, length=2) Traceback (most recent call last): ... - ValueError: the size must be specified with any keyword argument + ValueError: the parameters 'parts_in', 'starting', 'ending', 'regular' and 'restricted' cannot be combined with anything else + sage: Partitions(5, regular=5, length=2) + Traceback (most recent call last): + ... + ValueError: the parameters 'parts_in', 'starting', 'ending', 'regular' and 'restricted' cannot be combined with anything else + sage: Partitions(NN, length=2) + Partitions satisfying constraints length=2 + sage: Partitions(('la','la','laaaa'), max_part=8) Traceback (most recent call last): ... @@ -6110,6 +6118,24 @@ class Partitions(UniqueRepresentation, Parent): Partitions of the integer 5 satisfying constraints inner=[2, 1], outer=[3, 2] sage: P.list() [[3, 2]] + + Check that contradictory length requirements are handled correctly:: + + sage: list(Partitions(5, max_length=1, length=3)) + Traceback (most recent call last): + ... + ValueError: do not specify the length together with the minimal or maximal length + + sage: list(Partitions(5, min_length=2, max_length=1)) + [] + + Check that :issue:`38897` is fixed:: + + sage: Partitions(40, min_length=10).cardinality() + 24000 + + sage: Partitions(40, max_length=10).cardinality() + 16928 """ @staticmethod def __classcall_private__(cls, n=None, **kwargs): @@ -6136,35 +6162,82 @@ def __classcall_private__(cls, n=None, **kwargs): sage: list(P) [[5], [1, 1, 1, 1, 1]] """ - if n == infinity: + if n is infinity: raise ValueError("n cannot be infinite") if isinstance(n, (int, Integer)): - if len(kwargs) == 0: + if not kwargs: return Partitions_n(n) + if n < 0: + return Partitions_n(-1) if len(kwargs) == 1: if 'max_part' in kwargs: - return PartitionsGreatestLE(n, kwargs['max_part']) + if not n: + return Partitions_n(0) + max_part = min(kwargs['max_part'], n) + if max_part < 1: + return Partitions_n(-1) + return Partitions_length_and_parts_constrained(n, 1, n, 1, max_part) + if 'min_part' in kwargs: + if not n: + return Partitions_n(0) + min_part = max(kwargs['min_part'], 1) + if min_part > n: + return Partitions_n(-1) + return Partitions_length_and_parts_constrained(n, 1, n, min_part, n) if 'length' in kwargs: return Partitions_nk(n, kwargs['length']) + if 'parts_in' in kwargs: + return Partitions_parts_in(n, kwargs['parts_in']) + if 'starting' in kwargs: + return Partitions_starting(n, kwargs['starting']) + if 'ending' in kwargs: + return Partitions_ending(n, kwargs['ending']) + if 'regular' in kwargs: + return RegularPartitions_n(n, kwargs['regular']) + if 'restricted' in kwargs: + return RestrictedPartitions_n(n, kwargs['restricted']) - if (len(kwargs) > 1 and - ('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") - - if 'parts_in' in kwargs: - return Partitions_parts_in(n, kwargs['parts_in']) - elif 'starting' in kwargs: - return Partitions_starting(n, kwargs['starting']) - elif 'ending' in kwargs: - return Partitions_ending(n, kwargs['ending']) - elif 'regular' in kwargs: - return RegularPartitions_n(n, kwargs['regular']) - elif 'restricted' in kwargs: - return RestrictedPartitions_n(n, kwargs['restricted']) + else: + if ('parts_in' in kwargs or + 'starting' in kwargs or + 'ending' in kwargs or + 'regular' in kwargs or + 'restricted' in kwargs): + raise ValueError("the parameters 'parts_in', 'starting', " + + "'ending', 'regular' and 'restricted' " + + "cannot be combined with anything else") + + if 'length' in kwargs and ('min_length' in kwargs or 'max_length' in kwargs): + raise ValueError("do not specify the length together with the minimal or maximal length") + + if set(kwargs).issubset(['length', 'min_part', 'max_part', + 'min_length', 'max_length']): + if 'length' in kwargs: + min_length = max_length = kwargs['length'] + if not n: + if min_length: + return Partitions_n(-1) + return Partitions_n(0) + if not (1 <= min_length <= n): + return Partitions_n(-1) + else: + max_length = min(kwargs.get('max_length', n), n) + if not n: + min_length = max(kwargs.get('min_length', 0), 0) + if min_length <= 0 <= max_length: + return Partitions_n(0) + return Partitions_n(-1) + min_length = max(kwargs.get('min_length', 1), 1) + if min_length > max_length: + return Partitions_n(-1) + + min_part = max(kwargs.get('min_part', 1), 1) + max_part = min(kwargs.get('max_part', n), n) + if min_part > max_part: + return Partitions_n(-1) + + return Partitions_length_and_parts_constrained(n, min_length, max_length, min_part, max_part) # FIXME: should inherit from IntegerListLex, and implement repr, or _name as a lazy attribute kwargs['name'] = "Partitions of the integer {} satisfying constraints {}".format(n, ", ".join(["{}={}".format(key, kwargs[key]) for key in sorted(kwargs)])) @@ -6192,25 +6265,30 @@ def __classcall_private__(cls, n=None, **kwargs): kwargs.get('min_length', 0)) del kwargs['inner'] return Partitions_with_constraints(n, **kwargs) - elif n is None or n is NN or n is NonNegativeIntegers(): - if len(kwargs) > 0: - if len(kwargs) == 1: + + if n is None or n is NN or n is NonNegativeIntegers(): + if not kwargs: + return Partitions_all() + + if len(kwargs) == 1: + if 'max_part' in kwargs: + return Partitions_all_bounded(kwargs['max_part']) + if 'regular' in kwargs: + return RegularPartitions_all(kwargs['regular']) + if 'restricted' in kwargs: + return RestrictedPartitions_all(kwargs['restricted']) + elif len(kwargs) == 2: + if 'regular' in kwargs: + if kwargs['regular'] < 1 or kwargs['regular'] not in ZZ: + raise ValueError("the regularity must be a positive integer") if 'max_part' in kwargs: - return Partitions_all_bounded(kwargs['max_part']) - if 'regular' in kwargs: - return RegularPartitions_all(kwargs['regular']) - if 'restricted' in kwargs: - return RestrictedPartitions_all(kwargs['restricted']) - elif len(kwargs) == 2: - if 'regular' in kwargs: - if kwargs['regular'] < 1 or kwargs['regular'] not in ZZ: - raise ValueError("the regularity must be a positive integer") - if 'max_part' in kwargs: - return RegularPartitions_bounded(kwargs['regular'], kwargs['max_part']) - if 'max_length' in kwargs: - return RegularPartitions_truncated(kwargs['regular'], kwargs['max_length']) - raise ValueError("the size must be specified with any keyword argument") - return Partitions_all() + return RegularPartitions_bounded(kwargs['regular'], kwargs['max_part']) + if 'max_length' in kwargs: + return RegularPartitions_truncated(kwargs['regular'], kwargs['max_length']) + elif 'max_part' in kwargs and 'max_length' in kwargs: + return PartitionsInBox(kwargs['max_length'], kwargs['max_part']) + + return Partitions_all_constrained(**kwargs) raise ValueError("n must be an integer or be equal to one of " "None, NN, NonNegativeIntegers()") @@ -6381,9 +6459,9 @@ def _element_constructor_(self, lst): if lst.parent() is self: return lst try: - lst = list(map(ZZ, lst)) + lst = [ZZ(e) for e in lst] except TypeError: - raise ValueError('all parts of %s should be nonnegative integers' % repr(lst)) + raise ValueError(f'all parts of {repr(lst)} should be nonnegative integers') if lst in self: # trailing zeros are removed in Partition.__init__ @@ -6728,12 +6806,83 @@ def from_core_and_quotient(self, core, quotient): return self.element_class(self, [new_w[i]+i for i in range(len(new_w))]) +class Partitions_all_constrained(Partitions): + def __init__(self, **kwargs): + """ + TESTS:: + + sage: TestSuite(sage.combinat.partition.Partitions_all_constrained(max_length=3)).run() # long time + """ + self._constraints = kwargs + Partitions.__init__(self, is_infinite=True) + + def __contains__(self, x): + """ + TESTS:: + + sage: from sage.combinat.partition import Partitions_all_constrained + sage: P = Partitions_all_constrained(max_part=3, max_length=2) + sage: 1 in P + False + sage: Partition([2,1]) in P + True + sage: [2,1] in P + True + sage: [3,2,1] in P + False + sage: [1,2] in P + False + sage: [5,1] in P + False + sage: [0] in P + True + sage: [] in P + True + sage: [3,1,0] in P + True + """ + try: + return x in Partitions(sum(x), **self._constraints) + except TypeError: + return False + + def _repr_(self): + """ + EXAMPLES:: + + sage: Partitions(max_part=3, max_length=4, min_length=2) + Partitions satisfying constraints max_length=4, max_part=3, min_length=2 + """ + return "Partitions satisfying constraints " + ", ".join(["{}={}".format(key, value) + for key, value in sorted(self._constraints.items())]) + + def __iter__(self): + """ + An iterator for partitions with various constraints. + + EXAMPLES:: + + sage: P = Partitions(max_length=2) + sage: it = iter(P) + sage: [next(it) for i in range(10)] + [[], [1], [2], [1, 1], [3], [2, 1], [4], [3, 1], [2, 2], [5]] + """ + n = 0 + while True: + for p in Partitions(n, **self._constraints): + yield self.element_class(self, p) + n += 1 + + class Partitions_all_bounded(Partitions): + """ + Partitions whose parts do not exceed a given bound. + """ def __init__(self, k): """ TESTS:: - sage: TestSuite( sage.combinat.partition.Partitions_all_bounded(3) ).run() # long time + sage: TestSuite(sage.combinat.partition.Partitions_all_bounded(3)).run() # long time """ self.k = k Partitions.__init__(self, is_infinite=True) @@ -6743,6 +6892,10 @@ def __contains__(self, x): TESTS:: sage: P = Partitions(max_part=3) + sage: 1 in P + False + sage: 0 in P + False sage: Partition([2,1]) in P True sage: [2,1] in P @@ -6758,7 +6911,7 @@ def __contains__(self, x): sage: [] in P True """ - return not x or (x[0] <= self.k and x in _Partitions) + return x in _Partitions and (not x or x[0] <= self.k) def _repr_(self): """ @@ -6815,14 +6968,16 @@ def __contains__(self, x): TESTS:: - sage: p = Partitions(5) - sage: [2,1] in p + sage: P = Partitions(5) + sage: 5 in P + False + sage: [2,1] in P False - sage: [2,2,1] in p + sage: [2,2,1] in P True - sage: [3,2] in p + sage: [3,2] in P True - sage: [2,3] in p + sage: [2,3] in P False """ return x in _Partitions and sum(x) == self.n @@ -7217,23 +7372,35 @@ def __contains__(self, x): TESTS:: - sage: p = Partitions(5, length=2) - sage: [2,1] in p + sage: P = Partitions(5, length=2) + sage: [2,1] in P False - sage: [2,2,1] in p + sage: [2,2,1] in P False - sage: [3,2] in p + sage: [3,2] in P True - sage: [2,3] in p + sage: [2,3] in P False - sage: [4,1] in p + sage: [4,1] in P True - sage: [1,1,1,1,1] in p + sage: [1,1,1,1,1] in P + False + sage: [5] in P False - sage: [5] in p + sage: [4,1,0] in P + True + sage: [] in Partitions(0, length=0) + True + sage: [0] in Partitions(0, length=0) + True + sage: [] in Partitions(0, length=1) False """ - return x in _Partitions and sum(x) == self.n and len(x) == self.k + if x not in _Partitions or sum(x) != self.n: + return False + if not x or not x[0]: + return not self.k + return len(x) == next(i for i, e in enumerate(reversed(x), self.k) if e) def _repr_(self): """ @@ -7400,7 +7567,7 @@ def subset(self, **kwargs): sage: P = Partitions(5, length=2); P Partitions of the integer 5 of length 2 sage: P.subset(max_part=3) - Partitions of the integer 5 satisfying constraints length=2, max_part=3 + Partitions of 5 having length 2 and whose parts are at most 3 """ return Partitions(self.n, length=self.k, **kwargs) @@ -7449,14 +7616,24 @@ def __contains__(self, x): """ TESTS:: - sage: p = Partitions(5, parts_in=[1,2]) - sage: [2,1,1,1] in p + sage: from sage.combinat.partition import Partitions_parts_in + sage: P = Partitions_parts_in(5, [1,2]) + sage: 5 in P + False + sage: [2,1,1,1] in P True - sage: [4,1] in p + sage: [4,1] in P False + sage: [2,1,1,1,0] in P + True """ - return (x in _Partitions and sum(x) == self.n and - all(p in self.parts for p in x)) + if x not in _Partitions or sum(x) != self.n: + return False + if x and not x[-1]: + x = x[:-1] + while x and not x[-1]: + x.pop() + return all(p in self.parts for p in x) def _repr_(self): """ @@ -7804,8 +7981,20 @@ def __contains__(self, x): True sage: [3] in p False + + TESTS:: + + sage: from sage.combinat.partition import Partitions_starting + sage: [2,1,0] in Partitions_starting(3, [2, 1]) + True """ - return x in Partitions_n(self.n) and x <= self._starting + if x not in _Partitions or sum(x) != self.n: + return False + if x and not x[-1]: + x = x[:-1] + while x and not x[-1]: + x.pop() + return x <= self._starting def first(self): """ @@ -7916,8 +8105,20 @@ def __contains__(self, x): False sage: [2,1] in p False + + TESTS:: + + sage: from sage.combinat.partition import Partitions_ending + sage: [4,0] in Partitions_ending(4, [2, 2]) + True """ - return x in Partitions_n(self.n) and x >= self._ending + if x not in _Partitions or sum(x) != self.n: + return False + if x and not x[-1]: + x = x[:-1] + while x and not x[-1]: + x.pop() + return x >= self._ending def first(self): """ @@ -7967,12 +8168,14 @@ class PartitionsInBox(Partitions): EXAMPLES:: - sage: PartitionsInBox(2,2) + sage: PartitionsInBox(2, 2) Integer partitions which fit in a 2 x 2 box - sage: PartitionsInBox(2,2).list() + sage: PartitionsInBox(2, 2).list() [[], [1], [1, 1], [2], [2, 1], [2, 2]] - """ + sage: Partitions(max_part=2, max_length=3) + Integer partitions which fit in a 3 x 2 box + """ def __init__(self, h, w): """ Initialize ``self``. @@ -8015,9 +8218,15 @@ def __contains__(self, x): False sage: [3,1] in PartitionsInBox(2, 3) True + sage: [0] in PartitionsInBox(2,2) + True + sage: [3,1,0] in PartitionsInBox(2, 3) + True """ - return x in _Partitions and len(x) <= self.h \ - and (len(x) == 0 or x[0] <= self.w) + return (x in _Partitions + and (not x or not x[0] + or (x[0] <= self.w + and len(x) <= next(i for i, e in enumerate(reversed(x), self.h) if e)))) def list(self): """ @@ -8044,7 +8253,10 @@ def list(self): return [self.element_class(self, [])] else: l = [[i] for i in range(w + 1)] - add = lambda x: [x + [i] for i in range(x[-1] + 1)] + + def add(x): + return [x + [i] for i in range(x[-1] + 1)] + for i in range(h-1): new_list = [] for element in l: @@ -8187,7 +8399,8 @@ def __contains__(self, x): """ TESTS:: - sage: P = Partitions(regular=3) + sage: from sage.combinat.partition import RegularPartitions + sage: P = RegularPartitions(3) sage: [5] in P True sage: [] in P @@ -8205,7 +8418,7 @@ def __contains__(self, x): sage: Partition([10,1]) in P True """ - if not Partitions.__contains__(self, x): + if x not in _Partitions: return False if isinstance(x, Partition): return max(x.to_exp() + [0]) < self._ell @@ -8349,15 +8562,22 @@ def __contains__(self, x): """ TESTS:: - sage: P = Partitions(regular=4, max_length=3) + sage: from sage.combinat.partition import RegularPartitions_truncated + sage: P = RegularPartitions_truncated(4, 3) + sage: 3 in P + False sage: [3, 3, 3] in P True sage: [] in P True sage: [4, 2, 1, 1] in P False + sage: [0, 0, 0, 0] in P + True """ - return len(x) <= self._max_len and RegularPartitions.__contains__(self, x) + return (RegularPartitions.__contains__(self, x) + and (not x or not x[0] or + len(x) <= next(i for i, e in enumerate(reversed(x), self._max_len) if e))) def _repr_(self): """ @@ -8466,15 +8686,21 @@ def __contains__(self, x): """ TESTS:: - sage: P = Partitions(regular=4, max_part=3) + sage: from sage.combinat.partition import RegularPartitions_bounded + sage: P = RegularPartitions_bounded(4, 3) + sage: 0 in P + False sage: [3, 3, 3] in P True sage: [] in P True sage: [4, 2, 1] in P False + sage: [0, 0, 0, 0, 0] in P + True """ - return len(x) == 0 or (x[0] <= self.k and RegularPartitions.__contains__(self, x)) + return (RegularPartitions.__contains__(self, x) + and (not x or x[0] <= self.k)) def _repr_(self): """ @@ -8553,11 +8779,14 @@ def __contains__(self, x): """ TESTS:: - sage: P = Partitions(5, regular=3) + sage: from sage.combinat.partition import RegularPartitions_n + sage: P = RegularPartitions_n(5, 3) sage: [3, 1, 1] in P True sage: [3, 2, 1] in P False + sage: [5, 0, 0, 0, 0] in P + True """ return RegularPartitions.__contains__(self, x) and sum(x) == self.n @@ -8670,7 +8899,6 @@ class OrderedPartitions(Partitions): sage: OrderedPartitions(4).list() # needs sage.libs.gap [[4], [3, 1], [2, 2], [2, 1, 1], [1, 3], [1, 2, 1], [1, 1, 2], [1, 1, 1, 1]] """ - @staticmethod def __classcall_private__(cls, n, k=None): """ @@ -8784,14 +9012,223 @@ def cardinality(self): return ZZ(ans) +########################################### +# Partitions_length_and_parts_constrained # +########################################### + +class Partitions_length_and_parts_constrained(Partitions): + r""" + The class of all integer partitions having parts and length in a + given range. + + This class is strictly more general than + :class:`PartitionsGreatestLE`, except that we insist that the + size of the partition is positive and that neither the + constraints on the parts nor on the length are contradictory. + + INPUT: + + - ``n`` -- the size of the partition, positive + - ``min_length`` -- the lower bound on the number of parts, between 1 and ``n`` + - ``max_length`` -- the upper bound on the number of parts, between ``min_length`` and ``n`` + - ``min_part`` -- the bound on the smallest part, between 1 and ``n`` + - ``max_part`` -- the bound on the largest part, between ``min_part`` and ``n`` + + EXAMPLES:: + + sage: from sage.combinat.partition import Partitions_length_and_parts_constrained + sage: Partitions_length_and_parts_constrained(10, 1, 10, 2, 5) + Partitions of 10 whose parts are between 2 and 5 + sage: list(Partitions_length_and_parts_constrained(9, 3, 4, 2, 4)) + [[4, 3, 2], [3, 3, 3], [3, 2, 2, 2]] + + sage: [4,3,2,1] in Partitions_length_and_parts_constrained(10, 1, 10, 2, 10) + False + sage: [2,2,2,2,2] in Partitions_length_and_parts_constrained(10, 1, 10, 2, 10) + True + + .. WARNING:: + + If ``min_length`` and ``min_part`` equal 1 and ``max_length`` + and ``max_part`` equal ``n``, this class contains the same + partitions as :class:`~sage.combinat.partition.Partitions`, + but is different from that class. + + :: + + sage: Partitions_length_and_parts_constrained(9, 1, 9, 1, 9) + Partitions of 9 + sage: Partitions_length_and_parts_constrained(9, 1, 9, 1, 9) == Partitions(9) + False + """ + def __init__(self, n, min_length, max_length, min_part, max_part): + """ + Initialize ``self``. + + TESTS:: + + sage: from sage.combinat.partition import Partitions_length_and_parts_constrained + sage: p = Partitions_length_and_parts_constrained(10, 2, 5, 3, 4) + sage: TestSuite(p).run() + """ + if not (1 <= min_part <= max_part <= n): + raise ValueError(f"min_part (={min_part}) and max_part (={max_part}) should satisfy 1 <= min_part <= max_part <= n (={n})") + if not (1 <= min_length <= max_length <= n): + raise ValueError(f"min_length (={min_length}) and max_length (={max_length}) should satisfy 1 <= min_length <= max_length <= n (={n})") + Partitions.__init__(self) + self._n = n + self._min_part = min_part + self._max_part = max_part + self._min_length = min_length + self._max_length = max_length + + def _repr_(self): + """ + Return a string representation of ``self``. + + TESTS:: + + sage: from sage.combinat.partition import Partitions_length_and_parts_constrained + sage: Partitions_length_and_parts_constrained(9, 1, 9, 1, 9) + Partitions of 9 + sage: Partitions_length_and_parts_constrained(9, 1, 3, 1, 9) + Partitions of 9 having length at most 3 + sage: Partitions_length_and_parts_constrained(9, 3, 9, 1, 9) + Partitions of 9 having length at least 3 + sage: Partitions_length_and_parts_constrained(9, 1, 9, 2, 9) + Partitions of 9 whose parts are at least 2 + sage: Partitions_length_and_parts_constrained(9, 1, 9, 1, 3) + Partitions of 9 whose parts are at most 3 + sage: Partitions_length_and_parts_constrained(9, 3, 5, 2, 9) + Partitions of 9 having length between 3 and 5 and whose parts are at least 2 + """ + if self._min_length == 1 and self._max_length == self._n: + length_str = "" + elif self._min_length == self._max_length: + length_str = f"having length {self._min_length}" + elif self._min_length == 1: + length_str = f"having length at most {self._max_length}" + elif self._max_length == self._n: + length_str = f"having length at least {self._min_length}" + else: + length_str = f"having length between {self._min_length} and {self._max_length}" + + if self._min_part == 1 and self._max_part == self._n: + parts_str = "" + elif self._min_part == self._max_part: + parts_str = f"having parts equal to {self._min_part}" + elif self._min_part == 1: + parts_str = f"whose parts are at most {self._max_part}" + elif self._max_part == self._n: + parts_str = f"whose parts are at least {self._min_part}" + else: + parts_str = f"whose parts are between {self._min_part} and {self._max_part}" + + if length_str: + if parts_str: + return f"Partitions of {self._n} " + length_str + " and " + parts_str + return f"Partitions of {self._n} " + length_str + if parts_str: + return f"Partitions of {self._n} " + parts_str + return f"Partitions of {self._n}" + + def __contains__(self, x): + """ + Check if ``x`` is contained in ``self``. + + TESTS:: + + sage: from sage.combinat.partition import Partitions_length_and_parts_constrained + sage: P = Partitions_length_and_parts_constrained(10, 2, 4, 2, 5) + sage: 1 in P + False + sage: Partition([]) in P + False + sage: Partition([3]) in P + False + sage: Partition([5, 3, 2]) in P + True + sage: [5, 3, 2, 0, 0] in P + True + """ + if x not in _Partitions or sum(x) != self._n: + return False + if x and not x[-1]: + x = x[:-1] + while x and not x[-1]: + x.pop() + return (not x + or (x[-1] >= self._min_part + and x[0] <= self._max_part + and self._min_length <= len(x) <= self._max_length)) + + def __iter__(self): + """ + Iterator over the set of partitions in ``self``. + + EXAMPLES:: + + sage: list(Partitions(9, min_part=2, max_part=4, min_length=3, max_length=4)) + [[4, 3, 2], [3, 3, 3], [3, 2, 2, 2]] + """ + yield from IntegerListsLex(self._n, max_slope=0, + min_part=self._min_part, + max_part=self._max_part, + min_length=self._min_length, + max_length=self._max_length, + element_constructor=lambda x: self.element_class(self, x)) + + def cardinality(self): + """ + Return the cardinality of ``self``. + + EXAMPLES:: + + sage: from sage.combinat.partition import Partitions_length_and_parts_constrained + sage: list(Partitions_length_and_parts_constrained(9, 1, 2, 3, 9)) + [[9], [6, 3], [5, 4]] + sage: Partitions_length_and_parts_constrained(9, 1, 2, 3, 9).cardinality() + 3 + + TESTS:: + + sage: from itertools import product + sage: P = Partitions + sage: all(P(n, min_length=k, max_length=m, min_part=a, max_part=b).cardinality() + ....: == len(list(P(n, min_length=k, max_length=m, min_part=a, max_part=b))) + ....: for n, k, m, a, b in product(range(-1, 5), repeat=5)) + True + """ + n = self._n + a = self._min_part + b = self._max_part + k = self._min_length + m = self._max_length + if a == 1: + # unrestricted min_part + if k == 1: + if m == n: + # unrestricted length, parts smaller max_part + return number_of_partitions_length(n + b, b) + + return number_of_partitions_max_length_max_part(n, m, b) + + return (number_of_partitions_max_length_max_part(n, m, b) + - number_of_partitions_max_length_max_part(n, k - 1, b)) + + d = b - a + return ZZ.sum(number_of_partitions_max_length_max_part(n1, min(ell, n1), min(d, n1)) + for ell in range(k, min(m, n // a) + 1) if (n1 := n - a * ell) is not None) + + ########################## # Partitions Greatest LE # ########################## class PartitionsGreatestLE(UniqueRepresentation, IntegerListsLex): - """ - The class of all (unordered) "restricted" partitions of the integer `n` - having parts less than or equal to the integer `k`. + r""" + The class of all (unordered) "restricted" partitions of the + integer `n` having parts less than or equal to the integer `k`. EXAMPLES:: @@ -8812,7 +9249,6 @@ class PartitionsGreatestLE(UniqueRepresentation, IntegerListsLex): sage: PartitionsGreatestLE(10, 2).first().parent() Partitions... """ - def __init__(self, n, k): """ Initialize ``self``. @@ -8850,12 +9286,12 @@ def cardinality(self): TESTS:: - sage: all(PartitionsGreatestLE(n, a).cardinality() == # needs sage.libs.gap - ....: len(PartitionsGreatestLE(n, a).list()) + sage: all(PartitionsGreatestLE(n, a).cardinality() == + ....: len(list(PartitionsGreatestLE(n, a))) ....: for n in range(20) for a in range(6)) True """ - return sum(number_of_partitions_length(self.n, i) for i in range(self.k+1)) + return sum(number_of_partitions_length(self.n, i) for i in range(self.k + 1)) Element = Partition options = Partitions.options @@ -9003,7 +9439,8 @@ def __contains__(self, x): """ TESTS:: - sage: P = Partitions(restricted=3) + sage: from sage.combinat.partition import RestrictedPartitions_generic + sage: P = RestrictedPartitions_generic(3) sage: [5] in P False sage: [2] in P @@ -9033,9 +9470,9 @@ def __contains__(self, x): sage: Partition([3,3] + [1]*10) in P True """ - if not Partitions.__contains__(self, x): + if x not in _Partitions: return False - if x == []: + if not x: return True return (all(x[i] - x[i+1] < self._ell for i in range(len(x)-1)) and x[-1] < self._ell) @@ -9056,9 +9493,9 @@ def _fast_iterator(self, n, max_part): sage: for n in range(10): ....: for ell in range(2, n): - ....: Pres = Partitions(n, restricted=ell) - ....: Preg = Partitions(n, regular=ell) - ....: assert set(Pres) == set(p.conjugate() for p in Preg) + ....: P_res = Partitions(n, restricted=ell) + ....: P_reg = Partitions(n, regular=ell) + ....: assert set(P_res) == set(p.conjugate() for p in P_reg) """ if n == 0: yield [] @@ -9166,11 +9603,16 @@ def __contains__(self, x): """ TESTS:: - sage: P = Partitions(5, regular=3) + sage: from sage.combinat.partition import RestrictedPartitions_n + sage: P = RestrictedPartitions_n(5, 3) sage: [3, 1, 1] in P True sage: [3, 2, 1] in P False + sage: [3, 2, 0, 0, 0] in P + True + sage: [5] in P + False """ return RestrictedPartitions_generic.__contains__(self, x) and sum(x) == self.n @@ -9406,6 +9848,65 @@ def number_of_partitions_length(n, k, algorithm='hybrid'): return ZZ(libgap.NrPartitions(ZZ(n), ZZ(k))) +@cached_function +def number_of_partitions_max_length_max_part(n, k, b): + r""" + Return the number of partitions of `n` with at most `k` + parts, all of which are at most `b`. + + EXAMPLES: + + This could also be computed using the `q`-binomial coefficient:: + + sage: from sage.combinat.partition import number_of_partitions_max_length_max_part as f + sage: all(f(n, k, b) == q_binomial(k + b, b)[n] for n in range(5) for k in range(n+1) for b in range(n+1)) + True + + However, although the `q`-binomial coefficient is faster for + individual invocations, it seems that the caching we use here is + essential for some computations:: + + sage: def A(n): + ....: s1 = number_of_partitions(n) + ....: s2 = sum(Partitions(m, max_part=l, length=k).cardinality() + ....: * Partitions(n-m-l^2, min_length=k+2*l).cardinality() + ....: for l in range(1, (n+1).isqrt()) + ....: for m in range((n-l^2-2*l)*l//(l+1)+1) + ....: for k in range(ceil(m/l), min(m, n-m-l^2-2*l)+1)) + ....: return s1 + s2 + + sage: A(100) + 10934714090 + """ + assert n >= 0 and k >= 0 and b >= 0, f"{n, k, b} must be non-negative" + if not n: + return ZZ.one() + # for best performance of the cache, it is better to pass bounds + # at most n - internally we make sure that this is the case + b = min(n, b) + k = min(n, k) + if n == k == b: + return number_of_partitions(n) + bk = b * k + if n > bk: + return ZZ.zero() + if n == bk: + return ZZ.one() + if k < b: + b, k = k, b + # shortcut if k = n + if n == k: + return number_of_partitions_length(n + b, b) + + # recurse on the size of the maximal part + # for optimal caching it would be nice to keep the second argument larger + # than the third + # since k >= b > 0 we have so min(k - 1, n1) >= min(m, n1) + # except maybe for m == k == b + return sum(number_of_partitions_max_length_max_part(n1, min(k - 1, n1), min(m, n1)) + for m in range(1, b + 1) if (n1 := n - m) is not None) + + ########## # issue 14225: Partitions() is frequently used, but only weakly cached. # Hence, establish a strong reference to it. diff --git a/src/sage/combinat/partition_kleshchev.py b/src/sage/combinat/partition_kleshchev.py index cfa78933e37..444a46f2cf1 100644 --- a/src/sage/combinat/partition_kleshchev.py +++ b/src/sage/combinat/partition_kleshchev.py @@ -162,9 +162,9 @@ def conormal_cells(self, i=None): carry[res] += 1 else: res = KP._multicharge[0] + self[row] - row - 1 - if row == len(self)-1 or self[row] > self[row+1]: # removable cell + if row == len(self)-1 or self[row] > self[row+1]: # removable cell carry[res] -= 1 - if row == 0 or self[row-1] > self[row]: #addable cell + if row == 0 or self[row-1] > self[row]: # addable cell if carry[res+1] >= 0: conormals[res+1].append((row, self[row])) else: @@ -661,25 +661,25 @@ def normal_cells(self, i=None): part_lens = [len(part) for part in self] # so we don't repeatedly call these KP = self.parent() if KP._convention[0] == 'L': - rows = [(k,r) for k,ell in enumerate(part_lens) for r in range(ell+1)] + rows = [(k, r) for k, ell in enumerate(part_lens) for r in range(ell+1)] else: - rows = [(k,r) for k,ell in reversed(list(enumerate(part_lens))) for r in range(ell+1)] + rows = [(k, r) for k, ell in reversed(list(enumerate(part_lens))) for r in range(ell+1)] if KP._convention[1] == 'S': rows.reverse() for row in rows: - k,r = row - if r == part_lens[k]: # addable cell at bottom of a component + k, r = row + if r == part_lens[k]: # addable cell at bottom of a component carry[KP._multicharge[k]-r] += 1 else: part = self[k] res = KP._multicharge[k] + (part[r] - r - 1) - if r == part_lens[k]-1 or part[r] > part[r+1]: # removable cell + if r == part_lens[k]-1 or part[r] > part[r+1]: # removable cell if carry[res] == 0: normals[res].insert(0, (k, r, part[r]-1)) else: carry[res] -= 1 - if r == 0 or part[r-1] > part[r]: #addable cell + if r == 0 or part[r-1] > part[r]: # addable cell carry[res+1] += 1 # finally return the result diff --git a/src/sage/combinat/permutation_cython.pxd b/src/sage/combinat/permutation_cython.pxd index 094dafc8ddc..3e5afddf40e 100644 --- a/src/sage/combinat/permutation_cython.pxd +++ b/src/sage/combinat/permutation_cython.pxd @@ -8,4 +8,3 @@ cpdef list left_action_same_n(list l, list r) cpdef list right_action_same_n(list l, list r) cpdef list left_action_product(list l, list r) cpdef list right_action_product(list l, list r) - diff --git a/src/sage/combinat/permutation_cython.pyx b/src/sage/combinat/permutation_cython.pyx index 978510c4ae9..db58f15f51e 100644 --- a/src/sage/combinat/permutation_cython.pyx +++ b/src/sage/combinat/permutation_cython.pyx @@ -74,7 +74,7 @@ cdef int next_swap(int n, int *c, int *o) noexcept: Note, Knuth's descriptions of algorithms tend to encourage one to think of finite state machines. For convenience, we have added comments to show what state the machine is - in at any given point in the algorithm. `plain_swap_reset` + in at any given point in the algorithm. ``plain_swap_reset`` sets the state to 1, and this function begins and ends in state 2. diff --git a/src/sage/combinat/posets/hasse_diagram.py b/src/sage/combinat/posets/hasse_diagram.py index 56b51e96371..5e10563794d 100644 --- a/src/sage/combinat/posets/hasse_diagram.py +++ b/src/sage/combinat/posets/hasse_diagram.py @@ -2101,14 +2101,16 @@ def orthocomplementations_iterator(self): for e in orbit: orbit_number[e] = ind - comps = [None] * n mt = self.meet_matrix() jn = self.join_matrix() - for e in range(n): - # Fix following after issue #20727 - comps[e] = [x for x in range(n) if - mt[e, x] == 0 and jn[e, x] == n - 1 and - x in orbits[orbit_number[dual_isomorphism[e]]]] + + items = ((e, dual_isomorphism[e]) for e in range(n)) + + # Fix following after issue #20727 + comps = [[x for x in range(n) + if mt[e, x] == 0 and jn[e, x] == n - 1 and + x in orbits[orbit_number[dual_e]]] + for e, dual_e in items] # Fitting is done by this recursive function: def recursive_fit(orthocomplements, unbinded): diff --git a/src/sage/combinat/posets/incidence_algebras.py b/src/sage/combinat/posets/incidence_algebras.py index 3fc3f2a0b76..566c8b3934e 100644 --- a/src/sage/combinat/posets/incidence_algebras.py +++ b/src/sage/combinat/posets/incidence_algebras.py @@ -11,6 +11,8 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from copy import copy +from typing import Any from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute @@ -19,8 +21,6 @@ from sage.combinat.free_module import CombinatorialFreeModule from sage.matrix.matrix_space import MatrixSpace -from copy import copy - class IncidenceAlgebra(CombinatorialFreeModule): r""" @@ -449,22 +449,22 @@ def __init__(self, I, prefix='R') -> None: sage: TestSuite(R).run() # long time """ self._ambient = I - EC = {} + EC: dict[Any, list] = {} P = self._ambient._poset if not P.is_finite(): raise NotImplementedError("only implemented for finite posets") for i in self._ambient.basis().keys(): S = P.subposet(P.interval(*i)) added = False - for k in EC: + for k, ECk in EC.items(): if S._hasse_diagram.is_isomorphic(k._hasse_diagram): - EC[k].append(i) + ECk.append(i) added = True break if not added: EC[S] = [i] - self._equiv_classes = map(sorted, EC.values()) - self._equiv_classes = {cls[0]: cls for cls in self._equiv_classes} + equiv_classes = map(sorted, EC.values()) + self._equiv_classes = {cls[0]: cls for cls in equiv_classes} cat = Algebras(I.base_ring()).FiniteDimensional().WithBasis() CombinatorialFreeModule.__init__(self, I.base_ring(), sorted(self._equiv_classes.keys()), diff --git a/src/sage/combinat/posets/linear_extensions.py b/src/sage/combinat/posets/linear_extensions.py index cf62e234321..f8c93185940 100644 --- a/src/sage/combinat/posets/linear_extensions.py +++ b/src/sage/combinat/posets/linear_extensions.py @@ -627,12 +627,12 @@ def cardinality(self): for x in range(n): # Use the existing Jup table to compute all covering # relations in J(P) for things that are above loc(x). - K = [[loc[x]]] + K0 = [[loc[x]]] j = 0 - while K[j]: - K.append([b for a in K[j] for b in Jup[a]]) + while K0[j]: + K0.append([b for a in K0[j] for b in Jup[a]]) j += 1 - K = sorted({item for sublist in K for item in sublist}) + K = sorted({item for sublist in K0 for item in sublist}) for j in range(len(K)): i = m + j + 1 Jup[i] = [m + K.index(a) + 1 for a in Jup[K[j]]] diff --git a/src/sage/combinat/posets/meson.build b/src/sage/combinat/posets/meson.build index 07837832519..9832967b4ff 100644 --- a/src/sage/combinat/posets/meson.build +++ b/src/sage/combinat/posets/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'cartesian_product.py', 'd_complete.py', diff --git a/src/sage/combinat/posets/posets.py b/src/sage/combinat/posets/posets.py index e565eb3d2ee..6d319084295 100644 --- a/src/sage/combinat/posets/posets.py +++ b/src/sage/combinat/posets/posets.py @@ -699,15 +699,12 @@ def Poset(data=None, element_labels=None, cover_relations=False, linear_extensio if element_labels is not None: P = P.relabel(element_labels) return P - else: - if element_labels is None: - return FinitePoset(data, elements=data._elements, category=category, facade=facade) - else: - return FinitePoset(data, elements=element_labels, category=category, facade=facade) + if element_labels is None: + return FinitePoset(data, elements=data._elements, category=category, facade=facade) + return FinitePoset(data, elements=element_labels, category=category, facade=facade) # Convert data to a DiGraph elements = None - D = {} if data is None: # type 0 D = DiGraph() elif isinstance(data, DiGraph): # type 4 @@ -794,7 +791,7 @@ class FinitePoset(UniqueRepresentation, Parent): corresponding to vertex ``i``. If ``elements`` is ``None``, then it is set to be the vertex set of the digraph. Note that if this option is set, then ``elements`` is considered as a specified linear extension of the poset - and the `linear_extension` attribute is set. + and the ``linear_extension`` attribute is set. - ``category`` -- :class:`FinitePosets`, or a subcategory thereof @@ -1529,10 +1526,11 @@ def sorted(self, l, allow_incomparable=True, remove_duplicates=False): sage: P.sorted([], allow_incomparable=False, remove_duplicates=False) [] """ - v = [self._element_to_vertex(x) for x in l] + v = (self._element_to_vertex(x) for x in l) if remove_duplicates: - v = set(v) - o = sorted(v) + o = sorted(set(v)) + else: + o = sorted(v) if not allow_incomparable: H = self._hasse_diagram @@ -2058,10 +2056,10 @@ def plot(self, label_elements=True, element_labels=None, 'cover_colors': 'edge_colors', 'cover_style': 'edge_style', 'border': 'graph_border'} - for param in rename: + for param, value in rename.items(): tmp = kwds.pop(param, None) if tmp is not None: - kwds[rename[param]] = tmp + kwds[value] = tmp heights = kwds.pop('heights', None) if heights is None: @@ -2716,10 +2714,9 @@ def linear_intervals_count(self) -> list[int]: for y in H.neighbor_out_iterator(xmax): if exposant == 1: next_stock.append((xmin, y, y)) - else: - if (cov_xmin, y) in short_stock: - if H.is_linear_interval(xmin, y): - next_stock.append((xmin, cov_xmin, y)) + elif (cov_xmin, y) in short_stock: + if H.is_linear_interval(xmin, y): + next_stock.append((xmin, cov_xmin, y)) if next_stock: poly.append(len(next_stock)) stock = next_stock @@ -2856,12 +2853,12 @@ def is_incomparable_chain_free(self, m, n=None) -> bool: closure = self._hasse_diagram.transitive_closure() for m, n in chain_pairs: try: - m, n = Integer(m), Integer(n) + ZZm, ZZn = Integer(m), Integer(n) except TypeError: raise TypeError(f"{m} and {n} must be integers") if m < 1 or n < 1: raise ValueError(f"{m} and {n} must be positive integers") - twochains = digraphs.TransitiveTournament(m) + digraphs.TransitiveTournament(n) + twochains = digraphs.TransitiveTournament(ZZm) + digraphs.TransitiveTournament(ZZn) if closure.subgraph_search(twochains, induced=True) is not None: return False return True @@ -5324,9 +5321,9 @@ def edge_color(va, vb): neigh1 = [z for z in prod_dg.neighbor_iterator(x) if edge_color(x, z) == i1] for x0, x1 in product(neigh0, neigh1): - x2 = list(x0) - x2[i1] = x1[i1] - x2 = tuple(x2) + _x2 = list(x0) + _x2[i1] = x1[i1] + x2 = tuple(_x2) A0 = prod_dg.has_edge(x, x0) B0 = prod_dg.has_edge(x1, x2) if A0 != B0: @@ -6530,7 +6527,7 @@ def random_maximal_chain(self): EXAMPLES:: - sage: set_random_seed(0) # results are reproduceable + sage: set_random_seed(0) # results are reproducible sage: P = posets.BooleanLattice(4) sage: P.random_maximal_chain() [0, 4, 5, 7, 15] @@ -6565,7 +6562,7 @@ def random_maximal_antichain(self): EXAMPLES:: - sage: set_random_seed(0) # results are reproduceable + sage: set_random_seed(0) # results are reproducible sage: P = posets.BooleanLattice(4) sage: P.random_maximal_antichain() [1, 8, 2, 4] @@ -6597,7 +6594,7 @@ def random_linear_extension(self): EXAMPLES:: - sage: set_random_seed(0) # results are reproduceable + sage: set_random_seed(0) # results are reproducible sage: P = posets.BooleanLattice(4) sage: P.random_linear_extension() [0, 4, 1, 2, 3, 8, 10, 5, 12, 9, 13, 11, 6, 14, 7, 15] diff --git a/src/sage/combinat/regular_sequence.py b/src/sage/combinat/regular_sequence.py index b57e5ccbf5b..6ad1c12c088 100644 --- a/src/sage/combinat/regular_sequence.py +++ b/src/sage/combinat/regular_sequence.py @@ -335,7 +335,7 @@ def __iter__(self): def is_degenerated(self): r""" Return whether this `k`-regular sequence is degenerated, - i.e., whether this `k`-regular sequence does not satisfiy + i.e., whether this `k`-regular sequence does not satisfy `\mu[0] \mathit{right} = \mathit{right}`. EXAMPLES:: @@ -368,7 +368,7 @@ def is_degenerated(self): def _error_if_degenerated_(self): r""" Raise an error if this `k`-regular sequence is degenerated, - i.e., if this `k`-regular sequence does not satisfiy + i.e., if this `k`-regular sequence does not satisfy `\mu[0] \mathit{right} = \mathit{right}`. TESTS:: diff --git a/src/sage/combinat/rigged_configurations/kleber_tree.py b/src/sage/combinat/rigged_configurations/kleber_tree.py index 551c975ce76..e0c16db6553 100644 --- a/src/sage/combinat/rigged_configurations/kleber_tree.py +++ b/src/sage/combinat/rigged_configurations/kleber_tree.py @@ -666,8 +666,8 @@ def latex_options(self, **options): if not options: from copy import copy return copy(self._latex_options) - for k in options: - self._latex_options[k] = options[k] + for key, value in options.items(): + self._latex_options[key] = value def _latex_(self): r""" diff --git a/src/sage/combinat/rigged_configurations/meson.build b/src/sage/combinat/rigged_configurations/meson.build index 6b12159dfda..40d0f4e42c5 100644 --- a/src/sage/combinat/rigged_configurations/meson.build +++ b/src/sage/combinat/rigged_configurations/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'bij_abstract_class.py', 'bij_infinity.py', diff --git a/src/sage/combinat/rigged_configurations/rigged_partition.pxd b/src/sage/combinat/rigged_configurations/rigged_partition.pxd index e99258f33b2..031ab548020 100644 --- a/src/sage/combinat/rigged_configurations/rigged_partition.pxd +++ b/src/sage/combinat/rigged_configurations/rigged_partition.pxd @@ -12,4 +12,3 @@ cdef class RiggedPartition(SageObject): cdef class RiggedPartitionTypeB(RiggedPartition): pass - diff --git a/src/sage/combinat/root_system/cartan_type.py b/src/sage/combinat/root_system/cartan_type.py index ce5762719e2..19c500a412f 100644 --- a/src/sage/combinat/root_system/cartan_type.py +++ b/src/sage/combinat/root_system/cartan_type.py @@ -841,7 +841,9 @@ def _samples(self): [CartanType(t) for t in [["I", 5], ["H", 3], ["H", 4]]] + \ [t.affine() for t in finite_crystallographic if t.is_irreducible()] + \ [CartanType(t) for t in [["BC", 1, 2], ["BC", 5, 2]]] + \ - [CartanType(t).dual() for t in [["B", 5, 1], ["C", 4, 1], ["F", 4, 1], ["G", 2, 1],["BC", 1, 2], ["BC", 5, 2]]] #+ \ + [CartanType(t).dual() for t in [["B", 5, 1], ["C", 4, 1], + ["F", 4, 1], ["G", 2, 1], + ["BC", 1, 2], ["BC", 5, 2]]] # + \ # [ g ] _colors = {1: 'blue', -1: 'blue', diff --git a/src/sage/combinat/root_system/meson.build b/src/sage/combinat/root_system/meson.build index 35e7bfb1950..629c67bcdd6 100644 --- a/src/sage/combinat/root_system/meson.build +++ b/src/sage/combinat/root_system/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'ambient_space.py', 'associahedron.py', diff --git a/src/sage/combinat/root_system/type_reducible.py b/src/sage/combinat/root_system/type_reducible.py index 53dadb9864d..dfede775aa3 100644 --- a/src/sage/combinat/root_system/type_reducible.py +++ b/src/sage/combinat/root_system/type_reducible.py @@ -90,7 +90,7 @@ def __init__(self, types): ((1, 0), 5), ((1, 1), 6), ((1, 2), 7), ((1, 3), 8), ((1, 4), 9), ((1, 5), 10), ((2, 1), 11), ((2, 2), 12), ((2, 3), 13)] - Similarly, the attribute `_shifts` specifies by how much the + Similarly, the attribute ``_shifts`` specifies by how much the indices of the bases of the ambient spaces of the components are shifted in the ambient space of this Cartan type:: diff --git a/src/sage/combinat/root_system/weyl_characters.py b/src/sage/combinat/root_system/weyl_characters.py index c8c44224741..2fb2f90bb2e 100644 --- a/src/sage/combinat/root_system/weyl_characters.py +++ b/src/sage/combinat/root_system/weyl_characters.py @@ -761,14 +761,9 @@ def _demazure_helper(self, dd, word='long', debug=False): next[mu] = next.get(mu, 0) - accum[v] if debug: print(" mu=%s, next[mu]=%s" % (mu, next[mu])) - accum = {} - for v in next: - accum[v] = next[v] - ret = {} - for v in accum: - if accum[v]: - ret[self._space.from_vector_notation(v, style='coroots')] = accum[v] - return ret + accum = dict(next) + return {self._space.from_vector_notation(v, style='coroots'): val + for v, val in accum.items() if val} @cached_method def _weight_multiplicities(self, x): diff --git a/src/sage/combinat/set_partition.py b/src/sage/combinat/set_partition.py index 092e2f9dbb7..5078003c6f2 100644 --- a/src/sage/combinat/set_partition.py +++ b/src/sage/combinat/set_partition.py @@ -73,7 +73,11 @@ def _repr_(self): sage: S([[1,3],[2,4]]) {{1, 3}, {2, 4}} """ - return '{' + ', '.join('{' + repr(sorted(x))[1:-1] + '}' for x in self) + '}' + try: + s = [sorted(x) for x in self] + except TypeError: + s = [sorted(x, key=str) for x in self] + return '{' + ', '.join('{' + repr(x)[1:-1] + '}' for x in s) + '}' def __hash__(self): """ @@ -532,7 +536,7 @@ def pre_conjugate(sp): class SetPartition(AbstractSetPartition, - metaclass=InheritComparisonClasscallMetaclass): + metaclass=InheritComparisonClasscallMetaclass): r""" A partition of a set. @@ -620,7 +624,11 @@ def __init__(self, parent, s, check=True): {} """ self._latex_options = {} - ClonableArray.__init__(self, parent, sorted(map(frozenset, s), key=min), check=check) + try: + s = sorted(map(frozenset, s), key=min) + except TypeError: + s = sorted(map(frozenset, s), key=lambda b: min(str(b))) + ClonableArray.__init__(self, parent, s, check=check) def check(self): """ @@ -2821,7 +2829,11 @@ def __iter__(self): sage: SetPartitions(["a", "b"]).list() [{{'a', 'b'}}, {{'a'}, {'b'}}] """ - for sp in set_partition_iterator(sorted(self._set)): + try: + s = sorted(self._set) + except TypeError: + s = sorted(self._set, key=str) + for sp in set_partition_iterator(s): yield self.element_class(self, sp, check=False) def base_set(self): @@ -3179,7 +3191,11 @@ def __iter__(self): sage: SetPartitions(["a", "b", "c"], 2).list() [{{'a', 'c'}, {'b'}}, {{'a'}, {'b', 'c'}}, {{'a', 'b'}, {'c'}}] """ - for sp in set_partition_iterator_blocks(sorted(self._set), self._k): + try: + s = sorted(self._set) + except TypeError: + s = sorted(self._set, key=str) + for sp in set_partition_iterator_blocks(s, self._k): yield self.element_class(self, sp, check=False) def __contains__(self, x): diff --git a/src/sage/combinat/sf/classical.py b/src/sage/combinat/sf/classical.py index badea76a0c5..d499ef94143 100644 --- a/src/sage/combinat/sf/classical.py +++ b/src/sage/combinat/sf/classical.py @@ -30,7 +30,11 @@ from . import jack from . import orthotriang -translate = {'monomial':'MONOMIAL', 'homogeneous':'HOMSYM', 'powersum':'POWSYM', 'elementary':'ELMSYM', 'Schur':'SCHUR'} +translate = {'monomial': 'MONOMIAL', + 'homogeneous': 'HOMSYM', + 'powersum': 'POWSYM', + 'elementary': 'ELMSYM', + 'Schur': 'SCHUR'} conversion_functions = {} @@ -55,11 +59,11 @@ def init(): s[1, 1, 1, 1] - s[2, 1, 1] + 2*s[2, 2] - s[3, 1] + s[4] """ import sage.libs.symmetrica.all as symmetrica - for other_basis in translate: - for basis in translate: + for other_basis, other_name in translate.items(): + for basis, name in translate.items(): try: conversion_functions[(other_basis, basis)] = getattr(symmetrica, - 't_{}_{}'.format(translate[other_basis], translate[basis])) + f't_{other_name}_{name}') except AttributeError: pass diff --git a/src/sage/combinat/sf/kfpoly.py b/src/sage/combinat/sf/kfpoly.py index d58fb746780..01470a24b5a 100644 --- a/src/sage/combinat/sf/kfpoly.py +++ b/src/sage/combinat/sf/kfpoly.py @@ -197,10 +197,7 @@ def schur_to_hl(mu, t=None): for rg in riggings(mu): res[rg[0]] = res.get(rg[0], 0) + weight(rg, t) - d = {} - for key in res: - d[ key.conjugate() ] = res[key] - return d + return {key.conjugate(): value for key, value in res.items()} def riggings(part): diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 8d911087b24..60fc4b65c53 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -2284,28 +2284,28 @@ def _invert_morphism(self, n, base_ring, sage: c2 == d2 True """ - #Decide whether we know how to go from self to other or - #from other to self + # Decide whether we know how to go from self to other or + # from other to self if to_other_function is not None: - known_cache = self_to_other_cache #the known direction - unknown_cache = other_to_self_cache #the unknown direction + known_cache = self_to_other_cache # the known direction + unknown_cache = other_to_self_cache # the unknown direction known_function = to_other_function else: - unknown_cache = self_to_other_cache #the known direction - known_cache = other_to_self_cache #the unknown direction + unknown_cache = self_to_other_cache # the known direction + known_cache = other_to_self_cache # the unknown direction known_function = to_self_function - #Do nothing if we've already computed the inverse - #for degree n. + # Do nothing if we've already computed the inverse + # for degree n. if n in known_cache and n in unknown_cache: return - #Univariate polynomial arithmetic is faster - #over ZZ. Since that is all we need to compute - #the transition matrices between S and P, we - #should use that. - #Zt = ZZ['t'] - #t = Zt.gen() + # Univariate polynomial arithmetic is faster + # over ZZ. Since that is all we need to compute + # the transition matrices between S and P, we + # should use that. + # Zt = ZZ['t'] + # t = Zt.gen() one = base_ring.one() zero = base_ring.zero() @@ -6747,7 +6747,7 @@ def _nonnegative_coefficients(x): sage: _nonnegative_coefficients(x^2-4) False """ - if isinstance(x, Polynomial) or isinstance(x, MPolynomial): + if isinstance(x, (Polynomial, MPolynomial)): return all(c >= 0 for c in x.coefficients(sparse=False)) else: return x >= 0 diff --git a/src/sage/combinat/sine_gordon.py b/src/sage/combinat/sine_gordon.py index 1891f172d38..f3b8ac496a9 100644 --- a/src/sage/combinat/sine_gordon.py +++ b/src/sage/combinat/sine_gordon.py @@ -598,11 +598,11 @@ def vertex_to_angle(v): **triangulation_opts) P += point((0, 0), zorder=len(P), **points_opts) # Vertices - v_points = {x: (radius * cos(vertex_to_angle(x)), - radius * sin(vertex_to_angle(x))) - for x in self.vertices()} - for v in v_points: - P += point(v_points[v], zorder=len(P), **points_opts) + v_points = [(radius * cos(vertex_to_angle(x)), + radius * sin(vertex_to_angle(x))) + for x in self.vertices()] + for coords in v_points: + P += point(coords, zorder=len(P), **points_opts) # Reflection axes P += line([(0, 1.1 * radius), (0, -1.1 * radius)], zorder=len(P), **reflections_opts) diff --git a/src/sage/combinat/six_vertex_model.py b/src/sage/combinat/six_vertex_model.py index 879418f18d9..ca70c9661c6 100644 --- a/src/sage/combinat/six_vertex_model.py +++ b/src/sage/combinat/six_vertex_model.py @@ -777,7 +777,7 @@ def to_alternating_sign_matrix(self): [ 0 1 -1 1] [ 0 0 1 0] """ - from sage.combinat.alternating_sign_matrix import AlternatingSignMatrix #AlternatingSignMatrices - #ASM = AlternatingSignMatrices(self.parent()._nrows) - #return ASM(self.to_signed_matrix()) + from sage.combinat.alternating_sign_matrix import AlternatingSignMatrix # AlternatingSignMatrices + # ASM = AlternatingSignMatrices(self.parent()._nrows) + # return ASM(self.to_signed_matrix()) return AlternatingSignMatrix(self.to_signed_matrix()) diff --git a/src/sage/combinat/specht_module.py b/src/sage/combinat/specht_module.py index e48e34419fe..1f7f15c90d6 100644 --- a/src/sage/combinat/specht_module.py +++ b/src/sage/combinat/specht_module.py @@ -1036,7 +1036,7 @@ def _repr_(self): class SimpleModule(SymmetricGroupRepresentation, QuotientModuleWithBasis): r""" - The simgle `S_n`-module associated with a partition `\lambda`. + The simple `S_n`-module associated with a partition `\lambda`. The simple module `D^{\lambda}` is the quotient of the Specht module `S^{\lambda}` by its :class:`maximal submodule ` diff --git a/src/sage/combinat/t_sequences.py b/src/sage/combinat/t_sequences.py index c78a451f67c..2af7e4b9d1a 100644 --- a/src/sage/combinat/t_sequences.py +++ b/src/sage/combinat/t_sequences.py @@ -84,7 +84,7 @@ def is_skew(seq, verbose=False): - ``seq`` -- the sequence that should be checked - ``verbose`` -- boolean (default: ``False``); if ``True`` the function - will be verbose when the sequences do not satisfy the contraints + will be verbose when the sequences do not satisfy the constraints EXAMPLES:: @@ -130,7 +130,7 @@ def is_symmetric(seq, verbose=False) -> bool: - ``seq`` -- the sequence that should be checked - ``verbose`` -- boolean (default: ``False``); if ``True`` the function will be - verbose when the sequences do not satisfy the contraints + verbose when the sequences do not satisfy the constraints EXAMPLES:: @@ -180,7 +180,7 @@ def is_T_sequences_set(sequences, verbose=False): - ``sequences`` -- list of four sequences - ``verbose`` -- boolean (default: ``False``); if ``True`` the function will be - verbose when the sequences do not satisfy the contraints + verbose when the sequences do not satisfy the constraints EXAMPLES:: @@ -643,7 +643,7 @@ def is_base_sequences_tuple(base_sequences, verbose=False): - ``base_sequences`` -- the list of 4 sequences that should be checked - ``verbose`` -- boolean (default: ``False``); if ``True`` the function - will be verbose when the sequences do not satisfy the contraints + will be verbose when the sequences do not satisfy the constraints EXAMPLES:: @@ -656,7 +656,7 @@ def is_base_sequences_tuple(base_sequences, verbose=False): sage: seqs = [[1, -1], [1, 1], [-1], [2]] sage: is_base_sequences_tuple(seqs, verbose=True) - Base sequences should only contiain -1, +1, found 2 + Base sequences should only contain -1, +1, found 2 False TESTS: @@ -694,7 +694,7 @@ def is_base_sequences_tuple(base_sequences, verbose=False): for el in seq: if abs(el) != 1: if verbose: - print(f'Base sequences should only contiain -1, +1, found {el}') + print(f'Base sequences should only contain -1, +1, found {el}') return False for j in range(1, n+p): diff --git a/src/sage/combinat/tableau.py b/src/sage/combinat/tableau.py index aace1ba5a2c..eef2536beba 100644 --- a/src/sage/combinat/tableau.py +++ b/src/sage/combinat/tableau.py @@ -5841,7 +5841,7 @@ class SemistandardTableaux(Tableaux): OUTPUT: - The appropriate class, after checking basic consistency tests. (For - example, specifying ``eval`` implies a value for `max_entry`). + example, specifying ``eval`` implies a value for ``max_entry``). A semistandard tableau is a tableau whose entries are positive integers, which are weakly increasing in rows and strictly increasing down columns. @@ -6973,15 +6973,12 @@ def __contains__(self, x): for row in x: for i in row: content[i] = content.get(i, 0) + 1 - content_list = [0]*int(max(content)) + content_list = [0] * int(max(content)) - for key in content: - content_list[key-1] = content[key] + for key, c in content.items(): + content_list[key - 1] = c - if content_list != self.weight: - return False - - return True + return content_list == self.weight def cardinality(self): """ @@ -8133,8 +8130,6 @@ def __iter__(self): yield self.element_class(self, tableau) - return - def list(self): r""" Return a list of the standard Young tableaux of the specified shape. diff --git a/src/sage/combinat/tableau_tuple.py b/src/sage/combinat/tableau_tuple.py index fd847c4ad1e..6c75106154b 100644 --- a/src/sage/combinat/tableau_tuple.py +++ b/src/sage/combinat/tableau_tuple.py @@ -4926,7 +4926,6 @@ def max_row_in_component(tab, r): yield tableau_from_list(tab) # all done! - return def last(self): r""" diff --git a/src/sage/combinat/triangles_FHM.py b/src/sage/combinat/triangles_FHM.py index c8248bdc5f2..9bd07daa5fe 100644 --- a/src/sage/combinat/triangles_FHM.py +++ b/src/sage/combinat/triangles_FHM.py @@ -427,7 +427,8 @@ def h(self): """ x, y = self._vars n = self._n - step = self._poly(x=y / (y - 1), y=(y - 1) * x / (1 + (y - 1) * x)) + step = self._poly.subs({x: y / (y - 1), + y: (y - 1) * x / (1 + (y - 1) * x)}) step *= (1 + (y - 1) * x)**n polyh = step.numerator() return H_triangle(polyh, variables=(x, y)) @@ -503,7 +504,8 @@ def m(self): """ x, y = self._vars n = self._n - step = self._poly(x=(x - 1) * y / (1 - y), y=x / (x - 1)) * (1 - y)**n + step = self._poly.subs({x: (x - 1) * y / (1 - y), + y: x / (x - 1)}) * (1 - y)**n polym = step.numerator() return M_triangle(polym, variables=(x, y)) @@ -536,8 +538,8 @@ def f(self): """ x, y = self._vars n = self._n - step1 = self._poly(x=x / (1 + x), y=y) * (x + 1)**n - step2 = step1(x=x, y=y / x) + step1 = self._poly.subs({x: x / (1 + x), y: y}) * (x + 1)**n + step2 = step1.subs({x: x, y: y / x}) polyf = step2.numerator() return F_triangle(polyf, variables=(x, y)) @@ -585,8 +587,9 @@ def vector(self): sage: H_triangle(ht).vector() x^2 + 3*x + 1 """ - anneau = PolynomialRing(ZZ, 'x') - return anneau(self._poly(y=1)) + x, y = self._vars + anneau = PolynomialRing(ZZ, "x") + return anneau(self._poly.subs({y: 1})) class F_triangle(Triangle): @@ -617,7 +620,8 @@ def h(self): """ x, y = self._vars n = self._n - step = (1 - x)**n * self._poly(x=x / (1 - x), y=x * y / (1 - x)) + step = (1 - x)**n * self._poly.subs({x: x / (1 - x), + y: x * y / (1 - x)}) polyh = step.numerator() return H_triangle(polyh, variables=(x, y)) @@ -662,11 +666,39 @@ def m(self): """ x, y = self._vars n = self._n - step = self._poly(x=y * (x - 1) / (1 - x * y), y=x * y / (1 - x * y)) + step = self._poly.subs({x: y * (x - 1) / (1 - x * y), + y: x * y / (1 - x * y)}) step *= (1 - x * y)**n polym = step.numerator() return M_triangle(polym, variables=(x, y)) + def parabolic(self): + """ + Return a parabolic version of the F-triangle. + + This is obtained by replacing the variable `y` by `y-1`. + + EXAMPLES:: + + sage: from sage.combinat.triangles_FHM import H_triangle + sage: x, y = polygens(ZZ,'x,y') + sage: H_triangle(1+x*y).f() + F: x + y + 1 + sage: _.parabolic() + F: x + y + + TESTS:: + + sage: a, b = polygens(ZZ,'a,b') + sage: H_triangle(1+a*b).f() + F: a + b + 1 + sage: _.parabolic() + F: a + b + """ + x, y = self._vars + polyf = self._poly.subs({y: y - 1}) + return F_triangle(polyf, variables=(x, y)) + def vector(self): """ Return the f-vector as a polynomial in one variable. @@ -681,9 +713,10 @@ def vector(self): sage: F_triangle(ft).vector() 5*x^2 + 5*x + 1 """ - anneau = PolynomialRing(ZZ, 'x') - x = anneau.gen() - return anneau(self._poly(y=x)) + x, y = self._vars + anneau = PolynomialRing(ZZ, "x") + nx = anneau.gen() + return anneau(self._poly.subs({x: nx, y: nx})) class Gamma_triangle(Triangle): diff --git a/src/sage/combinat/words/meson.build b/src/sage/combinat/words/meson.build index bb12f65d28f..2333d8dc0cd 100644 --- a/src/sage/combinat/words/meson.build +++ b/src/sage/combinat/words/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'abstract_word.py', 'all.py', 'alphabet.py', diff --git a/src/sage/combinat/words/suffix_trees.py b/src/sage/combinat/words/suffix_trees.py index 3249ce23235..86e2391c616 100644 --- a/src/sage/combinat/words/suffix_trees.py +++ b/src/sage/combinat/words/suffix_trees.py @@ -501,7 +501,6 @@ def show(self, *args, **kwds): sage: t.show() # needs sage.plot """ self.plot(*args, **kwds).show() - return ################################################################################ # Suffix Trees @@ -656,7 +655,6 @@ def _process_letter(self, letter): # set the active state s, k = self._canonize(s, (k, i)) self._active_state = (s, (k, i+1)) - return def _test_and_split(self, s, k_p, letter): r""" @@ -918,7 +916,6 @@ def show(self, word_labels=None, *args, **kwds): sage: t.show(word_labels=False) # needs sage.plot """ self.plot(word_labels=word_labels, *args, **kwds).show() - return ##### # Various methods @@ -1115,7 +1112,6 @@ def to_explicit_suffix_tree(self): end_state, r = self._test_and_split(s, (k, i-1), end_of_string) # remove the end of string symbol from the word self._letters.pop() - return def edge_iterator(self): r""" diff --git a/src/sage/combinat/words/words.py b/src/sage/combinat/words/words.py index e940582f83c..403b28f2049 100644 --- a/src/sage/combinat/words/words.py +++ b/src/sage/combinat/words/words.py @@ -90,10 +90,10 @@ def Words(alphabet=None, length=None, finite=True, infinite=True): sage: Words('natural numbers') Finite and infinite words over Non negative integers """ - if isinstance(alphabet, FiniteWords) or \ - isinstance(alphabet, InfiniteWords) or \ - isinstance(alphabet, FiniteOrInfiniteWords) or \ - isinstance(alphabet, Words_n): + if isinstance(alphabet, (FiniteWords, + InfiniteWords, + FiniteOrInfiniteWords, + Words_n)): return alphabet if length is None: diff --git a/src/sage/crypto/key_exchange/diffie_hellman.py b/src/sage/crypto/key_exchange/diffie_hellman.py index 47b6bd392a8..8dee1010a19 100644 --- a/src/sage/crypto/key_exchange/diffie_hellman.py +++ b/src/sage/crypto/key_exchange/diffie_hellman.py @@ -254,7 +254,7 @@ def subgroup_size(self) -> Integer: def __len__(self) -> int: """ Calculates the size of the subgroup of `\\GF{p}` generated by - ``self.generator()``. This is a wrapper around `subgroup_size`. + ``self.generator()``. This is a wrapper around ``subgroup_size``. TESTS:: diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index 430ab98f3ae..32b4f1c8be2 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -22,7 +22,7 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, @@ -253,7 +253,7 @@ def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, P = quotient.parent() # P should be a univariate polynomial ring over ZZ_q - if not isinstance(P, PolynomialRing_general): + if not isinstance(P, PolynomialRing_generic): raise TypeError("quotient should be a univariate polynomial") assert P.base_ring() is ZZ_q diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index 610a97b05fb..c60202c6f23 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -2248,8 +2248,8 @@ def shift_rows_matrix(self): bs = r*c*e shift_rows = matrix(k, bs, bs) I = MatrixSpace(k, e, e)(1) - for x in range(0, c): - for y in range(0, r): + for x in range(c): + for y in range(r): _r = ((x*r)+y) * e _c = (((x*r)+((r+1)*y)) * e) % bs self._insert_matrix_into_matrix(shift_rows, I, _r, _c) @@ -2290,14 +2290,14 @@ def lin_matrix(self, length=None): if e == 4: l = [k.from_integer(x) for x in (5, 1, 12, 5)] for k in range( 0, length ): - for i in range(0, 4): - for j in range(0, 4): + for i in range(4): + for j in range(4): lin[k*4+j, k*4+i] = l[(i-j) % 4] ** (2**j) elif e == 8: l = [k.from_integer(x) for x in (5, 9, 249, 37, 244, 1, 181, 143)] for k in range( 0, length ): - for i in range(0, 8): - for j in range(0, 8): + for i in range(8): + for j in range(8): lin[k*8+j, k*8+i] = l[(i-j) % 8] ** (2**j) return lin @@ -2651,8 +2651,8 @@ def shift_rows_matrix(self): k = self.k bs = r*c shift_rows = matrix(k, r*c, r*c) - for x in range(0, c): - for y in range(0, r): + for x in range(c): + for y in range(r): _r = ((x*r)+y) _c = ((x*r)+((r+1)*y)) % bs shift_rows[_r, _c] = 1 diff --git a/src/sage/crypto/sboxes.py b/src/sage/crypto/sboxes.py index ab0f2759573..1e7911364a8 100644 --- a/src/sage/crypto/sboxes.py +++ b/src/sage/crypto/sboxes.py @@ -399,6 +399,43 @@ def monomial_function(n, e): return SBox(X**e) +def chi(n): + r""" + Return the `\chi` function defined over `\GF{2^n}` used in the nonlinear + layer of Keccak and Xoodyak. + + INPUT: + + - ``n`` -- size of the S-Box + + EXAMPLES:: + + sage: from sage.crypto.sboxes import chi + sage: chi(3) + (0, 3, 6, 1, 5, 4, 2, 7) + sage: chi(3).is_permutation() + True + sage: chi(4).is_permutation() + False + sage: chi(5) + (0, 9, 18, 11, 5, 12, 22, 15, 10, 3, 24, 1, 13, 4, 30, 7, 20, 21, 6, + 23, 17, 16, 2, 19, 26, 27, 8, 25, 29, 28, 14, 31) + """ + from sage.rings.integer_ring import ZZ + from sage.rings.finite_rings.finite_field_constructor import GF + from sage.modules.free_module_element import vector + + table = [0]*(1 << n) + + for x in range(1 << n): + vx = vector(GF(2), ZZ(x).digits(base=2, padto=n)) + vy = [vx[i] + (vx[(i+1) % n] + 1)*vx[(i+2) % n] for i in range(n)] + y = ZZ(vy, base=2) + table[x] = y + + return SBox(table) + + # Bijective S-Boxes mapping 9 bits to 9 # ===================================== diff --git a/src/sage/data_structures/bitset.pxd b/src/sage/data_structures/bitset.pxd index db627b294cd..a93e26c2ef9 100644 --- a/src/sage/data_structures/bitset.pxd +++ b/src/sage/data_structures/bitset.pxd @@ -37,4 +37,3 @@ cdef class Bitset(FrozenBitset): cpdef discard(self, unsigned long n) cpdef pop(self) cpdef clear(self) - diff --git a/src/sage/data_structures/meson.build b/src/sage/data_structures/meson.build index 8a94548917b..8c100328378 100644 --- a/src/sage/data_structures/meson.build +++ b/src/sage/data_structures/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'binary_matrix.pxd', 'binary_search.pxd', @@ -9,6 +10,8 @@ py.install_sources( 'bounded_integer_sequences.pxd', 'list_of_pairs.pxd', 'mutable_poset.py', + 'pairing_heap.h', + 'pairing_heap.pxd', 'sparse_bitset.pxd', 'stream.py', subdir: 'sage/data_structures', @@ -39,3 +42,18 @@ foreach name, pyx : extension_data ) endforeach +extension_data_cpp = { + 'pairing_heap' : files('pairing_heap.pyx'), +} + +foreach name, pyx : extension_data_cpp + py.extension_module( + name, + sources: pyx, + subdir: 'sage/data_structures/', + install: true, + override_options: ['cython_language=cpp'], + include_directories: [inc_cpython, inc_data_structures], + dependencies: [py_dep, cysignals, gmp], + ) +endforeach diff --git a/src/sage/data_structures/pairing_heap.h b/src/sage/data_structures/pairing_heap.h new file mode 100644 index 00000000000..3c6cbbf4216 --- /dev/null +++ b/src/sage/data_structures/pairing_heap.h @@ -0,0 +1,344 @@ +/* + * Pairing heap + * + * Implements a pairing heap data structure as described in [1]. See also [2] + * for more details. + * + * This implementation is templated by the type TI of items and the type TV of + * the value associated with an item. The type TI must be either a standard type + * (int, size_t, etc.) or a type equipped with a has function as supported by + * std::unordered_map. The top of the heap is the item with smallest value, + * i.e., this is a min heap data structure. The number of items in the heap is + * not fixed. It supports the following operations: + * + * - empty(): return true if the heap is empty, and false otherwise. + * + * - push(item, value): push an item to the heap with specified value. + * + * - top(): access the pair (item, value) at the top of the heap, i.e., with + * smallest value in time O(1). + * This operation assumes that the heap is not empty. + * + * - top_item(): access the item at the top of the heap in time O(1). + * This operation assumes that the heap is not empty. + * + * - top_value(): access the value of the item at the top of the heap in O(1). + * This operation assumes that the heap is not empty. + * + * - pop(): remove top item from the heap in amortize time O(log(n)). + * + * - decrease(item, new_value): change the value associated with the item to the + * specified value ``new_value`` in time o(log(n)). The new value must be + * smaller than the previous one. Otherwise the structure of the heap is no + * longer guaranteed. + * If the item is not already in the heap, this method calls method ``push``. + * + * - contains(item): check whether specified item is in the heap in time O(1). + * + * - value(item): return the value associated with the item in the heap. + * This operation assumes that the item is already in the heap. + * + * References: + * + * [1] M. L. Fredman, R. Sedgewick, D. D. Sleator, and R. E. Tarjan. + * "The pairing heap: a new form of self-adjusting heap". + * Algorithmica. 1 (1): 111-129, 1986. doi:10.1007/BF01840439. + * + * [2] https://en.wikipedia.org/wiki/Pairing_heap + * + * Author: + * - David Coudert + * + */ + +#ifndef PAIRING_HEAP_H +#define PAIRING_HEAP_H + +#include +#include + +namespace pairing_heap { + + template< + typename TV, // type of values + typename T // type of the child class + > + struct PairingHeapNodeBase { + public: + + bool operator<=(PairingHeapNodeBase const& other) const { + return static_cast(this)->le_implem(static_cast(other)); + } + + // Pair list of heaps and return pointer to the top of resulting heap + static T *_pair(T *p) { + if (p == nullptr) { + return nullptr; + } + + /* + * Move toward the end of the list, counting elements along the way. + * This is done in order to: + * - know whether the list has odd or even number of nodes + * - speed up going-back through the list + */ + size_t children = 1; + T *it = p; + while (it->next != nullptr) { + it = it->next; + children++; + } + + T *result; + + if (children % 2 == 1) { + T *a = it; + it = it->prev; + a->prev = a->next = nullptr; + result = a; + } else { + T *a = it; + T *b = it->prev; + it = it->prev->prev; + a->prev = a->next = b->prev = b->next = nullptr; + result = _merge(a, b); + } + + for (size_t i = 0; i < (children - 1) / 2; i++) { + T *a = it; + T *b = it->prev; + it = it->prev->prev; + a->prev = a->next = b->prev = b->next = nullptr; + result = _merge(_merge(a, b), result); + } + + return result; + } // end _pair + + + // Merge 2 heaps and return pointer to the top of resulting heap + static T *_merge(T *a, T *b) { + if (*a <= *b) { // Use comparison method of PairingHeapNodeBase + _link(a, b); + return a; + } else { + _link(b, a); + return b; + } + } // end _merge + + + // Make b a child of a + static void _link(T *a, T *b) { + if (a->child != nullptr) { + b->next = a->child; + a->child->prev = b; + } + b->prev = a; + a->child = b; + } // end _link + + + // Remove p from its parent children list + static void _unlink(T *p) { + if (p->prev->child == p) { + p->prev->child = p->next; + } else { + p->prev->next = p->next; + } + if (p->next != nullptr) { + p->next->prev = p->prev; + } + p->prev = nullptr; + p->next = nullptr; + } // end _unlink + + + TV value; // value associated to the node + T * prev; // Previous sibling of the node or parent + T * next; // Next sibling of the node + T * child; // First child of the node + + protected: + // Only derived class can build a PairingHeapNodeBase + explicit PairingHeapNodeBase(const TV &some_value) + : value{some_value}, prev{nullptr}, next{nullptr}, child{nullptr} { + } + }; // end struct PairingHeapNodeBase + + + template< + typename TI, // type of items stored in the node + typename TV // type of values associated with the stored item + // Assumes TV is a comparable type + > + class PairingHeapNode + : public PairingHeapNodeBase> { + + public: + PairingHeapNode(TI const& some_item, TV const& some_value) + : Base_(some_value), item(some_item) { + } + + bool le_implem(PairingHeapNode const& other) const { + return this->value <= other.value; + } + + TI item; // item contained in the node + + private: + using Base_ = PairingHeapNodeBase>; + }; + + + class PairingHeapNodePy + : public PairingHeapNodeBase { + public: + PairingHeapNodePy(PyObject *some_value) + : Base_(some_value) { + } + + bool le_implem(PairingHeapNodePy const& other) const { + return PyObject_RichCompareBool(this->value, other.value, Py_LE); + } + + private: + using Base_ = PairingHeapNodeBase; + }; + + + + template< + typename TI, // type of items stored in the node + typename TV // type of values associated with the stored item + // Assume TV is a comparable type + > + class PairingHeap + { + public: + using HeapNodeType = PairingHeapNode; + + // Constructor + explicit PairingHeap() + : root(nullptr) { + } + + // Copy constructor + PairingHeap(PairingHeap const *other) + : root(nullptr) { + for (auto const& it: other->nodes) { + push(it.first, it.second->value); + } + } + + // Destructor + virtual ~PairingHeap() { + for (auto const& it: nodes) { + delete it.second; + } + } + + // Return true if the heap is empty, else false + bool empty() const { + return root == nullptr; + } + + // Return true if the heap is not empty, else false + explicit operator bool() const { + return root != nullptr; + } + + // Insert an item into the heap with specified value (priority) + void push(const TI &some_item, const TV &some_value) { + if (contains(some_item)) { + throw std::invalid_argument("item already in the heap"); + } + PairingHeapNode *p = new PairingHeapNode(some_item, some_value); + nodes[some_item] = p; + root = empty() ? p : HeapNodeType::_merge(root, p); + } + + // Return the top pair (item, value) of the heap + std::pair top() const { + if (empty()) { + throw std::domain_error("trying to access the top of an empty heap"); + } + return std::make_pair(root->item, root->value); + } + + // Return the top item of the heap + TI top_item() const { + if (empty()) { + throw std::domain_error("trying to access the top of an empty heap"); + } + return root->item; + } + + // Return the top value of the heap + TV top_value() const { + if (empty()) { + throw std::domain_error("trying to access the top of an empty heap"); + } + return root->value; + } + + // Remove the top element from the heap. Do nothing if empty + void pop() { + if (not empty()) { + PairingHeapNode *p = root->child; + nodes.erase(root->item); + delete root; + root = HeapNodeType::_pair(p); + } + } + + // Decrease the value of specified item + // If the item is not in the heap, push it + void decrease(const TI &some_item, const TV &new_value) { + if (contains(some_item)) { + PairingHeapNode *p = nodes[some_item]; + if (p->value <= new_value) { + throw std::invalid_argument("the new value must be less than the current value"); + } + p->value = new_value; + if (p->prev != nullptr) { + HeapNodeType::_unlink(p); + root = HeapNodeType::_merge(root, p); + } + } else { + push(some_item, new_value); + } + } + + // Check if specified item is in the heap + bool contains(TI const& some_item) const { + return nodes.find(some_item) != nodes.end(); + } + + // Return the value associated with the item + TV value(const TI &some_item) const { + auto it = nodes.find(some_item); + if (it == nodes.end()) { + throw std::invalid_argument("the specified item is not in the heap"); + } + return it->second->value; + } + + // Return the number of items in the heap + size_t size() const { + return nodes.size(); + } + + private: + + // Pointer to the top of the heap + PairingHeapNode *root; + + // Map used to access stored items + std::unordered_map *> nodes; + + }; // end class PairingHeap + +} // end namespace pairing_heap + +#endif diff --git a/src/sage/data_structures/pairing_heap.pxd b/src/sage/data_structures/pairing_heap.pxd new file mode 100644 index 00000000000..875e654c457 --- /dev/null +++ b/src/sage/data_structures/pairing_heap.pxd @@ -0,0 +1,87 @@ +# ****************************************************************************** +# Copyright (C) 2024 David Coudert +# +# 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 cpython cimport PyObject +from libcpp.pair cimport pair +from sage.data_structures.bitset_base cimport bitset_t + + +# ============================================================================== +# Interface to pairing heap data structure from ./pairing_heap.h +# ============================================================================== + +cdef extern from "./pairing_heap.h" namespace "pairing_heap": + cdef cppclass PairingHeap[TypeOfItem, TypeOfValue]: + PairingHeap() except + + PairingHeap(PairingHeap[TypeOfItem, TypeOfValue]) except + + bint empty() + void push(TypeOfItem, TypeOfValue) except + + pair[TypeOfItem, TypeOfValue] top() except + + TypeOfItem top_item() except + + TypeOfValue top_value() except + + void pop() except + + void decrease(TypeOfItem, TypeOfValue) except + + bint contains(TypeOfItem) + TypeOfValue value(TypeOfItem) except + + size_t size() + + cdef cppclass PairingHeapNodePy: + PyObject * value # value associated with the item + PairingHeapNodePy * prev # Previous sibling of the node or parent + PairingHeapNodePy * next # Next sibling of the node + PairingHeapNodePy * child # First child of the node + + @staticmethod + PairingHeapNodePy * _merge(PairingHeapNodePy * a, PairingHeapNodePy * b) except + + + @staticmethod + PairingHeapNodePy * _pair(PairingHeapNodePy * p) except + + + @staticmethod + void _link(PairingHeapNodePy * a, PairingHeapNodePy * b) + + @staticmethod + void _unlink(PairingHeapNodePy * p) + + +# ============================================================================== +# Pairing heap data structure with fixed capacity n +# ============================================================================== + +cdef class PairingHeap_class: + cdef size_t n # maximum number of items + cdef PairingHeapNodePy * root # pointer to the top of the heap + cdef PairingHeapNodePy * nodes # array of size n to store items + cdef size_t number_of_items # number of active items + cpdef bint empty(self) noexcept + cpdef bint full(self) noexcept + cpdef size_t capacity(self) noexcept + cpdef size_t size(self) noexcept + cpdef tuple top(self) + cpdef object top_value(self) + cpdef void pop(self) noexcept + + +cdef class PairingHeap_of_n_integers(PairingHeap_class): + cdef bitset_t active # bitset to identify active items + cpdef void push(self, size_t item, object value) except * + cpdef size_t top_item(self) except * + cpdef void decrease(self, size_t item, object new_value) except * + cpdef object value(self, size_t item) + + +cdef class PairingHeap_of_n_hashables(PairingHeap_class): + cdef list _int_to_item # mapping from integers to items + cdef dict _item_to_int # mapping from items to integers + cdef list free_idx # list of free indexes + cpdef void push(self, object item, object value) except * + cpdef object top_item(self) + cpdef void decrease(self, object item, object new_value) except * + cpdef object value(self, object item) diff --git a/src/sage/data_structures/pairing_heap.pyx b/src/sage/data_structures/pairing_heap.pyx new file mode 100644 index 00000000000..ec08be43652 --- /dev/null +++ b/src/sage/data_structures/pairing_heap.pyx @@ -0,0 +1,1462 @@ +# distutils: language = c++ +r""" +Pairing Heap + +This module proposes several implementations of the pairing heap data structure +[FSST1986]_. See the :wikipedia:`Pairing_heap` for more information on this +min-heap data structure. + +- :class:`PairingHeap_of_n_integers`: a pairing heap data structure with fixed + capacity `n`. Its items are integers in the range `[0, n-1]`. Values can be of + any type equipped with a comparison method (``<=``). + +- :class:`PairingHeap_of_n_hashables`: a pairing heap data structure with fixed + capacity `n`. Its items can be of any hashable type. Values can be of any type + equipped with a comparison method (``<=``). + +- ``PairingHeap``: interface to a pairing heap data structure written in C++. + The advantages of this data structure are that: its capacity is unbounded; + items can be of any hashable type equipped with a hashing method that can be + supported by ``std::unordered_map``; values can be of any specified type + equipped with a comparison method (``<=``). This data structure is for + internal use and therefore cannot be accessed from a shell. + +EXAMPLES: + +Pairing heap of `n` integers in the range `[0, n-1]`:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(10); P + PairingHeap_of_n_integers: capacity 10, size 0 + sage: P.push(1, 3) + sage: P.push(2, 2) + sage: P + PairingHeap_of_n_integers: capacity 10, size 2 + sage: P.top() + (2, 2) + sage: P.decrease(1, 1) + sage: P.top() + (1, 1) + sage: P.pop() + sage: P.top() + (2, 2) + + sage: P = PairingHeap_of_n_integers(10) + sage: P.push(1, (2, 'a')) + sage: P.push(2, (2, 'b')) + sage: P.top() + (1, (2, 'a')) + +Pairing heap of `n` hashables:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(10); P + PairingHeap_of_n_hashables: capacity 10, size 0 + sage: P.push(1, 3) + sage: P.push('b', 2) + sage: P.push((1, 'abc'), 4) + sage: P.top() + ('b', 2) + sage: P.decrease((1, 'abc'), 1) + sage: P.top() + ((1, 'abc'), 1) + sage: P.pop() + sage: P.top() + ('b', 2) + + sage: # needs sage.graphs + sage: P = PairingHeap_of_n_hashables(10) + sage: P.push(('a', 1), (2, 'b')) + sage: P.push(2, (2, 'a')) + sage: g = Graph(2, immutable=True) + sage: P.push(g, (3, 'z')) + sage: P.top() + (2, (2, 'a')) + sage: P.decrease(g, (1, 'z')) + sage: P.top() + (Graph on 2 vertices, (1, 'z')) + sage: while P: + ....: print(P.top()) + ....: P.pop() + (Graph on 2 vertices, (1, 'z')) + (2, (2, 'a')) + (('a', 1), (2, 'b')) +""" +# ****************************************************************************** +# Copyright (C) 2024 David Coudert +# +# 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 libcpp.pair cimport pair +from cpython.ref cimport PyObject, Py_INCREF, Py_XDECREF +from cysignals.signals cimport sig_on, sig_off, sig_check +from cysignals.memory cimport check_allocarray, sig_free +from sage.data_structures.bitset_base cimport (bitset_init, bitset_free, + bitset_add, bitset_remove, + bitset_in) +from sage.misc.prandom import shuffle + + +# ============================================================================== +# Class PairingHeap_class +# ============================================================================== + +cdef class PairingHeap_class: + r""" + Common class and methods for :class:`PairingHeap_of_n_integers` and + :class:`PairingHeap_of_n_hashables`. + """ + + def __repr__(self): + r""" + Return a string representing ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5); P + PairingHeap_of_n_integers: capacity 5, size 0 + sage: P.push(1, 2) + sage: P + PairingHeap_of_n_integers: capacity 5, size 1 + """ + return f"{type(self).__name__}: capacity {self.n}, size {len(self)}" + + def __bool__(self): + r""" + Check whether ``self`` is not empty. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: 'not empty' if P else 'empty' + 'empty' + sage: P.push(1, 2) + sage: 'not empty' if P else 'empty' + 'not empty' + """ + return self.root != NULL + + cpdef bint empty(self) noexcept: + r""" + Check whether the heap is empty. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: P.empty() + True + sage: P.push(1, 2) + sage: P.empty() + False + """ + return self.root == NULL + + cpdef bint full(self) noexcept: + r""" + Check whether the heap is full. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(2) + sage: P.full() + False + sage: P.push(0, 2) + sage: P.push(1, 3) + sage: P.full() + True + """ + return self.n == self.number_of_items + + cpdef size_t capacity(self) noexcept: + r""" + Return the maximum capacity of the heap. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: P.capacity() + 5 + sage: P.push(1, 2) + sage: P.capacity() + 5 + """ + return self.n + + cpdef size_t size(self) noexcept: + r""" + Return the number of items in the heap. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: P.size() + 0 + sage: P.push(1, 2) + sage: P.size() + 1 + + One may also use Python's ``__len__``:: + + sage: len(P) + 1 + """ + return self.number_of_items + + def __len__(self): + r""" + Return the number of items in the heap. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: len(P) + 0 + sage: P.push(1, 2) + sage: len(P) + 1 + """ + return self.number_of_items + + cpdef tuple top(self): + r""" + Return the top pair (item, value) of the heap. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: P.push(1, 2) + sage: P.top() + (1, 2) + sage: P.push(3, 1) + sage: P.top() + (3, 1) + + sage: P = PairingHeap_of_n_integers(3) + sage: P.top() + Traceback (most recent call last): + ... + ValueError: trying to access the top of an empty heap + """ + raise NotImplementedError() + + cpdef object top_value(self): + r""" + Return the value of the top item of the heap. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: P.push(1, 2) + sage: P.top() + (1, 2) + sage: P.top_value() + 2 + + sage: P = PairingHeap_of_n_integers(3) + sage: P.top_value() + Traceback (most recent call last): + ... + ValueError: trying to access the top of an empty heap + """ + if not self: + raise ValueError("trying to access the top of an empty heap") + return self.root.value + + cpdef void pop(self) noexcept: + r""" + Remove the top item from the heap. + + If the heap is already empty, we do nothing. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5); P + PairingHeap_of_n_integers: capacity 5, size 0 + sage: P.push(1, 2); P + PairingHeap_of_n_integers: capacity 5, size 1 + sage: P.pop(); P + PairingHeap_of_n_integers: capacity 5, size 0 + sage: P.pop(); P + PairingHeap_of_n_integers: capacity 5, size 0 + """ + raise NotImplementedError() + + +# ============================================================================== +# Class PairingHeap_of_n_integers +# ============================================================================== + +cdef class PairingHeap_of_n_integers(PairingHeap_class): + r""" + Pairing Heap for items in range `[0, n - 1]`. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5); P + PairingHeap_of_n_integers: capacity 5, size 0 + sage: P.push(1, 3) + sage: P.push(2, 2) + sage: P + PairingHeap_of_n_integers: capacity 5, size 2 + sage: P.top() + (2, 2) + sage: P.decrease(1, 1) + sage: P.top() + (1, 1) + sage: P.pop() + sage: P.top() + (2, 2) + + TESTS:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(0) + Traceback (most recent call last): + ... + ValueError: the capacity of the heap must be strictly positive + sage: P = PairingHeap_of_n_integers(1); P + PairingHeap_of_n_integers: capacity 1, size 0 + sage: P = PairingHeap_of_n_integers(5) + sage: P.push(11, 3) + Traceback (most recent call last): + ... + ValueError: item must be in range [0, 4] + """ + + def __init__(self, size_t n): + r""" + Construct the ``PairingHeap_of_n_integers`` where items are integers + from `0` to `n-1`. + + INPUT: + + - ``n`` -- strictly positive integer; the maximum number of items in the heap + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5); P + PairingHeap_of_n_integers: capacity 5, size 0 + sage: P.push(1, 2); P + PairingHeap_of_n_integers: capacity 5, size 1 + sage: P.push(2, 3); P + PairingHeap_of_n_integers: capacity 5, size 2 + sage: P.pop(); P + PairingHeap_of_n_integers: capacity 5, size 1 + sage: P.push(10, 1) + Traceback (most recent call last): + ... + ValueError: item must be in range [0, 4] + sage: PairingHeap_of_n_integers(1) + PairingHeap_of_n_integers: capacity 1, size 0 + + TESTS:: + + sage: PairingHeap_of_n_integers(0) + Traceback (most recent call last): + ... + ValueError: the capacity of the heap must be strictly positive + sage: P = PairingHeap_of_n_integers(10) + sage: P.push(1, 1); P.push(7, 0); P.push(0, 4); P.pop(); P.push(5, 5) + sage: TestSuite(P).run(skip="_test_pickling") + """ + if not n: + raise ValueError("the capacity of the heap must be strictly positive") + self.n = n + self.root = NULL + self.nodes = check_allocarray(n, sizeof(PairingHeapNodePy)) + bitset_init(self.active, n) + self.number_of_items = 0 + + def __dealloc__(self): + """ + Deallocate ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: del P + """ + sig_free(self.nodes) + bitset_free(self.active) + + cpdef void push(self, size_t item, object value) except *: + r""" + Insert an item into the heap with specified value (priority). + + INPUT: + + - ``item`` -- nonnegative integer; the item to consider + + - ``value`` -- the value associated with ``item`` + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: P.push(1, 2) + sage: P.top() + (1, 2) + sage: P.push(3, 1) + sage: P.top() + (3, 1) + + TESTS:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: P.push(1, 2) + sage: P.push(1, 2) + Traceback (most recent call last): + ... + ValueError: 1 is already in the heap + sage: P.push(11, 2) + Traceback (most recent call last): + ... + ValueError: item must be in range [0, 4] + sage: P.push(-1, 0) + Traceback (most recent call last): + ... + OverflowError: can't convert negative value to size_t + """ + if item >= self.n: + raise ValueError(f"item must be in range [0, {self.n - 1}]") + if item in self: + raise ValueError(f"{item} is already in the heap") + + cdef PairingHeapNodePy * p = self.nodes + item + Py_INCREF(value) + p.value = value + p.prev = p.next = p.child = NULL + if self.root == NULL: + self.root = p + else: + self.root = PairingHeapNodePy._merge(self.root, p) + bitset_add(self.active, item) + self.number_of_items += 1 + + cpdef tuple top(self): + r""" + Return the top pair (item, value) of the heap. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: P.push(1, 2) + sage: P.top() + (1, 2) + sage: P.push(3, 1) + sage: P.top() + (3, 1) + + sage: P = PairingHeap_of_n_integers(3) + sage: P.top() + Traceback (most recent call last): + ... + ValueError: trying to access the top of an empty heap + """ + if not self: + raise ValueError("trying to access the top of an empty heap") + return self.root - self.nodes, self.root.value + + cpdef size_t top_item(self) except *: + r""" + Return the top item of the heap. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: P.push(1, 2) + sage: P.top() + (1, 2) + sage: P.top_item() + 1 + + sage: P = PairingHeap_of_n_integers(3) + sage: P.top_item() + Traceback (most recent call last): + ... + ValueError: trying to access the top of an empty heap + """ + if not self: + raise ValueError("trying to access the top of an empty heap") + return self.root - self.nodes + + cpdef void pop(self) noexcept: + r""" + Remove the top item from the heap. + + If the heap is already empty, we do nothing. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5); P + PairingHeap_of_n_integers: capacity 5, size 0 + sage: P.push(1, 2); P + PairingHeap_of_n_integers: capacity 5, size 1 + sage: P.push(2, 3); P + PairingHeap_of_n_integers: capacity 5, size 2 + sage: P.pop(); P + PairingHeap_of_n_integers: capacity 5, size 1 + sage: P.pop(); P + PairingHeap_of_n_integers: capacity 5, size 0 + sage: P.pop(); P + PairingHeap_of_n_integers: capacity 5, size 0 + """ + if not self: + return + cdef size_t item = self.top_item() + Py_XDECREF(self.nodes[item].value) + bitset_remove(self.active, item) + self.number_of_items -= 1 + self.root = PairingHeapNodePy._pair(self.root.child) + + cpdef void decrease(self, size_t item, object new_value) except *: + r""" + Decrease the value of specified item. + + This method is more permissive than it should as it can also be used to + push an item in the heap. + + INPUT: + + - ``item`` -- nonnegative integer; the item to consider + + - ``new_value`` -- the new value for ``item`` + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: 3 in P + False + sage: P.decrease(3, 33) + sage: 3 in P + True + sage: P.top() + (3, 33) + sage: P.push(1, 10) + sage: P.top() + (1, 10) + sage: P.decrease(3, 7) + sage: P.top() + (3, 7) + + TESTS:: + + sage: P = PairingHeap_of_n_integers(5) + sage: P.push(1, 3) + sage: P.decrease(1, 2) + sage: P.decrease(1, 2) + Traceback (most recent call last): + ... + ValueError: the new value must be less than the current value + """ + if item >= self.n: + raise ValueError(f"item must be in range [0, {self.n - 1}]") + cdef PairingHeapNodePy * p + if bitset_in(self.active, item): + p = self.nodes + item + if p.value <= new_value: + raise ValueError("the new value must be less than the current value") + Py_XDECREF(p.value) + Py_INCREF(new_value) + p.value = new_value + if p.prev != NULL: + PairingHeapNodePy._unlink(p) + self.root = PairingHeapNodePy._merge(self.root, p) + else: + self.push(item, new_value) + + def __contains__(self, size_t item): + r""" + Check whether the specified item is in the heap. + + INPUT: + + - ``item`` -- nonnegative integer; the item to consider + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: 3 in P + False + sage: P.push(3, 33) + sage: 3 in P + True + sage: 100 in P + False + """ + if item >= self.n: + return False + return bitset_in(self.active, item) + + contains = __contains__ + + cpdef object value(self, size_t item): + r""" + Return the value associated with the item. + + INPUT: + + - ``item`` -- nonnegative integer; the item to consider + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: P.push(3, 33) + sage: P.push(1, 10) + sage: P.value(3) + 33 + sage: P.value(7) + Traceback (most recent call last): + ... + ValueError: 7 is not in the heap + """ + if item not in self: + raise ValueError(f"{item} is not in the heap") + return self.nodes[item].value + + +# ============================================================================== +# Class PairingHeap_of_n_hashables +# ============================================================================== + +cdef class PairingHeap_of_n_hashables(PairingHeap_class): + r""" + Pairing Heap for `n` hashable items. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(5); P + PairingHeap_of_n_hashables: capacity 5, size 0 + sage: P.push(1, 3) + sage: P.push('abc', 2); P + PairingHeap_of_n_hashables: capacity 5, size 2 + sage: P.top() + ('abc', 2) + sage: P.decrease(1, 1) + sage: P.top() + (1, 1) + sage: P.pop() + sage: P.top() + ('abc', 2) + + sage: P = PairingHeap_of_n_hashables(5) + sage: P.push(1, (2, 3)) + sage: P.push('a', (2, 2)) + sage: P.push('b', (3, 3)) + sage: P.push('c', (2, 1)) + sage: P.top() + ('c', (2, 1)) + sage: P.push(Graph(2, immutable=True), (1, 7)) + sage: P.top() + (Graph on 2 vertices, (1, 7)) + sage: P.decrease('b', (1, 5)) + sage: P.top() + ('b', (1, 5)) + + TESTS:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(0) + Traceback (most recent call last): + ... + ValueError: the capacity of the heap must be strictly positive + sage: P = PairingHeap_of_n_hashables(1); P + PairingHeap_of_n_hashables: capacity 1, size 0 + sage: P.push(11, 3) + sage: P.push(12, 4) + Traceback (most recent call last): + ... + ValueError: the heap is full + + sage: P = PairingHeap_of_n_hashables(10) + sage: P.push(1, 'John') + sage: P.push(4, 42) + Traceback (most recent call last): + ... + TypeError: unsupported operand parent(s) for >=: 'Integer Ring' and '' + """ + + def __init__(self, size_t n): + r""" + Construct the ``PairingHeap_of_n_hashables``. + + This pairing heap has a maximum capacity of `n` items and each item is a + hashable object. + + INPUT: + + - ``n`` -- strictly positive integer; the maximum number of items in the heap + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(2); P + PairingHeap_of_n_hashables: capacity 2, size 0 + sage: P.push(1, 2) + sage: P + PairingHeap_of_n_hashables: capacity 2, size 1 + sage: P.push(2, 3) + sage: P + PairingHeap_of_n_hashables: capacity 2, size 2 + sage: P.full() + True + sage: P.push(10, 1) + Traceback (most recent call last): + ... + ValueError: the heap is full + sage: P.pop() + sage: P + PairingHeap_of_n_hashables: capacity 2, size 1 + sage: P.push(10, 1) + + TESTS:: + + sage: P = PairingHeap_of_n_hashables(0) + Traceback (most recent call last): + ... + ValueError: the capacity of the heap must be strictly positive + sage: P = PairingHeap_of_n_hashables(1); P + PairingHeap_of_n_hashables: capacity 1, size 0 + sage: P = PairingHeap_of_n_hashables(6) + sage: P.push(1, -0.5); P.push(frozenset(), 1); P.pop(); P.push('a', 3.5) + sage: TestSuite(P).run(skip="_test_pickling") + """ + if not n: + raise ValueError("the capacity of the heap must be strictly positive") + self.n = n + self.root = NULL + self.nodes = check_allocarray(n, sizeof(PairingHeapNodePy)) + self.number_of_items = 0 + self._int_to_item = [None] * n + self._item_to_int = dict() + self.free_idx = list(range(n)) + + def __dealloc__(self): + """ + Deallocate ``self``. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_integers + sage: P = PairingHeap_of_n_integers(5) + sage: del P + """ + sig_free(self.nodes) + + cpdef void push(self, object item, object value) except *: + r""" + Insert an item into the heap with specified value (priority). + + INPUT: + + - ``item`` -- a hashable object; the item to add + + - ``value`` -- the value associated with ``item`` + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(5) + sage: P.push(1, 2) + sage: P.top() + (1, 2) + sage: P.push(3, 1) + sage: P.top() + (3, 1) + + TESTS:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(2) + sage: P.push(1, 2) + sage: P.push(1, 2) + Traceback (most recent call last): + ... + ValueError: 1 is already in the heap + sage: P.push(11, 2) + sage: P.push(7, 5) + Traceback (most recent call last): + ... + ValueError: the heap is full + """ + if item in self: + raise ValueError(f"{item} is already in the heap") + if self.full(): + raise ValueError("the heap is full") + + cdef size_t idx = self.free_idx.pop() + self._int_to_item[idx] = item + self._item_to_int[item] = idx + cdef PairingHeapNodePy * p = self.nodes + idx + Py_INCREF(value) + p.value = value + p.prev = p.next = p.child = NULL + if self.root == NULL: + self.root = p + else: + self.root = PairingHeapNodePy._merge(self.root, p) + self.number_of_items += 1 + + cpdef tuple top(self): + r""" + Return the top pair (item, value) of the heap. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(5) + sage: P.push(1, 2) + sage: P.top() + (1, 2) + sage: P.push(3, 1) + sage: P.top() + (3, 1) + + sage: P = PairingHeap_of_n_hashables(3) + sage: P.top() + Traceback (most recent call last): + ... + ValueError: trying to access the top of an empty heap + """ + if not self: + raise ValueError("trying to access the top of an empty heap") + cdef size_t idx = self.root - self.nodes + return self._int_to_item[idx], self.root.value + + cpdef object top_item(self): + r""" + Return the top item of the heap. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(5) + sage: P.push(1, 2) + sage: P.top() + (1, 2) + sage: P.top_item() + 1 + + sage: P = PairingHeap_of_n_hashables(3) + sage: P.top_item() + Traceback (most recent call last): + ... + ValueError: trying to access the top of an empty heap + """ + if not self: + raise ValueError("trying to access the top of an empty heap") + cdef size_t idx = self.root - self.nodes + return self._int_to_item[idx] + + cpdef void pop(self) noexcept: + r""" + Remove the top item from the heap. + + If the heap is already empty, we do nothing. + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(5); len(P) + 0 + sage: P.push(1, 2); len(P) + 1 + sage: P.push(2, 3); len(P) + 2 + sage: P.pop(); len(P) + 1 + sage: P.pop(); len(P) + 0 + sage: P.pop(); len(P) + 0 + """ + if not self: + return + cdef object item = self.top_item() + cdef size_t idx = self._item_to_int[item] + Py_XDECREF(self.nodes[idx].value) + self.free_idx.append(idx) + del self._item_to_int[item] + self.number_of_items -= 1 + self.root = PairingHeapNodePy._pair(self.root.child) + + cpdef void decrease(self, object item, object new_value) except *: + r""" + Decrease the value of specified item. + + This method is more permissive than it should as it can also be used to + push an item in the heap. + + INPUT: + + - ``item`` -- the item to consider + + - ``new_value`` -- the new value for ``item`` + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(5) + sage: 3 in P + False + sage: P.decrease(3, 33) + sage: 3 in P + True + sage: P.top() + (3, 33) + sage: P.push(1, 10) + sage: P.top() + (1, 10) + sage: P.decrease(3, 7) + sage: P.top() + (3, 7) + + TESTS:: + + sage: P = PairingHeap_of_n_hashables(5) + sage: P.push(1, 3) + sage: P.decrease(1, 2) + sage: P.decrease(1, 2) + Traceback (most recent call last): + ... + ValueError: the new value must be less than the current value + """ + cdef PairingHeapNodePy * p + cdef size_t idx + if item in self: + idx = self._item_to_int[item] + p = self.nodes + idx + if p.value <= new_value: + raise ValueError("the new value must be less than the current value") + Py_XDECREF(p.value) + Py_INCREF(new_value) + p.value = new_value + if p.prev != NULL: + PairingHeapNodePy._unlink(p) + self.root = PairingHeapNodePy._merge(self.root, p) + else: + self.push(item, new_value) + + def __contains__(self, object item): + r""" + Check whether the specified item is in the heap. + + INPUT: + + - ``item`` -- the item to consider + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(5) + sage: 3 in P + False + sage: P.push(3, 33) + sage: 3 in P + True + sage: 100 in P + False + """ + return item in self._item_to_int + + contains = __contains__ + + cpdef object value(self, object item): + r""" + Return the value associated with the item. + + INPUT: + + - ``item`` -- the item to consider + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import PairingHeap_of_n_hashables + sage: P = PairingHeap_of_n_hashables(5) + sage: P.push(3, 33) + sage: P.push(1, 10) + sage: P.value(3) + 33 + sage: P.value(7) + Traceback (most recent call last): + ... + ValueError: 7 is not in the heap + """ + if item not in self: + raise ValueError(f"{item} is not in the heap") + cdef size_t idx = self._item_to_int[item] + return self.nodes[idx].value + + +# ============================================================================== +# Methods to check the validity of the pairing heaps +# ============================================================================== + +def _test_PairingHeap_from_C(n=100): + r""" + Test :class:`~sage.data_structures.pairing_heap.PairingHeap`. + + INPUT: + + - ``n`` -- a strictly positive integer (default: 100); the maximum capacity + of the heap + + TESTS:: + + sage: from sage.data_structures.pairing_heap import _test_PairingHeap_from_C + sage: _test_PairingHeap_from_C(100) + """ + from sage.misc.prandom import randint, shuffle + sig_on() + cdef PairingHeap[size_t, size_t] PH = PairingHeap[size_t, size_t]() + sig_off() + + # Initialize a list of tuples (value, item) randomly ordered + items = list(range(n)) + values = list(range(n)) + shuffle(items) + shuffle(values) + cdef list Lref = list(zip(values, items)) + + for value, item in Lref: + PH.push(item, value) + sig_check() + + L = [] + while not PH.empty(): + item, value = PH.top() + L.append((value, item)) + PH.pop() + sig_check() + + if L != sorted(Lref): + raise ValueError('the order is not good') + + # Test decrease key operations. We first push items in the heap with an + # excess of k in the value. Then we decrease the keys in a random order by + # random values until returning to the original values. We finally check the + # validity of the resulting ordering. + k = 10 + dec = {item: k for item in items} + shuffle(Lref) + for value, item in Lref: + PH.push(item, value + k) + sig_check() + + L = list(items) + while L: + i = randint(0, len(L) - 1) + item = L[i] + d = randint(1, dec[item]) + dec[item] -= d + if not dec[item]: + L[i] = L[-1] + L.pop() + PH.decrease(item, PH.value(item) - d) + sig_check() + + L = [] + while not PH.empty(): + item, value = PH.top() + L.append((value, item)) + PH.pop() + sig_check() + + if L != sorted(Lref): + raise ValueError('the order is not good') + + # Different cost function + from sage.functions.trig import sin, cos + sig_on() + cdef PairingHeap[size_t, pair[size_t, size_t]] HH = PairingHeap[size_t, pair[size_t, size_t]]() + sig_off() + + for i in range(n): + HH.push(i, (sin(i), cos(i))) + sig_check() + + L = [] + while not HH.empty(): + L.append(HH.top()) + HH.pop() + sig_check() + + for (u, cu), (v, cv) in zip(L, L[1:]): + if cu > cv: + print(u, cu, v, cv) + + # We finally show that an error is raised when trying to access the top of + # an empty heap + try: + _ = HH.top() + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + try: + _ = HH.top_item() + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + try: + _ = HH.top_value() + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + # Or to get the value associated to an item that is not in the heap + try: + _ = HH.value(123) + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + +def _test_PairingHeap_of_n_integers(n=100): + r""" + Test :class:`~sage.data_structures.pairing_heap.PairingHeap_of_n_integers`. + + INPUT: + + - ``n`` -- a strictly positive integer (default: 100); the maximum capacity + of the heap + + TESTS:: + + sage: from sage.data_structures.pairing_heap import _test_PairingHeap_of_n_integers + sage: _test_PairingHeap_of_n_integers(100) + """ + from sage.misc.prandom import randint, shuffle + + sig_on() + cdef PairingHeap_of_n_integers P = PairingHeap_of_n_integers(n) + sig_off() + + # Initialize a list of tuples (value, item) randomly ordered + cdef list items = list(range(n)) + cdef list values = list(range(n)) + shuffle(items) + shuffle(values) + cdef list Lref = list(zip(values, items)) + + cdef int value, item + for value, item in Lref: + P.push(item, value) + sig_check() + + cdef list L = [] + while P: + item, value = P.top() + L.append((value, item)) + P.pop() + sig_check() + + if L != sorted(Lref): + raise ValueError('the order is not good') + + # Test decrease key operations. We first push items in the heap with an + # excess of k in the value. Then we decrease the keys in a random order by + # random values until returning to the original values. We finally check the + # validity of the resulting ordering. + cdef int k = 10 + cdef list dec = [k] * n + shuffle(Lref) + for value, item in Lref: + P.push(item, value + k) + sig_check() + + L = list(items) + while L: + i = randint(0, len(L) - 1) + item = L[i] + d = randint(1, dec[item]) + dec[item] -= d + if not dec[item]: + L[i] = L[-1] + L.pop() + P.decrease(item, P.value(item) - d) + sig_check() + + L = [] + while P: + item, value = P.top() + L.append((value, item)) + P.pop() + sig_check() + + if L != sorted(Lref): + raise ValueError('the order is not good') + + # We finally show that an error is raised when trying to access the top of + # an empty heap + try: + _ = P.top() + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + try: + _ = P.top_item() + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + try: + _ = P.top_value() + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + # Or to get the value associated to an item that is not in the heap + try: + _ = P.value(123) + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + +def _test_PairingHeap_of_n_hashables(n=100): + r""" + Test :class:`~sage.data_structures.pairing_heap.PairingHeap_of_n_hashables`. + + INPUT: + + - ``n`` -- a strictly positive integer (default: 100); the maximum capacity + of the heap + + TESTS:: + + sage: from sage.data_structures.pairing_heap import _test_PairingHeap_of_n_hashables + sage: _test_PairingHeap_of_n_hashables(100) + """ + from sage.misc.prandom import randint, shuffle + + sig_on() + cdef PairingHeap_of_n_hashables P = PairingHeap_of_n_hashables(n) + sig_off() + + # Initialize a list of tuples (value, item) randomly ordered + cdef list items = [(str(i), i) for i in range(n)] + cdef list values = list(range(n)) + shuffle(items) + shuffle(values) + cdef list Lref = list(zip(values, items)) + + for value, item in Lref: + P.push(item, value) + sig_check() + + cdef list L = [] + while P: + item, value = P.top() + L.append((value, item)) + P.pop() + sig_check() + + if L != sorted(Lref): + raise ValueError('the order is not good') + + # Test decrease key operations. We first push items in the heap with an + # excess of k in the value. Then we decrease the keys in a random order by + # random values until returning to the original values. We finally check the + # validity of the resulting ordering. + cdef int k = 10 + cdef dict dec = {item: k for item in items} + shuffle(Lref) + for value, item in Lref: + P.push(item, value + k) + sig_check() + + L = list(items) + while L: + i = randint(0, len(L) - 1) + item = L[i] + d = randint(1, dec[item]) + dec[item] -= d + if not dec[item]: + L[i] = L[-1] + L.pop() + P.decrease(item, P.value(item) - d) + sig_check() + + L = [] + while P: + item, value = P.top() + L.append((value, item)) + P.pop() + sig_check() + + if L != sorted(Lref): + raise ValueError('the order is not good') + + # We finally show that an error is raised when trying to access the top of + # an empty heap + try: + _ = P.top() + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + try: + _ = P.top_item() + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + try: + _ = P.top_value() + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + # Or to get the value associated to an item that is not in the heap + try: + _ = P.value(123) + print("something goes wrong, the error has not been raised") + except ValueError as msg: + # The error has been properly handled + pass + + +def _compare_heaps(n=100, verbose=False): + r""" + Check that the heaps behave the same. + + This method selects a list of instructions: push items in some order, + decrease the values of the items in some order, extract all items in order. + Then it applies the same instructions to a ``PairingHeap``, a + :class:`PairingHeap_of_n_integers` and a + :class:`PairingHeap_of_n_hashables`. It checks that all heaps report the + list of items in the same order and it measures the running time. + + INPUT: + + - ``n`` -- a strictly positive integer (default: 100); the maximum capacity + of the heap + + - ``verbose`` -- boolean (default: ``False``); whether to display + information about the running times + + EXAMPLES:: + + sage: from sage.data_structures.pairing_heap import _compare_heaps + sage: _compare_heaps(n=100) + sage: _compare_heaps(n=100, verbose=True) # random + PairingHeap_of_n_integers: 7.800000000024454e-05 + PairingHeap_of_n_hashables: 9.400000000026054e-05 + PairingHeap (C++): 6.899999999987472e-05 + sage: _compare_heaps(1000000, verbose=True) # not tested (long time), random + PairingHeap_of_n_integers: 1.5106779999999995 + PairingHeap_of_n_hashables: 4.998040000000001 + PairingHeap (C++): 1.7841750000000012 + """ + from sage.misc.prandom import shuffle + from sage.misc.timing import cputime + + items = list(range(n)) + values = list(range(n)) + shuffle(items) + shuffle(values) + Lref = list(zip(values, items)) + k = 10 + dec_order = list(items) + shuffle(dec_order) + + t = cputime() + sig_on() + cdef PairingHeap_of_n_integers P = PairingHeap_of_n_integers(n) + sig_off() + for value, item in Lref: + P.push(item, value + k) + sig_check() + for item in dec_order: + P.decrease(item, P.value(item) - k) + sig_check() + LP = [] + while P: + LP.append(P.top()) + P.pop() + sig_check() + t = cputime(t) + if verbose: + print(f"PairingHeap_of_n_integers: {t}") + + t = cputime() + sig_on() + cdef PairingHeap_of_n_hashables Q = PairingHeap_of_n_hashables(n) + sig_off() + for value, item in Lref: + Q.push(item, value + k) + sig_check() + for item in dec_order: + Q.decrease(item, Q.value(item) - k) + sig_check() + LQ = [] + while Q: + LQ.append(Q.top()) + Q.pop() + sig_check() + t = cputime(t) + if verbose: + print(f"PairingHeap_of_n_hashables: {t}") + + t = cputime() + sig_on() + cdef PairingHeap[size_t, size_t] PH = PairingHeap[size_t, size_t]() + sig_off() + for value, item in Lref: + PH.push(item, value + k) + sig_check() + for item in dec_order: + PH.decrease(item, PH.value(item) - k) + sig_check() + LPH = [] + while not PH.empty(): + LPH.append(PH.top()) + PH.pop() + sig_check() + t = cputime(t) + if verbose: + print(f"PairingHeap (C++): {t}") + + if LPH != LP or LP != LQ: + print('something goes wrong') diff --git a/src/sage/data_structures/stream.py b/src/sage/data_structures/stream.py index ddca8fb26b2..eade622907f 100644 --- a/src/sage/data_structures/stream.py +++ b/src/sage/data_structures/stream.py @@ -3247,7 +3247,7 @@ def __init__(self, series, shift, minimal_valuation): true order at initialization:: sage: f = Stream_function(fun, True, 0) - sage: [f[i] for i in range(0, 10)] + sage: [f[i] for i in range(10)] [0, 1, 1, 0, 1, 0, 0, 0, 1, 0] sage: f._cache {1: 1, 2: 1, 3: 0, 4: 1, 5: 0, 6: 0, 7: 0, 8: 1, 9: 0} @@ -3257,7 +3257,7 @@ def __init__(self, series, shift, minimal_valuation): sage: s._approximate_order 3 sage: f = Stream_function(fun, False, 0) - sage: [f[i] for i in range(0, 10)] + sage: [f[i] for i in range(10)] [0, 1, 1, 0, 1, 0, 0, 0, 1, 0] sage: f._cache [1, 1, 0, 1, 0, 0, 0, 1, 0] @@ -3432,7 +3432,7 @@ def is_nonzero(self): sage: from sage.data_structures.stream import Stream_function, Stream_truncated sage: def fun(n): return 1 if ZZ(n).is_power_of(2) else 0 sage: f = Stream_function(fun, False, 0) - sage: [f[i] for i in range(0, 4)] + sage: [f[i] for i in range(4)] [0, 1, 1, 0] sage: f._cache [1, 1, 0] @@ -3445,7 +3445,7 @@ def is_nonzero(self): True sage: f = Stream_function(fun, True, 0) - sage: [f[i] for i in range(0, 4)] + sage: [f[i] for i in range(4)] [0, 1, 1, 0] sage: f._cache {1: 1, 2: 1, 3: 0} diff --git a/src/sage/databases/cremona.py b/src/sage/databases/cremona.py index ca859214155..9b881ed70ea 100644 --- a/src/sage/databases/cremona.py +++ b/src/sage/databases/cremona.py @@ -1682,21 +1682,40 @@ def CremonaDatabase(name=None, mini=None, set_global=None): FeatureNotPresentError: database_should_not_exist_ellcurve is not available. '...db' not found in any of [...] ...Further installation instructions might be available at https://github.com/JohnCremona/ecdata. + + Verify that :issue:`39072` has been resolved:: + + sage: C = CremonaDatabase(mini=False) # optional - !database_cremona_ellcurve + Traceback (most recent call last): + ... + ValueError: the full Cremona database is not available; consider using the mini Cremona database by setting mini=True """ if set_global is not None: from sage.misc.superseded import deprecation deprecation(25825, "the set_global argument for CremonaDatabase is deprecated and ignored") + if name is None: - if DatabaseCremona().is_present(): - name = 'cremona' - else: + if mini is None: + if DatabaseCremona().is_present(): + name = 'cremona' + mini = False + else: + name = 'cremona mini' + mini = True + elif mini: name = 'cremona mini' - if name == 'cremona': - mini = False + else: + if not DatabaseCremona().is_present(): + raise ValueError('the full Cremona database is not available; ' + 'consider using the mini Cremona database by setting mini=True') + name = 'cremona' elif name == 'cremona mini': mini = True - if mini is None: - raise ValueError('mini must be set as either True or False') + elif name == 'cremona': + mini = False + else: + if mini is None: + raise ValueError('the mini option must be set to True or False') if mini: return MiniCremonaDatabase(name) diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 668af9abacc..3c75faf88ca 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -729,7 +729,7 @@ def __init__(self, num_strands): def _warn_incompatibility(self, fname): """ - Warn the user that he has an incomaptible file cache under `Sage_DOT` + Warn the user that he has an incomaptible file cache under ``Sage_DOT`` and move it away to another file (marked with timestamp). EXAMPLES:: @@ -1153,7 +1153,6 @@ def update_basis_extensions(self, new_basis_extensions): """ self._data_library.update({self.section.basis_extensions: new_basis_extensions}) self.write(self.section.basis_extensions) - return # ----------------------------------------------------------------------------- diff --git a/src/sage/databases/db_class_polynomials.py b/src/sage/databases/db_class_polynomials.py index 57acde7c05a..4362df56837 100644 --- a/src/sage/databases/db_class_polynomials.py +++ b/src/sage/databases/db_class_polynomials.py @@ -30,8 +30,8 @@ from .db_modular_polynomials import _dbz_to_integers -disc_format = "%07d" # disc_length = 7 -level_format = "%03d" # level_length = 3 +disc_format = "%07d" # disc_length = 7 +level_format = "%03d" # level_length = 3 class ClassPolynomialDatabase: @@ -52,7 +52,7 @@ def _dbpath(self, disc, level=1): if level != 1: raise NotImplementedError("Level (= %s) > 1 not yet implemented" % level) n1 = 5000*((abs(disc)-1)//5000) - s1 = disc_format % (n1+1) #_pad_int(n1+1, disc_length) + s1 = disc_format % (n1+1) # _pad_int(n1+1, disc_length) s2 = disc_format % (n1+5000) subdir = "%s-%s" % (s1, s2) discstr = disc_format % abs(disc) diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 1285569805e..0822a92c168 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -213,6 +213,7 @@ def mapping(sigma): from ast import literal_eval from copy import deepcopy +from pathlib import Path import re import webbrowser import tempfile @@ -491,8 +492,9 @@ def _submit(args, url): ....: "CurrentEmail": ""} sage: _submit(args, url) # optional -- webbrowser """ - f = tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False) + f = tempfile.NamedTemporaryFile(mode='w', suffix='.html', encoding='utf-8', delete=False) verbose("Created temporary file %s" % f.name, caller_name='FindStat') + f.write('\n\n\n') f.write(FINDSTAT_POST_HEADER) f.write(url) for key, value in args.items(): @@ -506,7 +508,7 @@ def _submit(args, url): f.write(FINDSTAT_FORM_FOOTER) f.close() verbose("Opening file with webbrowser", caller_name='FindStat') - webbrowser.open(f.name) + webbrowser.open(Path(f.name).as_uri()) def _data_to_str(data, domain, codomain=None): diff --git a/src/sage/doctest/control.py b/src/sage/doctest/control.py index fff35be8307..49df68fe66e 100644 --- a/src/sage/doctest/control.py +++ b/src/sage/doctest/control.py @@ -59,6 +59,7 @@ auto_optional_tags = set() + class DocTestDefaults(SageObject): """ This class is used for doctesting the Sage doctest module. @@ -1350,12 +1351,12 @@ def run_val_gdb(self, testing=False): opt = self.options if opt.gdb: - cmd = f'''exec gdb --eval-command="run" --args ''' + cmd = '''exec gdb --eval-command="run" --args ''' flags = "" if opt.logfile: sage_cmd += f" --logfile {shlex.quote(opt.logfile)}" elif opt.lldb: - cmd = f'''exec lldb --one-line "process launch" --one-line "cont" -- ''' + cmd = '''exec lldb --one-line "process launch" --one-line "cont" -- ''' flags = "" else: if opt.logfile is None: diff --git a/src/sage/doctest/external.py b/src/sage/doctest/external.py index bf0309d3131..45b3987de05 100644 --- a/src/sage/doctest/external.py +++ b/src/sage/doctest/external.py @@ -45,6 +45,7 @@ # software xxx is available to Sage. prefix = 'has_' + def has_internet(): """ Test if Internet is available. @@ -61,6 +62,7 @@ def has_internet(): from sage.features.internet import Internet return Internet().is_present() + def has_latex(): """ Test if Latex is available. @@ -74,6 +76,7 @@ def has_latex(): from sage.features.latex import latex return latex().is_present() + def has_xelatex(): """ Test if xelatex is available. @@ -87,6 +90,7 @@ def has_xelatex(): from sage.features.latex import xelatex return xelatex().is_present() + def has_pdflatex(): """ Test if pdflatex is available. @@ -100,6 +104,7 @@ def has_pdflatex(): from sage.features.latex import pdflatex return pdflatex().is_present() + def has_lualatex(): """ Test if lualatex is available. @@ -113,6 +118,7 @@ def has_lualatex(): from sage.features.latex import lualatex return lualatex().is_present() + def has_magma(): """ Test if Magma is available. @@ -126,6 +132,7 @@ def has_magma(): from sage.features.interfaces import Magma return Magma().is_present() + def has_matlab(): """ Test if Matlab is available. @@ -139,6 +146,7 @@ def has_matlab(): from sage.features.interfaces import Matlab return Matlab().is_present() + def has_mathematica(): """ Test if Mathematica is available. @@ -152,6 +160,7 @@ def has_mathematica(): from sage.features.interfaces import Mathematica return Mathematica().is_present() + def has_maple(): """ Test if Maple is available. @@ -165,6 +174,7 @@ def has_maple(): from sage.features.interfaces import Maple return Maple().is_present() + def has_macaulay2(): """ Test if Macaulay2 is available. @@ -178,6 +188,7 @@ def has_macaulay2(): from sage.features.interfaces import Macaulay2 return Macaulay2().is_present() + def has_octave(): """ Test if Octave is available. @@ -191,6 +202,7 @@ def has_octave(): from sage.features.interfaces import Octave return Octave().is_present() + def has_pandoc(): """ Test if pandoc is available. @@ -204,6 +216,7 @@ def has_pandoc(): from sage.features.pandoc import Pandoc return Pandoc().is_present() + def has_scilab(): """ Test if Scilab is available. @@ -221,6 +234,7 @@ def has_scilab(): except Exception: return False + def has_cplex(): """ Test if CPLEX is available. @@ -234,6 +248,7 @@ def has_cplex(): from sage.features.mip_backends import CPLEX return CPLEX().is_present() + def has_gurobi(): """ Test if Gurobi is available. @@ -247,6 +262,7 @@ def has_gurobi(): from sage.features.mip_backends import Gurobi return Gurobi().is_present() + def has_graphviz(): """ Test if graphviz (dot, twopi, neato) are available. @@ -260,6 +276,7 @@ def has_graphviz(): from sage.features.graphviz import Graphviz return Graphviz().is_present() + def has_ffmpeg(): """ Test if ffmpeg is available. @@ -273,6 +290,7 @@ def has_ffmpeg(): from sage.features.ffmpeg import FFmpeg return FFmpeg().is_present() + def has_imagemagick(): """ Test if ImageMagick (command magick or convert) is available. @@ -286,6 +304,7 @@ def has_imagemagick(): from sage.features.imagemagick import ImageMagick return ImageMagick().is_present() + def has_dvipng(): """ Test if dvipng is available. @@ -299,6 +318,7 @@ def has_dvipng(): from sage.features.dvipng import dvipng return dvipng().is_present() + def has_pdf2svg(): """ Test if pdf2svg is available. @@ -312,6 +332,7 @@ def has_pdf2svg(): from sage.features.pdf2svg import pdf2svg return pdf2svg().is_present() + def has_rubiks(): """ Test if the rubiks package (``cu2``, ``cubex``, ``dikcube``, @@ -326,6 +347,7 @@ def has_rubiks(): from sage.features.rubiks import Rubiks return Rubiks().is_present() + def has_4ti2(): """ Test if the 4ti2 package is available. @@ -339,6 +361,7 @@ def has_4ti2(): from sage.features.four_ti_2 import FourTi2 return FourTi2().is_present() + def external_features(): r""" Generate the features that are only to be tested if ``--optional=external`` is used. @@ -363,6 +386,7 @@ def external_features(): yield CPLEX() yield Gurobi() + def external_software() -> list[str]: """ Return the alphabetical list of external software supported by this module. diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index bf6d49906de..962c21e12cd 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -45,38 +45,48 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from __future__ import annotations - +import doctest +import errno +import gc +import hashlib +import linecache +import multiprocessing import os import platform +import re +import signal import sys +import tempfile import time -import signal -import linecache -import hashlib -import multiprocessing -import warnings -import re -import errno -import doctest import traceback -import tempfile +import typing +import warnings from collections import defaultdict from dis import findlinestarts from queue import Empty -import gc + import IPython.lib.pretty -import sage.misc.randstate as randstate -from sage.misc.timing import walltime -from .util import Timer, RecordingDict, count_noun -from .sources import DictAsObject -from .parsing import OriginalSource, reduce_hex -from sage.structure.sage_object import SageObject -from .parsing import SageOutputChecker, pre_hash, get_source, unparse_optional_tags -from sage.repl.user_globals import set_globals from sage.cpython.atexit import restore_atexit from sage.cpython.string import bytes_to_str, str_to_bytes +from sage.doctest.parsing import ( + OriginalSource, + SageOutputChecker, + get_source, + pre_hash, + reduce_hex, + unparse_optional_tags, +) +from sage.doctest.sources import DictAsObject +from sage.doctest.util import RecordingDict, Timer, count_noun +from sage.misc import randstate +from sage.repl.user_globals import set_globals +from sage.structure.sage_object import SageObject + +if typing.TYPE_CHECKING: + from sage.doctest.control import DocTestController # With OS X, Python 3.8 defaults to use 'spawn' instead of 'fork' in # multiprocessing, and Sage doctesting doesn't work with 'spawn'. See @@ -113,7 +123,7 @@ def inner(obj, p, cycle): return inner -def init_sage(controller=None): +def init_sage(controller: DocTestController | None = None) -> None: """ Import the Sage library. @@ -553,6 +563,8 @@ def __init__(self, *args, **kwds): self.total_walltime_skips = 0 self.total_performed_tests = 0 self.total_walltime = 0 + if sys.version_info < (3,13): + self._stats = self._name2ft def _run(self, test, compileflags, out): """ @@ -830,7 +842,10 @@ def compiler(example): self.optionflags = original_optionflags # Record and return the number of failures and tries. - self._DocTestRunner__record_outcome(test, failures, tries) + if sys.version_info < (3,13): + self._DocTestRunner__record_outcome(test, failures, tries) + else: + self._DocTestRunner__record_outcome(test, failures, tries, walltime_skips) self.total_walltime_skips += walltime_skips self.total_performed_tests += tries return TestResults(failures, tries) @@ -931,7 +946,7 @@ def summarize(self, verbose=None): sage: from sage.doctest.control import DocTestDefaults; DD = DocTestDefaults() sage: import doctest, sys, os sage: DTR = SageDocTestRunner(SageOutputChecker(), verbose=False, sage_options=DD, optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS) - sage: DTR._name2ft['sage.doctest.forker'] = (1,120) + sage: DTR._stats['sage.doctest.forker'] = (1,120) sage: results = DTR.summarize() ********************************************************************** 1 item had failures: @@ -946,8 +961,8 @@ def summarize(self, verbose=None): passed = [] failed = [] totalt = totalf = 0 - for x in self._name2ft.items(): - name, (f, t) = x + for x in self._stats.items(): + name, (f, t, *_) = x assert f <= t totalt += t totalf += f @@ -972,10 +987,10 @@ def summarize(self, verbose=None): print(self.DIVIDER, file=m) print(count_noun(len(failed), "item"), "had failures:", file=m) failed.sort() - for thing, (f, t) in failed: + for thing, (f, t, *_) in failed: print(" %3d of %3d in %s" % (f, t, thing), file=m) if verbose: - print(count_noun(totalt, "test") + " in " + count_noun(len(self._name2ft), "item") + ".", file=m) + print(count_noun(totalt, "test") + " in " + count_noun(len(self._stats), "item") + ".", file=m) print("%s passed and %s failed." % (totalt - totalf, totalf), file=m) if totalf: print("***Test Failed***", file=m) @@ -1710,7 +1725,7 @@ class DocTestDispatcher(SageObject): Create parallel :class:`DocTestWorker` processes and dispatches doctesting tasks. """ - def __init__(self, controller): + def __init__(self, controller: DocTestController): """ INPUT: diff --git a/src/sage/doctest/reporting.py b/src/sage/doctest/reporting.py index e6bfd52bf33..54742cd6c1e 100644 --- a/src/sage/doctest/reporting.py +++ b/src/sage/doctest/reporting.py @@ -50,6 +50,7 @@ from sage.doctest.sources import DictAsObject from .external import available_software + def signal_name(sig): """ Return a string describing a signal number. @@ -91,6 +92,7 @@ def signal_name(sig): return "bus error" return "signal %s" % sig + class DocTestReporter(SageObject): """ This class reports to the users on the results of doctests. diff --git a/src/sage/doctest/util.py b/src/sage/doctest/util.py index ed831598e65..e17df277c1f 100644 --- a/src/sage/doctest/util.py +++ b/src/sage/doctest/util.py @@ -26,6 +26,7 @@ from time import time as walltime from os import sysconf, times + def count_noun(number, noun, plural=None, pad_number=False, pad_noun=False): """ EXAMPLES:: @@ -614,6 +615,7 @@ def make_recording_dict(D, st, gt): ans.got = gt return ans + class NestedName: """ Class used to construct fully qualified names based on indentation level. diff --git a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py index ecf61822ba9..c9d9a0e5403 100644 --- a/src/sage/dynamics/arithmetic_dynamics/affine_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/affine_ds.py @@ -800,7 +800,7 @@ def multiplier(self, P, n, check=True): l = identity_matrix(FractionField(self.codomain().base_ring()), N, N) Q = P J = self.jacobian() - for i in range(0, n): + for i in range(n): R = self(Q) l = J(tuple(Q)) * l # chain rule matrix multiplication Q = R diff --git a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py index 902f83b55ae..ccd2041d1ca 100644 --- a/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py +++ b/src/sage/dynamics/arithmetic_dynamics/endPN_minimal_model.py @@ -66,12 +66,13 @@ def bCheck(c, v, p, b): sage: bCheck(11664*b^2 + 70227*b + 76059, 15/2, 3, b) -1 """ - val = (v+1).floor() + val = (v + 1).floor() deg = c.degree() coeffs = c.coefficients(sparse=False) lcoeff = coeffs[deg] coeffs.remove(lcoeff) - check1 = [(coeffs[i].valuation(p) - lcoeff.valuation(p))/(deg - i) for i in range(0,len(coeffs)) if coeffs[i] != 0] + check1 = [(coeffs[i].valuation(p) - lcoeff.valuation(p))/(deg - i) + for i in range(len(coeffs)) if coeffs[i] != 0] check2 = (val - lcoeff.valuation(p))/deg check1.append(check2) bval = min(check1) diff --git a/src/sage/dynamics/arithmetic_dynamics/generic_ds.py b/src/sage/dynamics/arithmetic_dynamics/generic_ds.py index f16d99cbb11..67ca0c97e8d 100644 --- a/src/sage/dynamics/arithmetic_dynamics/generic_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/generic_ds.py @@ -165,7 +165,8 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): if isinstance(morphism_or_polys, SchemeMorphism_polynomial): domain = morphism_or_polys.domain() if domain is not None: - if isinstance(domain, AffineSpace_generic) or isinstance(domain, AlgebraicScheme_subscheme_affine): + if isinstance(domain, (AffineSpace_generic, + AlgebraicScheme_subscheme_affine)): from sage.dynamics.arithmetic_dynamics.affine_ds import DynamicalSystem_affine return DynamicalSystem_affine(morphism_or_polys, domain) if isinstance(domain, Berkovich_Cp): diff --git a/src/sage/dynamics/arithmetic_dynamics/meson.build b/src/sage/dynamics/arithmetic_dynamics/meson.build index 9e26a72c874..7ba8b8b4068 100644 --- a/src/sage/dynamics/arithmetic_dynamics/meson.build +++ b/src/sage/dynamics/arithmetic_dynamics/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'affine_ds.py', 'all.py', 'berkovich_ds.py', diff --git a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py index 2fab95104f1..591693e5af8 100644 --- a/src/sage/dynamics/arithmetic_dynamics/projective_ds.py +++ b/src/sage/dynamics/arithmetic_dynamics/projective_ds.py @@ -95,7 +95,7 @@ class initialization directly. from sage.rings.morphism import RingHomomorphism_im_gens from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.quotient_ring import QuotientRing_generic from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RealField @@ -385,7 +385,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): polys = list(morphism_or_polys) if len(polys) == 1: raise ValueError("list/tuple must have at least 2 polynomials") - test = lambda x: isinstance(x, PolynomialRing_general) or isinstance(x, MPolynomialRing_base) + test = lambda x: isinstance(x, (PolynomialRing_generic, MPolynomialRing_base)) if not all(test(poly.parent()) for poly in polys): try: polys = [poly.lift() for poly in polys] @@ -395,7 +395,7 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): # homogenize! f = morphism_or_polys aff_CR = f.parent() - if (not isinstance(aff_CR, PolynomialRing_general) and not isinstance(aff_CR, FractionField_generic) + if (not isinstance(aff_CR, (PolynomialRing_generic, FractionField_generic)) and not (isinstance(aff_CR, MPolynomialRing_base) and aff_CR.ngens() == 1)): msg = '{} is not a single variable polynomial or rational function' raise ValueError(msg.format(f)) @@ -450,7 +450,8 @@ def __classcall_private__(cls, morphism_or_polys, domain=None, names=None): msg = 'polys (={}) must be of the same degree' raise ValueError(msg.format(polys)) - if not isinstance(domain, ProjectiveSpace_ring) and not isinstance(domain, AlgebraicScheme_subscheme_projective): + if not isinstance(domain, (ProjectiveSpace_ring, + AlgebraicScheme_subscheme_projective)): raise ValueError('"domain" must be a projective scheme') if R not in Fields(): return typecall(cls, polys, domain) @@ -2042,7 +2043,7 @@ def green_function(self, P, v, **kwds): sage: f.green_function(P([2, 1]), K.ideal(7), N=7) 0.48647753726382832627633818586 sage: f.green_function(P([w, 1]), K.ideal(17), error_bound=0.001) - -0.70813041039490996737374178059 + -0.70821687320448199545278619351 :: @@ -2073,7 +2074,7 @@ def green_function(self, P, v, **kwds): K = BR elif is_prime(v): K = Qp(v, prec) - elif v == 0: + elif v == 0 and BR == QQ: K = R v = BR.places(prec=prec)[0] else: @@ -2095,6 +2096,7 @@ def green_function(self, P, v, **kwds): # compute upper bound if isinstance(v, RingHomomorphism_im_gens): #archimedean vindex = BR.places(prec=prec).index(v) + emb = BR.places(prec=prec)[vindex] U = GBR.local_height_arch(vindex, prec=prec) + R(binomial(dim + d, d)).log() else: #non-archimedean U = GBR.local_height(v, prec=prec) @@ -2103,30 +2105,31 @@ def green_function(self, P, v, **kwds): CR = GBR.codomain().ambient_space().coordinate_ring() #.lift() only works over fields I = CR.ideal(GBR.defining_polynomials()) maxh = 0 - Res = 1 for k in range(dim + 1): CoeffPolys = (CR.gen(k) ** D).lift(I) h = 1 - for poly in CoeffPolys: - if poly != 0: - for c in poly.coefficients(): - Res = lcm(Res, c.denominator()) for poly in CoeffPolys: if poly != 0: if isinstance(v, RingHomomorphism_im_gens): #archimedean if BR == QQ: - h = max([(Res*c).local_height_arch(prec=prec) for c in poly.coefficients()]) + h = max([R(K(c).abs()) for c in poly.coefficients()]) else: - h = max([(Res*c).local_height_arch(vindex, prec=prec) for c in poly.coefficients()]) + h = max([R(emb(c).abs()) for c in poly.coefficients()]) else: #non-archimedean - h = max([c.local_height(v, prec=prec) for c in poly.coefficients()]) + if BR == QQ: + h = max([R(v)**(-R(c.valuation(v))) for c in poly.coefficients()]) + else: + h = max([R(c.abs_non_arch(v, prec=prec)) for c in poly.coefficients()]) maxh = max(h, maxh) if maxh == 0: maxh = 1 #avoid division by 0 if isinstance(v, RingHomomorphism_im_gens): #archimedean - L = R(Res / ((dim + 1) * binomial(dim + D - d, D - d) * maxh)).log().abs() + L = R(1 / ((dim + 1) * binomial(dim + D - d, D - d) * maxh)).log().abs() else: #non-archimedean - L = R(Res / maxh).log().abs() + if BR == QQ: + L = ((-self.resultant().valuation(v))*R(v).log()).abs() + else: + L = (self.resultant().abs_non_arch(v, prec=prec)).log().abs() C = max([U, L]) if C != 0: N = R(C / (err*(d-1))).log(d).abs().ceil() @@ -2252,7 +2255,7 @@ def canonical_height(self, P, **kwds): sage: f = DynamicalSystem_projective([1000*x^2 - 29*y^2, 1000*y^2]) sage: Q = P(-1/4, 1) sage: f.canonical_height(Q, error_bound=0.01) # needs sage.libs.pari - 3.7996079979254623065837411853 + 3.7979215342343045582800170705 :: @@ -3530,7 +3533,9 @@ def affine_preperiodic_model(self, m, n, return_conjugation=False): if hyperplane_found: break else: - if isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base) or isinstance(R, FractionField_generic): + if isinstance(R, (PolynomialRing_generic, + MPolynomialRing_base, + FractionField_generic)): # for polynomial rings, we can get an infinite family of hyperplanes # by increasing the degree var = R.gen() @@ -4592,7 +4597,8 @@ def preperiodic_points(self, m, n, **kwds): for k in ZZ(n).divisors(): if ZZ(n/k).is_prime(): Sn.append(k) - if (isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base)): + if isinstance(R, (PolynomialRing_generic, + MPolynomialRing_base)): phi = FlatteningMorphism(CR) flatCR = phi.codomain() Ik = flatCR.ideal(1) @@ -4946,9 +4952,10 @@ def periodic_points(self, n, minimal=True, formal=False, R=None, algorithm='vari elif minimal: Sn = [] for k in ZZ(n).divisors(): - if ZZ(n/k).is_prime(): + if ZZ(n//k).is_prime(): Sn.append(k) - if (isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base)): + if isinstance(R, (PolynomialRing_generic, + MPolynomialRing_base)): phi = FlatteningMorphism(CR) flatCR = phi.codomain() Ik = flatCR.ideal(1) @@ -5239,7 +5246,8 @@ def multiplier_spectra(self, n, formal=False, type='point', use_algebraic_closur # 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 isinstance(K, sage.rings.abc.AlgebraicField) or isinstance(K, AlgebraicClosureFiniteField_generic): + if isinstance(K, (sage.rings.abc.AlgebraicField, + AlgebraicClosureFiniteField_generic)): f = self.reduce_base_field() K = f.base_ring() use_algebraic_closure = True @@ -5780,7 +5788,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', else: F = base_ring if isinstance(base_ring, FractionField_generic): - if isinstance(base_ring.ring(), MPolynomialRing_base) or isinstance(base_ring.ring(), PolynomialRing_general): + if isinstance(base_ring.ring(), (MPolynomialRing_base, + PolynomialRing_generic)): f.normalize_coordinates() f_ring = f.change_ring(base_ring.ring()) X = f_ring.periodic_points(n, minimal=False, formal=formal, return_scheme=True) @@ -5883,7 +5892,8 @@ def sigma_invariants(self, n, formal=False, embedding=None, type='point', base_ring = dom.base_ring() if isinstance(base_ring, FractionField_generic): base_ring = base_ring.ring() - if (isinstance(base_ring, PolynomialRing_general) or isinstance(base_ring, MPolynomialRing_base)): + if isinstance(base_ring, (PolynomialRing_generic, + MPolynomialRing_base)): base_ring = base_ring.base_ring() elif base_ring in FunctionFields(): base_ring = base_ring.constant_base_field() @@ -6837,10 +6847,10 @@ def Lattes_to_curve(self, return_conjugation=False, check_lattes=False): INPUT: - `return_conjugation`` -- (default: ``False``) if ``True``, then + ``return_conjugation`` -- (default: ``False``) if ``True``, then return the conjugation that moves self to a map that comes from a Short Weierstrass Model Elliptic curve - `check_lattes``.-.(default:.``False``) if ``True``, then will ValueError if not Lattes + ``check_lattes``.-.(default:.``False``) if ``True``, then will ValueError if not Lattes OUTPUT: a Short Weierstrass Model Elliptic curve which is isogenous to the Elliptic curve of 'self', diff --git a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py index 766dff990e0..0a1a5ba1526 100644 --- a/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py +++ b/src/sage/dynamics/arithmetic_dynamics/wehlerK3.py @@ -1200,7 +1200,7 @@ def sigmaX(self, P, **kwds): e = min(maxexp) #Fix L and Q - for i in range(0,2): + for i in range(2): while T[i].subs({w1:t1}) == 0: T[i] = T[i]/t T[i] = T[i].subs({w1:t1}) @@ -1435,7 +1435,8 @@ def sigmaY(self, P, **kwds): -phi(self.Hpoly(0, 1, 2))] maxexp = [] - #Find highest exponent that we can divide out by to get a nonzero answer + # Find highest exponent that we can divide out by to get a + # nonzero answer for i in range(2, len(T)): e = 0 while (T[i]/t**e).subs({w1:t1}) == 0: @@ -1444,7 +1445,7 @@ def sigmaY(self, P, **kwds): e = min(maxexp) - for i in range(0, 2): + for i in range(2): while T[i].subs({w1:t1}) == 0: T[i] = T[i]/t T[i] = T[i].subs({w1:t1}) diff --git a/src/sage/dynamics/complex_dynamics/meson.build b/src/sage/dynamics/complex_dynamics/meson.build index d3961275d3e..ccde4866dd1 100644 --- a/src/sage/dynamics/complex_dynamics/meson.build +++ b/src/sage/dynamics/complex_dynamics/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'mandel_julia.py', subdir: 'sage/dynamics/complex_dynamics', diff --git a/src/sage/dynamics/finite_dynamical_system_catalog.py b/src/sage/dynamics/finite_dynamical_system_catalog.py old mode 100755 new mode 100644 diff --git a/src/sage/dynamics/meson.build b/src/sage/dynamics/meson.build index 134cfd1a296..9ba62964e6c 100644 --- a/src/sage/dynamics/meson.build +++ b/src/sage/dynamics/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'finite_dynamical_system.py', 'finite_dynamical_system_catalog.py', diff --git a/src/sage/env.py b/src/sage/env.py index 0cfe6dfe8c4..060eb2209a9 100644 --- a/src/sage/env.py +++ b/src/sage/env.py @@ -2,16 +2,21 @@ r""" Sage Runtime Environment -Verify that importing ``sage.all`` works in Sage's Python without any ``SAGE_`` -environment variables, and has the same ``SAGE_ROOT`` and ``SAGE_LOCAL`` -(see also :issue:`29446`):: +Verify that importing ``sage.all`` works in Sage's Python without any +``SAGE_`` environment variables, and has the same ``SAGE_ROOT`` and +``SAGE_LOCAL`` (see also :issue:`29446`). If ``SAGE_ROOT`` is a path, +we normalize it, but keep in mind that ``SAGE_ROOT`` may also be +``None``:: sage: env = {k:v for (k,v) in os.environ.items() if not k.startswith("SAGE_")} sage: from subprocess import check_output sage: module_name = "sage.all" # hide .all import from the linter sage: cmd = f"from {module_name} import SAGE_ROOT, SAGE_LOCAL;" sage: cmd += "from os.path import samefile;" - sage: cmd += f"s1 = samefile(SAGE_ROOT, '{SAGE_ROOT}') if SAGE_ROOT else True;" + sage: if SAGE_ROOT is None: + ....: cmd += "s1 = SAGE_ROOT is None;" + ....: else: + ....: cmd += f"s1 = samefile(SAGE_ROOT, '{SAGE_ROOT}');" sage: cmd += f"s2 = samefile(SAGE_LOCAL, '{SAGE_LOCAL}');" sage: cmd += "print(s1 and s2);" sage: out = check_output([sys.executable, "-c", cmd], env=env).decode().strip() # long time diff --git a/src/sage/ext/fast_callable.pyx b/src/sage/ext/fast_callable.pyx index 89c34b1f0fc..477f8608ef7 100644 --- a/src/sage/ext/fast_callable.pyx +++ b/src/sage/ext/fast_callable.pyx @@ -475,10 +475,11 @@ def fast_callable(x, domain=None, vars=None, x = x.function(*vars) if vars is None: - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base - if isinstance(x.parent(), PolynomialRing_general) or isinstance(x.parent(), MPolynomialRing_base): - vars = x.parent().variable_names() + P = x.parent() + if isinstance(P, (PolynomialRing_generic, MPolynomialRing_base)): + vars = P.variable_names() else: # constant vars = () diff --git a/src/sage/ext/meson.build b/src/sage/ext/meson.build index 73d0e85101d..dc3026cec34 100644 --- a/src/sage/ext/meson.build +++ b/src/sage/ext/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all__sagemath_objects.py', 'ccobject.h', 'cplusplus.pxd', diff --git a/src/sage/ext_data/valgrind/pyalloc.supp b/src/sage/ext_data/valgrind/pyalloc.supp index 35ebe0ce1a3..542ab3e5a0f 100644 --- a/src/sage/ext_data/valgrind/pyalloc.supp +++ b/src/sage/ext_data/valgrind/pyalloc.supp @@ -1,4 +1,4 @@ -# Read Misc/README.valgrind in the Python sourcs for a thorough explanation +# Read Misc/README.valgrind in the Python sources for a thorough explanation # # In short: We need these unless we compile python without pyalloc, # but that would be prohibitively slow. diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index e02015a5710..ac4a0bcd97f 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -418,6 +418,7 @@ def is_hidden(self): return True return False + class FeatureNotPresentError(RuntimeError): r""" A missing feature error. diff --git a/src/sage/features/databases.py b/src/sage/features/databases.py index 9d070d932ed..2394d4d6c05 100644 --- a/src/sage/features/databases.py +++ b/src/sage/features/databases.py @@ -25,7 +25,7 @@ def sage_data_path(data_name): r""" - Search path for database `data_name`. + Search path for database ``data_name``. EXAMPLES:: diff --git a/src/sage/features/dvipng.py b/src/sage/features/dvipng.py index 68bcdcb5a04..4ae0c7a01cf 100644 --- a/src/sage/features/dvipng.py +++ b/src/sage/features/dvipng.py @@ -14,6 +14,7 @@ from . import Executable + class dvipng(Executable): r""" A :class:`~sage.features.Feature` describing the presence of ``dvipng``. diff --git a/src/sage/features/ffmpeg.py b/src/sage/features/ffmpeg.py index 0d3ff8e4232..c33e36062a1 100644 --- a/src/sage/features/ffmpeg.py +++ b/src/sage/features/ffmpeg.py @@ -14,6 +14,7 @@ from . import Executable, FeatureTestResult + class FFmpeg(Executable): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`ffmpeg `. @@ -75,19 +76,19 @@ def is_functional(self): # The `-nostdin` is needed to avoid the command to hang, see # https://stackoverflow.com/questions/16523746/ffmpeg-hangs-when-run-in-background commands = [] - for ext in ['.avi', '.flv', '.gif', '.mkv', '.mov', #'.mpg', - '.mp4', '.ogg', '.ogv', '.webm', '.wmv']: + for ext in ['.avi', '.flv', '.gif', '.mkv', '.mov', + '.mp4', '.ogg', '.ogv', '.webm', '.wmv']: cmd = ['ffmpeg', '-nostdin', '-y', '-f', 'image2', '-r', '5', - '-i', filename_png, '-pix_fmt', 'rgb24', '-loop', '0', - filename + ext] + '-i', filename_png, '-pix_fmt', 'rgb24', '-loop', '0', + filename + ext] commands.append(cmd) for ext in ['.avi', '.flv', '.gif', '.mkv', '.mov', '.mpg', - '.mp4', '.ogg', '.ogv', '.webm', '.wmv']: + '.mp4', '.ogg', '.ogv', '.webm', '.wmv']: cmd = ['ffmpeg', '-nostdin', '-y', '-f', 'image2', '-i', - filename_png, filename + ext] + filename_png, filename + ext] commands.append(cmd) # Running the commands and reporting any issue encountered diff --git a/src/sage/features/fricas.py b/src/sage/features/fricas.py index 539b3b027dd..15c346248ae 100644 --- a/src/sage/features/fricas.py +++ b/src/sage/features/fricas.py @@ -16,6 +16,7 @@ import subprocess from . import Executable, FeatureTestResult + class FriCAS(Executable): r""" A :class:`~sage.features.Feature` which checks for the :ref:`fricas ` binary. @@ -62,5 +63,6 @@ def is_functional(self): return FeatureTestResult(self, True) + def all_features(): return [FriCAS()] diff --git a/src/sage/features/gap.py b/src/sage/features/gap.py index 609cb37c263..6a6f20b30a8 100644 --- a/src/sage/features/gap.py +++ b/src/sage/features/gap.py @@ -16,6 +16,7 @@ from .join_feature import JoinFeature from .sagemath import sage__libs__gap + class GapPackage(Feature): r""" A :class:`~sage.features.Feature` describing the presence of a GAP package. diff --git a/src/sage/features/giac.py b/src/sage/features/giac.py index 6f9fe2ccfba..67403a332be 100644 --- a/src/sage/features/giac.py +++ b/src/sage/features/giac.py @@ -5,6 +5,7 @@ from . import Executable, FeatureTestResult + class Giac(Executable): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`giac `. @@ -26,5 +27,6 @@ def __init__(self): Executable.__init__(self, 'giac', executable='giac', spkg='giac', type='standard') + def all_features(): return [Giac()] diff --git a/src/sage/features/igraph.py b/src/sage/features/igraph.py index 9bb61c28454..bd349ec730d 100644 --- a/src/sage/features/igraph.py +++ b/src/sage/features/igraph.py @@ -40,5 +40,6 @@ def __init__(self): [PythonModule('igraph', spkg='python_igraph', url='http://igraph.org')]) + def all_features(): return [python_igraph()] diff --git a/src/sage/features/imagemagick.py b/src/sage/features/imagemagick.py index 866d0aed95e..fa63616b596 100644 --- a/src/sage/features/imagemagick.py +++ b/src/sage/features/imagemagick.py @@ -21,6 +21,7 @@ from . import Executable, FeatureTestResult from .join_feature import JoinFeature + class Magick(Executable): r""" A :class:`~sage.features.Feature` describing the presence of ``magick`` or the deprecated ``convert``. @@ -134,5 +135,6 @@ def __init__(self): spkg='imagemagick', url='https://www.imagemagick.org/') + def all_features(): return [ImageMagick()] diff --git a/src/sage/features/info.py b/src/sage/features/info.py index eeaf0118c0d..22580a42c00 100644 --- a/src/sage/features/info.py +++ b/src/sage/features/info.py @@ -5,6 +5,7 @@ from . import Executable + class Info(Executable): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`info `. @@ -26,5 +27,6 @@ def __init__(self): Executable.__init__(self, 'info', executable='info', spkg='info', type='standard') + def all_features(): return [Info()] diff --git a/src/sage/features/kenzo.py b/src/sage/features/kenzo.py index b5d83b06972..3d2efaf50d6 100644 --- a/src/sage/features/kenzo.py +++ b/src/sage/features/kenzo.py @@ -18,6 +18,7 @@ from . import Feature, FeatureTestResult + class Kenzo(Feature): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`Kenzo `. diff --git a/src/sage/features/latex.py b/src/sage/features/latex.py index 271800beece..46173f7484b 100644 --- a/src/sage/features/latex.py +++ b/src/sage/features/latex.py @@ -208,6 +208,7 @@ def __init__(self): Executable.__init__(self, 'dvips', executable='dvips', url='https://tug.org/texinfohtml/dvips.html') + class TeXFile(StaticFile): r""" A :class:`sage.features.Feature` describing the presence of a TeX file. diff --git a/src/sage/features/msolve.py b/src/sage/features/msolve.py index bc66da45044..24215a7c57c 100644 --- a/src/sage/features/msolve.py +++ b/src/sage/features/msolve.py @@ -22,6 +22,7 @@ from . import Executable from . import FeatureTestResult + class msolve(Executable): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`msolve `. @@ -64,5 +65,6 @@ def is_functional(self): reason="output of msolve -h not recognized") return FeatureTestResult(self, True) + def all_features(): return [msolve()] diff --git a/src/sage/features/palp.py b/src/sage/features/palp.py index 9e3324c495b..b20f44104d6 100644 --- a/src/sage/features/palp.py +++ b/src/sage/features/palp.py @@ -43,6 +43,7 @@ def __init__(self, palpprog, suff=None): executable=f"{palpprog}.x", spkg='palp', type='standard') + class Palp(JoinFeature): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`PALP `. @@ -61,5 +62,6 @@ def __init__(self): for suff in (None, 4, 5, 6, 11)], description='PALP') + def all_features(): return [Palp()] diff --git a/src/sage/features/pdf2svg.py b/src/sage/features/pdf2svg.py index 41014eb8e5c..92d9f563b5b 100644 --- a/src/sage/features/pdf2svg.py +++ b/src/sage/features/pdf2svg.py @@ -14,6 +14,7 @@ from . import Executable + class pdf2svg(Executable): r""" A :class:`~sage.features.Feature` describing the presence of :ref:`pdf2svg `. diff --git a/src/sage/features/poppler.py b/src/sage/features/poppler.py index a6da8343f53..436506e0b36 100644 --- a/src/sage/features/poppler.py +++ b/src/sage/features/poppler.py @@ -32,6 +32,7 @@ from . import Executable + class pdftocairo(Executable): r""" A :class:`sage.features.Feature` describing the presence of @@ -54,5 +55,6 @@ def __init__(self): Executable.__init__(self, "pdftocairo", executable='pdftocairo', url='https://poppler.freedesktop.org/') + def all_features(): return [pdftocairo()] diff --git a/src/sage/features/symengine_py.py b/src/sage/features/symengine_py.py index 96a64ca60b3..e822e252eda 100644 --- a/src/sage/features/symengine_py.py +++ b/src/sage/features/symengine_py.py @@ -40,5 +40,6 @@ def __init__(self): [PythonModule('symengine', spkg='symengine_py', url='https://pypi.org/project/symengine')]) + def all_features(): return [symengine_py()] diff --git a/src/sage/functions/airy.py b/src/sage/functions/airy.py index d8f1a79fa8b..ba1ebe34c91 100644 --- a/src/sage/functions/airy.py +++ b/src/sage/functions/airy.py @@ -241,7 +241,7 @@ def _evalf_(self, x, **kwargs): from sage.rings.real_mpfr import RR from sage.rings.cc import CC from sage.functions.other import real, imag - from scipy.special import airy as airy + from scipy.special import airy if x in RR: y = airy(real(x))[0] if parent is None: @@ -341,7 +341,7 @@ def _evalf_(self, x, **kwargs): from sage.rings.real_mpfr import RR from sage.rings.cc import CC from sage.functions.other import real, imag - from scipy.special import airy as airy + from scipy.special import airy if x in RR: y = airy(real(x))[1] if parent is None: @@ -680,7 +680,7 @@ def _evalf_(self, x, **kwargs): from sage.rings.real_mpfr import RR from sage.rings.cc import CC from sage.functions.other import real, imag - from scipy.special import airy as airy + from scipy.special import airy if x in RR: y = airy(real(x))[2] if parent is None: @@ -782,7 +782,7 @@ def _evalf_(self, x, **kwargs): from sage.rings.real_mpfr import RR from sage.rings.cc import CC from sage.functions.other import real, imag - from scipy.special import airy as airy + from scipy.special import airy if x in RR: y = airy(real(x))[3] if parent is None: diff --git a/src/sage/functions/log.py b/src/sage/functions/log.py index de1db4dcb92..344bff959a3 100644 --- a/src/sage/functions/log.py +++ b/src/sage/functions/log.py @@ -8,7 +8,7 @@ - Tomas Kalvoda (2015-04-01): Add :meth:`exp_polar()` (:issue:`18085`) """ -from sage.misc.functional import log as log +from sage.misc.functional import log from sage.misc.lazy_import import lazy_import from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ diff --git a/src/sage/functions/meson.build b/src/sage/functions/meson.build index c2a77f0e238..85b7b4afa49 100644 --- a/src/sage/functions/meson.build +++ b/src/sage/functions/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'airy.py', 'all.py', 'bessel.py', diff --git a/src/sage/functions/piecewise.py b/src/sage/functions/piecewise.py index fc69057ef6f..2986e47960d 100644 --- a/src/sage/functions/piecewise.py +++ b/src/sage/functions/piecewise.py @@ -836,6 +836,7 @@ def integral(self, parameters, variable, x=None, a=None, b=None, definite=False, Check that the algorithm keyword can be used:: + sage: # needs sage.libs.giac sage: ex = piecewise([([0, 1], 1), ((1, oo), 1/x**2)]) sage: integral(ex, x, 0, 100, algorithm='sympy') 199/100 diff --git a/src/sage/functions/special.py b/src/sage/functions/special.py index 308171af3cd..f511190aeff 100644 --- a/src/sage/functions/special.py +++ b/src/sage/functions/special.py @@ -216,11 +216,16 @@ class SphericalHarmonic(BuiltinFunction): sage: spherical_harmonic(1, 1, pi/2, pi).n() # abs tol 1e-14 # needs sage.symbolic 0.345494149471335 - sage: from scipy.special import sph_harm # NB: arguments x and y are swapped # needs scipy sage: import numpy as np # needs scipy sage: if int(np.version.short_version[0]) > 1: # needs scipy ....: np.set_printoptions(legacy="1.25") # needs scipy - sage: sph_harm(1, 1, pi.n(), (pi/2).n()) # abs tol 1e-14 # needs scipy sage.symbolic + sage: import scipy.version + sage: if scipy.version.version < '1.15.0': + ....: from scipy.special import sph_harm # NB: arguments x and y are swapped # needs scipy + ....: sph_harm(1, 1, pi.n(), (pi/2).n()) # abs tol 1e-14 # needs scipy sage.symbolic + ....: else: + ....: from scipy.special import sph_harm_y # needs scipy + ....: sph_harm_y(1, 1, (pi/2).n(), pi.n()).item() # abs tol 1e-9 # needs scipy sage.symbolic (0.3454941494713355-4.231083042742082e-17j) Note that this convention differs from the one in Maxima, as revealed by diff --git a/src/sage/game_theory/normal_form_game.py b/src/sage/game_theory/normal_form_game.py index e46e96c2b32..39622aaf3ef 100644 --- a/src/sage/game_theory/normal_form_game.py +++ b/src/sage/game_theory/normal_form_game.py @@ -1989,7 +1989,7 @@ def _solve_enumeration(self, maximization=True): sage: c._solve_enumeration() [[(0, 1), (1, 0)]] - Testing against an error in `_is_NE`. Note that 1 equilibrium is + Testing against an error in ``_is_NE``. Note that 1 equilibrium is missing: ``[(2/3, 1/3), (0, 1)]``, however this equilibrium has supports of different sizes. This only occurs in degenerate games and is not supported in the `enumeration` algorithm:: diff --git a/src/sage/games/meson.build b/src/sage/games/meson.build index d0776c0c71a..8852b13d9cf 100644 --- a/src/sage/games/meson.build +++ b/src/sage/games/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'hexad.py', 'quantumino.py', diff --git a/src/sage/games/quantumino.py b/src/sage/games/quantumino.py index 555f6901f4a..587e279e042 100644 --- a/src/sage/games/quantumino.py +++ b/src/sage/games/quantumino.py @@ -205,6 +205,7 @@ pentaminos.append(Polyomino([(0,0,0), (0,1,0), (1,1,0), (1,2,0), (1,2,1)], color='purple')) pentaminos.append(Polyomino([(0,1,0), (1,0,0), (1,1,0), (1,1,1), (1,2,0)], color='gray')) + def show_pentaminos(box=(5, 8, 2)): r""" Show the 17 3-D pentaminos included in the game and the `5 \times 8 @@ -245,6 +246,8 @@ def show_pentaminos(box=(5, 8, 2)): ############################## # Class QuantuminoState ############################## + + class QuantuminoState(SageObject): r""" A state of the Quantumino puzzle. @@ -386,6 +389,8 @@ def show3d(self, size=0.85): ############################## # Class QuantuminoSolver ############################## + + class QuantuminoSolver(SageObject): r""" Return the Quantumino solver for the given box where one of the diff --git a/src/sage/games/sudoku_backtrack.pyx b/src/sage/games/sudoku_backtrack.pyx index b9630566cf5..744bafce6be 100644 --- a/src/sage/games/sudoku_backtrack.pyx +++ b/src/sage/games/sudoku_backtrack.pyx @@ -71,7 +71,7 @@ def backtrack_all(n, puzzle): # location as row and column in square # grids are numbered similarly, in row-major order row = level // nsquare - col = level % nsquare + col = level % nsquare grid_corner = (row - (row % n))*nsquare + (col - (col % n)) grid_row = row // n grid_col = col // n @@ -141,7 +141,7 @@ def backtrack_all(n, puzzle): if available[abox][asymbol] == 0: card[abox] += 1 # move sideways in search tree to next available symbol - symbol += 1 + symbol += 1 while (symbol < nsquare) and (available[level][symbol] != 0): symbol += 1 if symbol == nsquare: diff --git a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py index 2dd20676215..9fe8f9e5a67 100644 --- a/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py +++ b/src/sage/geometry/hyperbolic_space/hyperbolic_isometry.py @@ -188,9 +188,9 @@ def __eq__(self, other): return False test_matrix = bool((self.matrix() - other.matrix()).norm() < EPSILON) if self.domain().is_isometry_group_projective(): - A,B = self.matrix(), other.matrix() # Rename for simplicity + A, B = self.matrix(), other.matrix() # Rename for simplicity m = self.matrix().ncols() - A = A / sqrt(A.det(), m) # Normalized to have determinant 1 + A = A / sqrt(A.det(), m) # Normalized to have determinant 1 B = B / sqrt(B.det(), m) test_matrix = ((A - B).norm() < EPSILON or (A + B).norm() < EPSILON) @@ -636,7 +636,7 @@ class HyperbolicIsometryUHP(HyperbolicIsometry): [1 0] [0 1] """ - def _call_(self, p): #UHP + def _call_(self, p): # UHP r""" Return image of ``p`` under the action of ``self``. @@ -656,7 +656,7 @@ def _call_(self, p): #UHP coords = coords.conjugate() return self.codomain().get_point(moebius_transform(self._matrix, coords)) - def preserves_orientation(self): #UHP + def preserves_orientation(self): # UHP r""" Return ``True`` if ``self`` is orientation-preserving and ``False`` otherwise. @@ -673,7 +673,7 @@ def preserves_orientation(self): #UHP """ return bool(self._matrix.det() > 0) - def classification(self): #UHP + def classification(self): # UHP r""" Classify the hyperbolic isometry as elliptic, parabolic, or hyperbolic. @@ -725,7 +725,7 @@ def classification(self): #UHP return 'reflection' return 'orientation-reversing hyperbolic' - def translation_length(self): #UHP + def translation_length(self): # UHP r""" For hyperbolic elements, return the translation length; otherwise, raise a :exc:`ValueError`. @@ -800,7 +800,7 @@ def fixed_point_set(self): # UHP d = sqrt(tau - 4) return [pt((M[0,0] - M[1,1] + sign(M[1,0])*d) / (2*M[1,0]))] elif M_cls == 'hyperbolic': - if M[1,0] != 0: #if the isometry doesn't fix infinity + if M[1,0] != 0: # if the isometry does not fix infinity d = sqrt(tau - 4) p_1 = (M[0,0] - M[1,1]+d) / (2*M[1,0]) p_2 = (M[0,0] - M[1,1]-d) / (2*M[1,0]) @@ -898,7 +898,7 @@ class HyperbolicIsometryPD(HyperbolicIsometry): [1 0] [0 1] """ - def _call_(self, p): #PD + def _call_(self, p): # PD r""" Return image of ``p`` under the action of ``self``. @@ -917,7 +917,7 @@ def _call_(self, p): #PD _image = moebius_transform(self._matrix, coords) return self.codomain().get_point(_image) - def __mul__(self, other): #PD + def __mul__(self, other): # PD r""" Return image of ``p`` under the action of ``self``. @@ -935,7 +935,7 @@ def __mul__(self, other): #PD return M.to_model('PD') return super().__mul__(other) - def __pow__(self, n): #PD + def __pow__(self, n): # PD r""" EXAMPLES:: @@ -948,7 +948,7 @@ def __pow__(self, n): #PD """ return (self._cached_isometry**n).to_model('PD') - def preserves_orientation(self): #PD + def preserves_orientation(self): # PD """ Return ``True`` if ``self`` preserves orientation and ``False`` otherwise. @@ -964,7 +964,7 @@ def preserves_orientation(self): #PD return bool(self._matrix.det() > 0) and HyperbolicIsometryPD._orientation_preserving(self._matrix) @staticmethod - def _orientation_preserving(A): #PD + def _orientation_preserving(A): # PD r""" For a matrix ``A`` of a PD isometry, determine if it preserves orientation. @@ -1001,7 +1001,7 @@ class HyperbolicIsometryKM(HyperbolicIsometry): [0 1 0] [0 0 1] """ - def _call_(self, p): #KM + def _call_(self, p): # KM r""" Return image of ``p`` under the action of ``self``. @@ -1019,7 +1019,7 @@ def _call_(self, p): #KM return self.codomain().get_point(v[0:2] / v[2]) ##################################################################### -## Helper functions +# Helper functions def moebius_transform(A, z): diff --git a/src/sage/geometry/hyperplane_arrangement/hyperplane.py b/src/sage/geometry/hyperplane_arrangement/hyperplane.py index 04de307442d..38e0761330b 100644 --- a/src/sage/geometry/hyperplane_arrangement/hyperplane.py +++ b/src/sage/geometry/hyperplane_arrangement/hyperplane.py @@ -353,10 +353,7 @@ def linear_part_projection(self, point): sage: p2 = h.linear_part_projection([3,4,5]); p2 (8/7, 2/7) sage: h.linear_part().basis() - [ - (1, 0, -1/3), - (0, 1, -2/3) - ] + [(1, 0, -1/3), (0, 1, -2/3)] sage: p3 = h.linear_part_projection([1,1,1]); p3 (4/7, 1/7) """ diff --git a/src/sage/geometry/hyperplane_arrangement/library.py b/src/sage/geometry/hyperplane_arrangement/library.py index 9e2ca3336f6..2c731eba212 100644 --- a/src/sage/geometry/hyperplane_arrangement/library.py +++ b/src/sage/geometry/hyperplane_arrangement/library.py @@ -502,7 +502,8 @@ def Ish(self, n, K=QQ, names=None): A = H(*hyperplanes) x = polygen(QQ, 'x') charpoly = x * sum([(-1)**k * stirling_number2(n, n-k) * - prod([(x - 1 - j) for j in range(k, n-1)]) for k in range(0, n)]) + prod([(x - 1 - j) for j in range(k, n-1)]) + for k in range(n)]) A.characteristic_polynomial.set_cache(charpoly) return A diff --git a/src/sage/geometry/hyperplane_arrangement/ordered_arrangement.py b/src/sage/geometry/hyperplane_arrangement/ordered_arrangement.py index c0024f4c982..87774ec64ab 100644 --- a/src/sage/geometry/hyperplane_arrangement/ordered_arrangement.py +++ b/src/sage/geometry/hyperplane_arrangement/ordered_arrangement.py @@ -394,7 +394,6 @@ def projective_fundamental_group(self): < x0, x1, x2, x3, x4 | x4^-1*x3^-1*x2^-1*x3*x4*x0*x2*x0^-1, x4^-1*x2^-1*x4*x2, x4^-1*x1^-1*x0^-1*x1*x4*x0, x4^-1*x1^-1*x0^-1*x4*x0*x1, - x4^-1*x1^-1*x3*x0*x1*x3^-1*x2^-1*x4*x0^-1*x2, x3^-1*x2^-1*x1^-1*x0^-1*x3*x0*x1*x2, x3^-1*x1^-1*x3*x1 > sage: G3.abelian_invariants() @@ -406,9 +405,7 @@ def projective_fundamental_group(self): < x0, x1, x2, x3, x4 | x4^-1*x3^-1*x2^-1*x3*x4*x0*x2*x0^-1, x4^-1*x2^-1*x4*x2, x4^-1*x1^-1*x0^-1*x1*x4*x0, x4^-1*x1^-1*x0^-1*x4*x0*x1, - x4^-1*x1^-1*x3*x0*x1*x3^-1*x2^-1*x4*x0^-1*x2, - x3^-1*x2^-1*x1^-1*x0^-1*x3*x0*x1*x2, - x3^-1*x1^-1*x3*x1 > + x3^-1*x2^-1*x1^-1*x0^-1*x3*x0*x1*x2, x3^-1*x1^-1*x3*x1 > sage: G4.abelian_invariants() (0, 0, 0, 0, 0) diff --git a/src/sage/geometry/lattice_polytope.py b/src/sage/geometry/lattice_polytope.py index 2869dcc7442..da030a17966 100644 --- a/src/sage/geometry/lattice_polytope.py +++ b/src/sage/geometry/lattice_polytope.py @@ -1250,11 +1250,9 @@ def _read_nef_partitions(self, data): False sage: o_copy._read_nef_partitions(s) # needs palp sage: o_copy._nef_partitions # needs palp - [ - Nef-partition {0, 1, 3} ⊔ {2, 4, 5}, - Nef-partition {0, 1, 2} ⊔ {3, 4, 5}, - Nef-partition {0, 1, 2, 3} ⊔ {4, 5} - ] + [Nef-partition {0, 1, 3} ⊔ {2, 4, 5}, + Nef-partition {0, 1, 2} ⊔ {3, 4, 5}, + Nef-partition {0, 1, 2, 3} ⊔ {4, 5}] """ if isinstance(data, str): f = StringIO(data) @@ -2710,29 +2708,25 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, sage: p = lattice_polytope.cross_polytope(4) sage: p.nef_partitions() # needs palp - [ - Nef-partition {0, 1, 4, 5} ⊔ {2, 3, 6, 7} (direct product), - Nef-partition {0, 1, 2, 4} ⊔ {3, 5, 6, 7}, - Nef-partition {0, 1, 2, 4, 5} ⊔ {3, 6, 7}, - Nef-partition {0, 1, 2, 4, 5, 6} ⊔ {3, 7} (direct product), - Nef-partition {0, 1, 2, 3} ⊔ {4, 5, 6, 7}, - Nef-partition {0, 1, 2, 3, 4} ⊔ {5, 6, 7}, - Nef-partition {0, 1, 2, 3, 4, 5} ⊔ {6, 7}, - Nef-partition {0, 1, 2, 3, 4, 5, 6} ⊔ {7} (projection) - ] + [Nef-partition {0, 1, 4, 5} ⊔ {2, 3, 6, 7} (direct product), + Nef-partition {0, 1, 2, 4} ⊔ {3, 5, 6, 7}, + Nef-partition {0, 1, 2, 4, 5} ⊔ {3, 6, 7}, + Nef-partition {0, 1, 2, 4, 5, 6} ⊔ {3, 7} (direct product), + Nef-partition {0, 1, 2, 3} ⊔ {4, 5, 6, 7}, + Nef-partition {0, 1, 2, 3, 4} ⊔ {5, 6, 7}, + Nef-partition {0, 1, 2, 3, 4, 5} ⊔ {6, 7}, + Nef-partition {0, 1, 2, 3, 4, 5, 6} ⊔ {7} (projection)] Now we omit projections:: sage: p.nef_partitions(keep_projections=False) # needs palp - [ - Nef-partition {0, 1, 4, 5} ⊔ {2, 3, 6, 7} (direct product), - Nef-partition {0, 1, 2, 4} ⊔ {3, 5, 6, 7}, - Nef-partition {0, 1, 2, 4, 5} ⊔ {3, 6, 7}, - Nef-partition {0, 1, 2, 4, 5, 6} ⊔ {3, 7} (direct product), - Nef-partition {0, 1, 2, 3} ⊔ {4, 5, 6, 7}, - Nef-partition {0, 1, 2, 3, 4} ⊔ {5, 6, 7}, - Nef-partition {0, 1, 2, 3, 4, 5} ⊔ {6, 7} - ] + [Nef-partition {0, 1, 4, 5} ⊔ {2, 3, 6, 7} (direct product), + Nef-partition {0, 1, 2, 4} ⊔ {3, 5, 6, 7}, + Nef-partition {0, 1, 2, 4, 5} ⊔ {3, 6, 7}, + Nef-partition {0, 1, 2, 4, 5, 6} ⊔ {3, 7} (direct product), + Nef-partition {0, 1, 2, 3} ⊔ {4, 5, 6, 7}, + Nef-partition {0, 1, 2, 3, 4} ⊔ {5, 6, 7}, + Nef-partition {0, 1, 2, 3, 4, 5} ⊔ {6, 7}] Currently Hodge numbers cannot be computed for a given nef-partition:: @@ -2745,16 +2739,14 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, Partitions will be exactly the same:: sage: p.nef_partitions(hodge_numbers=True) # long time (2s on sage.math, 2011), needs palp - [ - Nef-partition {0, 1, 4, 5} ⊔ {2, 3, 6, 7} (direct product), - Nef-partition {0, 1, 2, 4} ⊔ {3, 5, 6, 7}, - Nef-partition {0, 1, 2, 4, 5} ⊔ {3, 6, 7}, - Nef-partition {0, 1, 2, 4, 5, 6} ⊔ {3, 7} (direct product), - Nef-partition {0, 1, 2, 3} ⊔ {4, 5, 6, 7}, - Nef-partition {0, 1, 2, 3, 4} ⊔ {5, 6, 7}, - Nef-partition {0, 1, 2, 3, 4, 5} ⊔ {6, 7}, - Nef-partition {0, 1, 2, 3, 4, 5, 6} ⊔ {7} (projection) - ] + [Nef-partition {0, 1, 4, 5} ⊔ {2, 3, 6, 7} (direct product), + Nef-partition {0, 1, 2, 4} ⊔ {3, 5, 6, 7}, + Nef-partition {0, 1, 2, 4, 5} ⊔ {3, 6, 7}, + Nef-partition {0, 1, 2, 4, 5, 6} ⊔ {3, 7} (direct product), + Nef-partition {0, 1, 2, 3} ⊔ {4, 5, 6, 7}, + Nef-partition {0, 1, 2, 3, 4} ⊔ {5, 6, 7}, + Nef-partition {0, 1, 2, 3, 4, 5} ⊔ {6, 7}, + Nef-partition {0, 1, 2, 3, 4, 5, 6} ⊔ {7} (projection)] Now it is possible to get Hodge numbers:: @@ -2772,21 +2764,17 @@ def nef_partitions(self, keep_symmetric=False, keep_products=True, sage: p = lattice_polytope.cross_polytope(2) sage: p.nef_partitions() # needs palp - [ - Nef-partition {0, 2} ⊔ {1, 3} (direct product), - Nef-partition {0, 1} ⊔ {2, 3}, - Nef-partition {0, 1, 2} ⊔ {3} (projection) - ] + [Nef-partition {0, 2} ⊔ {1, 3} (direct product), + Nef-partition {0, 1} ⊔ {2, 3}, + Nef-partition {0, 1, 2} ⊔ {3} (projection)] sage: p.nef_partitions(keep_symmetric=True) # needs palp - [ - Nef-partition {0, 1, 3} ⊔ {2} (projection), - Nef-partition {0, 2, 3} ⊔ {1} (projection), - Nef-partition {0, 3} ⊔ {1, 2}, - Nef-partition {1, 2, 3} ⊔ {0} (projection), - Nef-partition {1, 3} ⊔ {0, 2} (direct product), - Nef-partition {2, 3} ⊔ {0, 1}, - Nef-partition {0, 1, 2} ⊔ {3} (projection) - ] + [Nef-partition {0, 1, 3} ⊔ {2} (projection), + Nef-partition {0, 2, 3} ⊔ {1} (projection), + Nef-partition {0, 3} ⊔ {1, 2}, + Nef-partition {1, 2, 3} ⊔ {0} (projection), + Nef-partition {1, 3} ⊔ {0, 2} (direct product), + Nef-partition {2, 3} ⊔ {0, 1}, + Nef-partition {0, 1, 2} ⊔ {3} (projection)] Nef-partitions can be computed only for reflexive polytopes:: @@ -3308,7 +3296,7 @@ def _palp_PM_max(self, check=False): [(1,2), (1,2)], [(), ()], [(2,3), (2,3)]] - sage: PM_max.automorphisms_of_rows_and_columns() # needs sage.graphs + sage: PM_max.automorphisms_of_rows_and_columns() # needs sage.graphs sage.groups [((), ()), ((1,2,3), (1,2,3)), ((1,3,2), (1,3,2)), @@ -4135,7 +4123,7 @@ def is_NefPartition(x): sage: o = lattice_polytope.cross_polytope(3) sage: np = o.nef_partitions()[0]; np # needs palp Nef-partition {0, 1, 3} ⊔ {2, 4, 5} - sage: isinstance(np, NefPartition) # needs palp + sage: isinstance(np, NefPartition) # needs palp True """ from sage.misc.superseded import deprecation @@ -4276,13 +4264,11 @@ class NefPartition(SageObject, Hashable): ``nef.x`` program from PALP):: sage: o.nef_partitions() # needs palp - [ - Nef-partition {0, 1, 3} ⊔ {2, 4, 5}, - Nef-partition {0, 1, 3, 4} ⊔ {2, 5} (direct product), - Nef-partition {0, 1, 2} ⊔ {3, 4, 5}, - Nef-partition {0, 1, 2, 3} ⊔ {4, 5}, - Nef-partition {0, 1, 2, 3, 4} ⊔ {5} (projection) - ] + [Nef-partition {0, 1, 3} ⊔ {2, 4, 5}, + Nef-partition {0, 1, 3, 4} ⊔ {2, 5} (direct product), + Nef-partition {0, 1, 2} ⊔ {3, 4, 5}, + Nef-partition {0, 1, 2, 3} ⊔ {4, 5}, + Nef-partition {0, 1, 2, 3, 4} ⊔ {5} (projection)] """ def __init__(self, data, Delta_polar, check=True): @@ -5329,13 +5315,11 @@ def all_nef_partitions(polytopes, keep_symmetric=False): sage: o = lattice_polytope.cross_polytope(3) sage: lattice_polytope.all_nef_partitions([o]) # needs palp sage: o.nef_partitions() # needs palp - [ - Nef-partition {0, 1, 3} ⊔ {2, 4, 5}, - Nef-partition {0, 1, 3, 4} ⊔ {2, 5} (direct product), - Nef-partition {0, 1, 2} ⊔ {3, 4, 5}, - Nef-partition {0, 1, 2, 3} ⊔ {4, 5}, - Nef-partition {0, 1, 2, 3, 4} ⊔ {5} (projection) - ] + [Nef-partition {0, 1, 3} ⊔ {2, 4, 5}, + Nef-partition {0, 1, 3, 4} ⊔ {2, 5} (direct product), + Nef-partition {0, 1, 2} ⊔ {3, 4, 5}, + Nef-partition {0, 1, 2, 3} ⊔ {4, 5}, + Nef-partition {0, 1, 2, 3, 4} ⊔ {5} (projection)] You cannot use this function for non-reflexive polytopes:: diff --git a/src/sage/geometry/meson.build b/src/sage/geometry/meson.build index 8906b859dde..3b48404564d 100644 --- a/src/sage/geometry/meson.build +++ b/src/sage/geometry/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'cone.py', 'cone_catalog.py', diff --git a/src/sage/geometry/polyhedral_complex.py b/src/sage/geometry/polyhedral_complex.py index 539e2021f88..fa4aab394d4 100644 --- a/src/sage/geometry/polyhedral_complex.py +++ b/src/sage/geometry/polyhedral_complex.py @@ -412,7 +412,7 @@ def cell_iterator(self, increasing=True): 11 """ cells = self.cells() - dim_index = range(0, self.dimension() + 1) + dim_index = range(self.dimension() + 1) if not increasing: dim_index = reversed(dim_index) for d in dim_index: @@ -2271,7 +2271,7 @@ def is_simplicial_fan(self): Test if this polyhedral complex is a simplicial fan. A polyhedral complex is a **simplicial fan** if all of its (maximal) - cells are simplical cones, i.e., every cell is a pointed cone (with + cells are simplicial cones, i.e., every cell is a pointed cone (with vertex being the origin) generated by `d` linearly independent rays, where `d` is the dimension of the cone. diff --git a/src/sage/geometry/polyhedron/base_number_field.py b/src/sage/geometry/polyhedron/base_number_field.py index ef912a5e501..c1d0ab39190 100644 --- a/src/sage/geometry/polyhedron/base_number_field.py +++ b/src/sage/geometry/polyhedron/base_number_field.py @@ -28,7 +28,7 @@ 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. + Like ``number_field_elements_from_algebraics``, but for a list of lists of lists. EXAMPLES:: diff --git a/src/sage/geometry/polyhedron/combinatorial_polyhedron/meson.build b/src/sage/geometry/polyhedron/combinatorial_polyhedron/meson.build index 4b4ea8df4e7..a279309fc13 100644 --- a/src/sage/geometry/polyhedron/combinatorial_polyhedron/meson.build +++ b/src/sage/geometry/polyhedron/combinatorial_polyhedron/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'base.pxd', 'combinatorial_face.pxd', diff --git a/src/sage/geometry/polyhedron/meson.build b/src/sage/geometry/polyhedron/meson.build index 3b07bbdd9a5..db589c39385 100644 --- a/src/sage/geometry/polyhedron/meson.build +++ b/src/sage/geometry/polyhedron/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'backend_cdd.py', 'backend_cdd_rdf.py', diff --git a/src/sage/geometry/polyhedron/modules/formal_polyhedra_module.py b/src/sage/geometry/polyhedron/modules/formal_polyhedra_module.py index d7ef932a4cf..91101f120fc 100644 --- a/src/sage/geometry/polyhedron/modules/formal_polyhedra_module.py +++ b/src/sage/geometry/polyhedron/modules/formal_polyhedra_module.py @@ -82,7 +82,7 @@ def __classcall__(cls, base_ring, dimension, basis, category=None): """ if isinstance(basis, list): basis = tuple(basis) - if isinstance(basis, tuple): #To make sure it only check for finite input + if isinstance(basis, tuple): # To make sure it only checks for finite input from sage.geometry.polyhedron.base import Polyhedron_base for P in basis: if not isinstance(P, Polyhedron_base): diff --git a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py index 17fb5028df1..308a151fad3 100644 --- a/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py +++ b/src/sage/geometry/riemannian_manifolds/parametrized_surface3d.py @@ -276,11 +276,11 @@ class ParametrizedSurface3D(SageObject): sage: cc_array = [(ccc - K_min)/(K_max - K_min) for ccc in K_array] sage: points_array = [ellipsoid_equation(u_array[counter][0], ....: u_array[counter][1]) - ....: for counter in range(0,len(u_array))] + ....: for counter in range(len(u_array))] sage: curvature_ellipsoid_plot = sum(point([xx # needs sage.plot ....: for xx in points_array[counter]], ....: color=hue(cc_array[counter]/2)) - ....: for counter in range(0,len(u_array))) + ....: for counter in range(len(u_array))) sage: curvature_ellipsoid_plot.show(aspect_ratio=1) # needs sage.plot We can find the principal curvatures and principal directions of the diff --git a/src/sage/geometry/toric_lattice.py b/src/sage/geometry/toric_lattice.py index a79bac65c6e..12399603c9d 100644 --- a/src/sage/geometry/toric_lattice.py +++ b/src/sage/geometry/toric_lattice.py @@ -1099,19 +1099,13 @@ class ToricLattice_sublattice_with_basis(ToricLattice_generic, sage: sublattice.has_user_basis() True sage: sublattice.basis() - [ - N(1, 1, 0), - N(3, 2, 1) - ] + [N(1, 1, 0), N(3, 2, 1)] Even if you have provided your own basis, you still can access the "standard" one:: sage: sublattice.echelonized_basis() - [ - N(1, 0, 1), - N(0, 1, -1) - ] + [N(1, 0, 1), N(0, 1, -1)] """ def _repr_(self): @@ -1245,19 +1239,13 @@ class ToricLattice_sublattice(ToricLattice_sublattice_with_basis, sage: sublattice.has_user_basis() False sage: sublattice.basis() - [ - N(1, 0, 1), - N(0, 1, -1) - ] + [N(1, 0, 1), N(0, 1, -1)] For sublattices without user-specified basis, the basis obtained above is the same as the "standard" one:: sage: sublattice.echelonized_basis() - [ - N(1, 0, 1), - N(0, 1, -1) - ] + [N(1, 0, 1), N(0, 1, -1)] """ pass diff --git a/src/sage/geometry/triangulation/base.pyx b/src/sage/geometry/triangulation/base.pyx index 55144d1623c..3bbbaddef6b 100644 --- a/src/sage/geometry/triangulation/base.pyx +++ b/src/sage/geometry/triangulation/base.pyx @@ -595,13 +595,13 @@ cdef class PointConfiguration_base(Parent): EXAMPLES:: sage: p = PointConfiguration([[1,0], [2,3], [3,2]]) - sage: [ p[i] for i in range(0,p.n_points()) ] + sage: [p[i] for i in range(p.n_points())] [P(1, 0), P(2, 3), P(3, 2)] sage: list(p) [P(1, 0), P(2, 3), P(3, 2)] sage: list(p.points()) [P(1, 0), P(2, 3), P(3, 2)] - sage: [ p.point(i) for i in range(0,p.n_points()) ] + sage: [p.point(i) for i in range(p.n_points())] [P(1, 0), P(2, 3), P(3, 2)] """ return self._pts[i] diff --git a/src/sage/geometry/triangulation/meson.build b/src/sage/geometry/triangulation/meson.build index dec407d83d5..e8361a9da09 100644 --- a/src/sage/geometry/triangulation/meson.build +++ b/src/sage/geometry/triangulation/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'data.pxd', 'element.py', diff --git a/src/sage/geometry/voronoi_diagram.py b/src/sage/geometry/voronoi_diagram.py index 1402e0b1e77..9929ae7ca60 100644 --- a/src/sage/geometry/voronoi_diagram.py +++ b/src/sage/geometry/voronoi_diagram.py @@ -290,7 +290,7 @@ def plot(self, cell_colors=None, **kwds): cell_colors = rainbow(self._n) shuffle(cell_colors) else: - if not (isinstance(cell_colors, list) or (isinstance(cell_colors, dict))): + if not isinstance(cell_colors, (list, dict)): raise AssertionError("'cell_colors' must be a list or a dictionary") for i, p in enumerate(self._P): col = cell_colors[i] diff --git a/src/sage/graphs/base/c_graph.pyx b/src/sage/graphs/base/c_graph.pyx index 1aa7b32d691..b3ab477e712 100644 --- a/src/sage/graphs/base/c_graph.pyx +++ b/src/sage/graphs/base/c_graph.pyx @@ -43,15 +43,18 @@ method :meth:`realloc `. # https://www.gnu.org/licenses/ # **************************************************************************** +from cysignals.memory cimport check_allocarray, sig_free +from libcpp.pair cimport pair +from libcpp.queue cimport queue +from libcpp.stack cimport stack + +from sage.arith.long cimport pyobject_to_long +from sage.data_structures.bitset cimport FrozenBitset from sage.data_structures.bitset_base cimport * +from sage.data_structures.pairing_heap cimport PairingHeap from sage.rings.integer cimport smallInteger -from sage.arith.long cimport pyobject_to_long -from libcpp.queue cimport priority_queue, queue -from libcpp.stack cimport stack -from libcpp.pair cimport pair + from sage.rings.integer_ring import ZZ -from cysignals.memory cimport check_allocarray, sig_free -from sage.data_structures.bitset cimport FrozenBitset cdef extern from "Python.h": @@ -2824,7 +2827,7 @@ cdef class CGraphBackend(GenericGraphBackend): # WARNING # If you modify this, you must keep in mind the documentation in the - # corresponding method in `generic_graph.py` in the method `edge_iterator`. + # corresponding method in ``generic_graph.py`` in the method ``edge_iterator``. # E.g. code assumes that you can use an iterator to relabel or delete arcs. u_int = cg._next_neighbor_unsafe(v_int, -1, out, &l_int) @@ -3737,7 +3740,6 @@ cdef class CGraphBackend(GenericGraphBackend): cdef dict pred_x = {} cdef dict pred_y = {} cdef dict pred_current - cdef dict pred_other # Stores the distances from x and y cdef dict dist_x = {} @@ -3745,95 +3747,90 @@ cdef class CGraphBackend(GenericGraphBackend): cdef dict dist_current cdef dict dist_other - # Lists of vertices who are left to be explored. They are represented - # as pairs of pair and pair: ((distance, side), (predecessor, name)). - # 1 indicates x's side, -1 indicates y's, the distance being - # defined relatively. - cdef priority_queue[pair[pair[double, int], pair[int, int]]] pq - pq.push(((0, 1), (x_int, x_int))) - pq.push(((0, -1), (y_int, y_int))) - cdef list neighbors - - cdef list shortest_path = [] + # We use 2 min-heap data structures (pairing heaps), one for the + # exploration from x and the other for the reverse exploration to y. + # Each heap associates to a vertex a pair (distance, pred). + cdef PairingHeap[int, pair[double, int]] px = PairingHeap[int, pair[double, int]]() + cdef PairingHeap[int, pair[double, int]] py = PairingHeap[int, pair[double, int]]() + cdef PairingHeap[int, pair[double, int]] * ptmp + px.push(x_int, (0, x_int)) + py.push(y_int, (0, y_int)) # Meeting_vertex is a vertex discovered through x and through y # which defines the shortest path found # (of length shortest_path_length). cdef int meeting_vertex = -1 + cdef double shortest_path_length + cdef double f_tmp if reduced_weight is not None: def weight_function(e): return reduced_weight[(e[0], e[1])] # As long as the current side (x or y) is not totally explored ... - while not pq.empty(): - (distance, side), (pred, v) = pq.top() - # priority_queue by default is max heap - # negative value of distance is stored in priority_queue to get - # minimum distance - distance = -distance - pq.pop() + while not (px.empty() and py.empty()): + if (px.empty() or + (not py.empty() and px.top_value().first > py.top_value().first)): + side = -1 + ptmp = &py + else: # px is not empty + side = 1 + ptmp = &px + v, (distance, pred) = ptmp.top() if meeting_vertex != -1 and distance > shortest_path_length: break + ptmp.pop() if side == 1: dist_current, dist_other = dist_x, dist_y - pred_current, pred_other = pred_x, pred_y + pred_current = pred_x + nbr_iter = self.cg().out_neighbors(v) else: dist_current, dist_other = dist_y, dist_x - pred_current, pred_other = pred_y, pred_x - - if v not in dist_current: - if not distance_flag: - pred_current[v] = pred - dist_current[v] = distance - - if v in dist_other: - f_tmp = distance + dist_other[v] - if meeting_vertex == -1 or f_tmp < shortest_path_length: - meeting_vertex = v - shortest_path_length = f_tmp - if side == 1: - nbr = self.cg().out_neighbors(v) - else: - nbr = self.cg().in_neighbors(v) - - if not exclude_e and not exclude_v: - neighbors = [] - for n in nbr: - if include_v and n not in include_vertices_int: - continue - neighbors.append(n) - else: - neighbors = [] - for w in nbr: - if exclude_v and w in exclude_vertices_int: - continue - if (exclude_e and - ((side == 1 and (v, w) in exclude_edges_int) or - (side == -1 and (w, v) in exclude_edges_int))): - continue - if include_v and w not in include_vertices_int: - continue - neighbors.append(w) - for w in neighbors: - # If the neighbor is new, adds its non-found neighbors to - # the queue. - if w not in dist_current: - v_obj = self.vertex_label(v) - w_obj = self.vertex_label(w) - if side == -1: - v_obj, w_obj = w_obj, v_obj - if self._multiple_edges: - edge_label = min(weight_function((v_obj, w_obj, l)) for l in self.get_edge_label(v_obj, w_obj)) - else: - edge_label = weight_function((v_obj, w_obj, self.get_edge_label(v_obj, w_obj))) - if edge_label < 0: - raise ValueError("the graph contains an edge with negative weight") - # priority_queue is by default max_heap - # negative value of distance + edge_label is stored in - # priority_queue to get minimum distance - pq.push(((-(distance + edge_label), side), (v, w))) + pred_current = pred_y + nbr_iter = self.cg().in_neighbors(v) + + dist_current[v] = distance + if not distance_flag: + pred_current[v] = pred + + if v in dist_other: + f_tmp = distance + dist_other[v] + if meeting_vertex == -1 or f_tmp < shortest_path_length: + meeting_vertex = v + shortest_path_length = f_tmp + + if not exclude_e and not exclude_v: + neighbors = (w for w in nbr_iter + if not include_v or w in include_vertices_int) + else: + neighbors = (w for w in nbr_iter + if ((not exclude_v or w not in exclude_vertices_int) and + (not exclude_e or + ((side == 1 and (v, w) not in exclude_edges_int) or + (side == -1 and (w, v) not in exclude_edges_int))) and + (not include_v or w in include_vertices_int))) + + for w in neighbors: + # If w has not yet been extracted from the heap, we check if we + # can improve its path + if w not in dist_current: + v_obj = self.vertex_label(v) + w_obj = self.vertex_label(w) + if side == -1: + v_obj, w_obj = w_obj, v_obj + if self._multiple_edges: + edge_label = min(weight_function((v_obj, w_obj, l)) for l in self.get_edge_label(v_obj, w_obj)) + else: + edge_label = weight_function((v_obj, w_obj, self.get_edge_label(v_obj, w_obj))) + if edge_label < 0: + raise ValueError("the graph contains an edge with negative weight") + f_tmp = distance + edge_label + if ptmp.contains(w): + if ptmp.value(w).first > f_tmp: + ptmp.decrease(w, (f_tmp, v)) + else: + ptmp.push(w, (f_tmp, v)) # No meeting point has been found if meeting_vertex == -1: @@ -3841,33 +3838,34 @@ cdef class CGraphBackend(GenericGraphBackend): from sage.rings.infinity import Infinity return Infinity return [] - else: - # build the shortest path and returns it. - if distance_flag: - if shortest_path_length in ZZ: - return int(shortest_path_length) - else: - return shortest_path_length - w = meeting_vertex - - while w != x_int: - shortest_path.append(self.vertex_label(w)) - w = pred_x[w] - shortest_path.append(x) - shortest_path.reverse() + if distance_flag: + if shortest_path_length in ZZ: + return int(shortest_path_length) + return shortest_path_length - if meeting_vertex == y_int: - return shortest_path + # build the shortest path and return it. + cdef list shortest_path = [] + w = meeting_vertex + while w != x_int: + shortest_path.append(self.vertex_label(w)) + w = pred_x[w] - w = pred_y[meeting_vertex] - while w != y_int: - shortest_path.append(self.vertex_label(w)) - w = pred_y[w] - shortest_path.append(y) + shortest_path.append(x) + shortest_path.reverse() + if meeting_vertex == y_int: return shortest_path + w = pred_y[meeting_vertex] + while w != y_int: + shortest_path.append(self.vertex_label(w)) + w = pred_y[w] + + shortest_path.append(y) + + return shortest_path + def bidirectional_dijkstra(self, x, y, weight_function=None, distance_flag=False): r""" @@ -3899,7 +3897,7 @@ cdef class CGraphBackend(GenericGraphBackend): sage: G = Graph(graphs.PetersenGraph()) sage: for (u, v) in G.edges(sort=True, labels=None): - ....: G.set_edge_label(u, v, 1) + ....: G.set_edge_label(u, v, 1) sage: G.shortest_path(0, 1, by_weight=True) [0, 1] sage: G.shortest_path_length(0, 1, by_weight=True) @@ -3928,7 +3926,7 @@ cdef class CGraphBackend(GenericGraphBackend): sage: G = DiGraph({0: [1, 2], 1: [4], 2: [3, 4], 4: [5], 5: [6]}, multiedges=True) sage: for u, v in list(G.edges(labels=None, sort=False)): - ....: G.set_edge_label(u, v, 1) + ....: G.set_edge_label(u, v, 1) sage: G.distance(0, 5, by_weight=true) 3 """ @@ -3954,7 +3952,6 @@ cdef class CGraphBackend(GenericGraphBackend): cdef dict pred_x = {} cdef dict pred_y = {} cdef dict pred_current - cdef dict pred_other # Stores the distances from x and y cdef dict dist_x = {} @@ -3962,77 +3959,81 @@ cdef class CGraphBackend(GenericGraphBackend): cdef dict dist_current cdef dict dist_other - # Lists of vertices who are left to be explored. They are represented - # as pairs of pair and pair: ((distance, side), (predecessor, name)). - # 1 indicates x's side, -1 indicates y's, the distance being - # defined relatively. - cdef priority_queue[pair[pair[double, int], pair[int, int]]] pq - pq.push(((0, 1), (x_int, x_int))) - pq.push(((0, -1), (y_int, y_int))) - cdef list neighbors + # We use 2 min-heap data structures (pairing heaps), one for the + # exploration from x and the other for the reverse exploration to y. + # Each heap associates to a vertex a pair (distance, pred). + cdef PairingHeap[int, pair[double, int]] px = PairingHeap[int, pair[double, int]]() + cdef PairingHeap[int, pair[double, int]] py = PairingHeap[int, pair[double, int]]() + cdef PairingHeap[int, pair[double, int]] * ptmp + px.push(x_int, (0, x_int)) + py.push(y_int, (0, y_int)) - cdef list shortest_path = [] + cdef list neighbors # Meeting_vertex is a vertex discovered through x and through y # which defines the shortest path found # (of length shortest_path_length). cdef int meeting_vertex = -1 + cdef double shortest_path_length + cdef double f_tmp if weight_function is None: def weight_function(e): return 1 if e[2] is None else e[2] # As long as the current side (x or y) is not totally explored ... - while not pq.empty(): - (distance, side), (pred, v) = pq.top() - # priority_queue by default is max heap - # negative value of distance is stored in priority_queue to get - # minimum distance - distance = -distance - pq.pop() + while not (px.empty() and py.empty()): + if (px.empty() or + (not py.empty() and px.top_value().first > py.top_value().first)): + side = -1 + ptmp = &py + else: # px is not empty + side = 1 + ptmp = &px + v, (distance, pred) = ptmp.top() if meeting_vertex != -1 and distance > shortest_path_length: break + ptmp.pop() if side == 1: dist_current, dist_other = dist_x, dist_y - pred_current, pred_other = pred_x, pred_y + pred_current = pred_x + neighbors = self.cg().out_neighbors(v) else: dist_current, dist_other = dist_y, dist_x - pred_current, pred_other = pred_y, pred_x - - if v not in dist_current: - if not distance_flag: - pred_current[v] = pred - dist_current[v] = distance - - if v in dist_other: - f_tmp = distance + dist_other[v] - if meeting_vertex == -1 or f_tmp < shortest_path_length: - meeting_vertex = v - shortest_path_length = f_tmp - - if side == 1: - neighbors = self.cg().out_neighbors(v) - else: - neighbors = self.cg().in_neighbors(v) - for w in neighbors: - # If the neighbor is new, adds its non-found neighbors to - # the queue. - if w not in dist_current: - v_obj = self.vertex_label(v) - w_obj = self.vertex_label(w) - if side == -1: - v_obj, w_obj = w_obj, v_obj - if self._multiple_edges: - edge_label = min(weight_function((v_obj, w_obj, l)) for l in self.get_edge_label(v_obj, w_obj)) - else: - edge_label = weight_function((v_obj, w_obj, self.get_edge_label(v_obj, w_obj))) - if edge_label < 0: - raise ValueError("the graph contains an edge with negative weight") - # priority_queue is by default max_heap - # negative value of distance + edge_label is stored in - # priority_queue to get minimum distance - pq.push(((-(distance + edge_label), side), (v, w))) + pred_current = pred_y + neighbors = self.cg().in_neighbors(v) + + dist_current[v] = distance + if not distance_flag: + pred_current[v] = pred + + if v in dist_other: + f_tmp = distance + dist_other[v] + if meeting_vertex == -1 or f_tmp < shortest_path_length: + meeting_vertex = v + shortest_path_length = f_tmp + + for w in neighbors: + # If w has not yet been extracted from the heap, we check if we + # can improve its path + if w not in dist_current: + v_obj = self.vertex_label(v) + w_obj = self.vertex_label(w) + if side == -1: + v_obj, w_obj = w_obj, v_obj + if self._multiple_edges: + edge_label = min(weight_function((v_obj, w_obj, l)) for l in self.get_edge_label(v_obj, w_obj)) + else: + edge_label = weight_function((v_obj, w_obj, self.get_edge_label(v_obj, w_obj))) + if edge_label < 0: + raise ValueError("the graph contains an edge with negative weight") + f_tmp = distance + edge_label + if ptmp.contains(w): + if ptmp.value(w).first > f_tmp: + ptmp.decrease(w, (f_tmp, v)) + else: + ptmp.push(w, (f_tmp, v)) # No meeting point has been found if meeting_vertex == -1: @@ -4040,33 +4041,34 @@ cdef class CGraphBackend(GenericGraphBackend): from sage.rings.infinity import Infinity return Infinity return [] - else: - # build the shortest path and returns it. - if distance_flag: - if shortest_path_length in ZZ: - return int(shortest_path_length) - else: - return shortest_path_length - w = meeting_vertex - while w != x_int: - shortest_path.append(self.vertex_label(w)) - w = pred_x[w] - - shortest_path.append(x) - shortest_path.reverse() + if distance_flag: + if shortest_path_length in ZZ: + return int(shortest_path_length) + return shortest_path_length - if meeting_vertex == y_int: - return shortest_path + # build the shortest path and return it. + cdef list shortest_path = [] + w = meeting_vertex + while w != x_int: + shortest_path.append(self.vertex_label(w)) + w = pred_x[w] - w = pred_y[meeting_vertex] - while w != y_int: - shortest_path.append(self.vertex_label(w)) - w = pred_y[w] - shortest_path.append(y) + shortest_path.append(x) + shortest_path.reverse() + if meeting_vertex == y_int: return shortest_path + w = pred_y[meeting_vertex] + while w != y_int: + shortest_path.append(self.vertex_label(w)) + w = pred_y[w] + + shortest_path.append(y) + + return shortest_path + def shortest_path_all_vertices(self, v, cutoff=None, distance_flag=False): r""" @@ -4176,7 +4178,8 @@ cdef class CGraphBackend(GenericGraphBackend): # Searching ################################### - def depth_first_search(self, v, reverse=False, ignore_direction=False): + def depth_first_search(self, v, reverse=False, ignore_direction=False, + forbidden_vertices=None): r""" Return a depth-first search from vertex ``v``. @@ -4192,6 +4195,9 @@ cdef class CGraphBackend(GenericGraphBackend): relevant to digraphs. If this is a digraph, ignore all orientations and consider the graph as undirected. + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search. The start vertex ``v`` cannot be in this set. + ALGORITHM: Below is a general template for depth-first search. @@ -4234,7 +4240,7 @@ cdef class CGraphBackend(GenericGraphBackend): Traversing the Petersen graph using depth-first search:: - sage: G = Graph(graphs.PetersenGraph()) + sage: G = graphs.PetersenGraph() sage: list(G.depth_first_search(0)) [0, 5, 8, 6, 9, 7, 2, 3, 4, 1] @@ -4251,14 +4257,33 @@ cdef class CGraphBackend(GenericGraphBackend): ....: "Stuttgart": ["Nurnberg"], "Erfurt": ["Wurzburg"]}) sage: list(G.depth_first_search("Stuttgart")) ['Stuttgart', 'Nurnberg', ...] + + Avoiding some cities: + + sage: list(G.depth_first_search("Stuttgart", + ....: forbidden_vertices=["Frankfurt", "Munchen"])) + ['Stuttgart', 'Nurnberg', 'Wurzburg', 'Erfurt'] + + TESTS: + + The start vertex cannot be forbidden:: + + sage: G = graphs.PetersenGraph() + sage: list(G.depth_first_search(0, forbidden_vertices=[0, 1])) + Traceback (most recent call last): + ... + ValueError: the start vertex is in the set of forbidden vertices """ return Search_iterator(self, v, direction=-1, reverse=reverse, - ignore_direction=ignore_direction) + ignore_direction=ignore_direction, + forbidden_vertices=forbidden_vertices) - def breadth_first_search(self, v, reverse=False, ignore_direction=False, report_distance=False, edges=False): + def breadth_first_search(self, v, reverse=False, ignore_direction=False, + report_distance=False, edges=False, + forbidden_vertices=None): r""" Return a breadth-first search from vertex ``v``. @@ -4286,6 +4311,9 @@ cdef class CGraphBackend(GenericGraphBackend): Note that parameters ``edges`` and ``report_distance`` cannot be ``True`` simultaneously. + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search. The start vertex ``v`` cannot be in this set. + ALGORITHM: Below is a general template for breadth-first search. @@ -4337,6 +4365,22 @@ cdef class CGraphBackend(GenericGraphBackend): sage: G = graphs.EuropeMap(continental=True) sage: list(G.breadth_first_search("Portugal")) ['Portugal', 'Spain', ..., 'Greece'] + + Avoiding some countries: + + sage: list(G.breadth_first_search("Portugal", + ....: forbidden_vertices=["Germany","Italy"])) + ['Portugal', 'Spain', ..., 'Sweden'] + + TESTS: + + The start vertex cannot be forbidden:: + + sage: G = graphs.PetersenGraph() + sage: list(G.breadth_first_search(0, forbidden_vertices=[0])) + Traceback (most recent call last): + ... + ValueError: the start vertex is in the set of forbidden vertices """ return Search_iterator(self, v, @@ -4344,16 +4388,22 @@ cdef class CGraphBackend(GenericGraphBackend): reverse=reverse, ignore_direction=ignore_direction, report_distance=report_distance, - edges=edges) + edges=edges, + forbidden_vertices=forbidden_vertices) ################################### # Connectedness ################################### - def is_connected(self): + def is_connected(self, forbidden_vertices=None): r""" Check whether the graph is connected. + INPUT: + + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search + EXAMPLES: Petersen's graph is connected:: @@ -4371,6 +4421,16 @@ cdef class CGraphBackend(GenericGraphBackend): sage: Graph(graphs.CubeGraph(3)).is_connected() True + A graph with forbidden vertices:: + + sage: G = graphs.PathGraph(5) + sage: G._backend.is_connected() + True + sage: G._backend.is_connected(forbidden_vertices=[1]) + False + sage: G._backend.is_connected(forbidden_vertices=[0, 1]) + True + TESTS:: sage: P = posets.PentagonPoset() # needs sage.modules @@ -4389,8 +4449,18 @@ cdef class CGraphBackend(GenericGraphBackend): if v_int == -1: return True v = self.vertex_label(v_int) - cdef size_t n = 0 - for _ in self.depth_first_search(v, ignore_direction=True): + cdef set forbidden = set(forbidden_vertices) if forbidden_vertices else set() + while v in forbidden: + v_int = bitset_next(cg.active_vertices, v_int + 1) + if v_int == -1: + # The empty graph is connected. So the graph with only forbidden + # vertices also is + return True + v = self.vertex_label(v_int) + + cdef size_t n = len(forbidden) + for _ in self.depth_first_search(v, ignore_direction=True, + forbidden_vertices=forbidden): n += 1 return n == cg.num_verts @@ -4720,7 +4790,8 @@ cdef class Search_iterator: cdef in_neighbors def __init__(self, graph, v, direction=0, reverse=False, - ignore_direction=False, report_distance=False, edges=False): + ignore_direction=False, report_distance=False, edges=False, + forbidden_vertices=None): r""" Initialize an iterator for traversing a (di)graph. @@ -4762,11 +4833,16 @@ cdef class Search_iterator: Note that parameters ``edges`` and ``report_distance`` cannot be ``True`` simultaneously. + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search. The start vertex ``v`` cannot be in this set. + EXAMPLES:: sage: g = graphs.PetersenGraph() sage: list(g.breadth_first_search(0)) [0, 1, 4, 5, 2, 6, 3, 9, 7, 8] + sage: list(g.breadth_first_search(0, forbidden_vertices=[1, 2])) + [0, 4, 5, 3, 9, 7, 8, 6] TESTS: @@ -4805,10 +4881,19 @@ cdef class Search_iterator: bitset_set_first_n(self.seen, 0) cdef int v_id = self.graph.get_vertex(v) + cdef int u_id if v_id == -1: raise LookupError("vertex ({0}) is not a vertex of the graph".format(repr(v))) + if forbidden_vertices is not None: + for u in forbidden_vertices: + u_id = self.graph.get_vertex(u) + if u_id != -1: + if u_id == v_id: + raise ValueError(f"the start vertex is in the set of forbidden vertices") + bitset_add(self.seen, u_id) + if direction == 0: self.fifo.push(v_id) self.first_with_new_distance = -1 diff --git a/src/sage/graphs/base/meson.build b/src/sage/graphs/base/meson.build index 92e205ceb81..badf69f0478 100644 --- a/src/sage/graphs/base/meson.build +++ b/src/sage/graphs/base/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'boost_graph.pxd', 'c_graph.pxd', diff --git a/src/sage/graphs/base/sparse_graph.pyx b/src/sage/graphs/base/sparse_graph.pyx index a02541436ac..d82ba543669 100644 --- a/src/sage/graphs/base/sparse_graph.pyx +++ b/src/sage/graphs/base/sparse_graph.pyx @@ -1569,7 +1569,7 @@ cdef class SparseGraphBackend(CGraphBackend): # WARNING # If you modify this, you must keep in mind the documentation in the - # corresponding method in `generic_graph.py` in the method `edge_iterator`. + # corresponding method in ``generic_graph.py`` in the method ``edge_iterator``. # E.g. code assumes that you can use an iterator to relabel or delete arcs. r = self._cg._neighbors_BTNode_unsafe(v_int, out, neighbors, maxdegree) diff --git a/src/sage/graphs/base/static_sparse_backend.pyx b/src/sage/graphs/base/static_sparse_backend.pyx index e51fc238ac5..62bce67f5c0 100644 --- a/src/sage/graphs/base/static_sparse_backend.pyx +++ b/src/sage/graphs/base/static_sparse_backend.pyx @@ -557,9 +557,28 @@ cdef class StaticSparseBackend(CGraphBackend): """ return v in self._vertex_to_int + def add_vertex(self, object v): + r""" + Add a vertex to the graph. No way + + INPUT: + + - ``v`` -- a vertex (or not?) + + TESTS:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: g = StaticSparseBackend(graphs.PetersenGraph()) + sage: g.add_vertex(123) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) + """ + raise ValueError("graph is immutable; please change a copy instead (use function copy())") + cpdef add_edge(self, object u, object v, object l, bint directed): r""" - Set edge label. No way. + Add an edge to the graph. No way. TESTS:: @@ -572,9 +591,13 @@ cdef class StaticSparseBackend(CGraphBackend): """ raise ValueError("graph is immutable; please change a copy instead (use function copy())") - def add_edges(self, edges, directed): + def add_edges(self, edges, directed, remove_loops=False): r""" - Set edge label. No way. + Add edges to the graph. No way. + + INPUT: + + - ``edges`` -- a list of edges (or not?) TESTS:: @@ -589,7 +612,11 @@ cdef class StaticSparseBackend(CGraphBackend): def add_vertices(self, vertices): r""" - Set edge label. No way. + Add vertices to the graph. No way. + + INPUT: + + - ``vertices`` -- a list of vertices (or not?) TESTS:: @@ -602,15 +629,75 @@ cdef class StaticSparseBackend(CGraphBackend): """ raise ValueError("graph is immutable; please change a copy instead (use function copy())") - cpdef del_edge(self, object u, object v, object l, bint directed): + def del_vertex(self, object v): r""" - Set edge label. No way. + Delete a vertex from the graph. No way + + INPUT: + + - ``v`` -- a vertex (or not?) TESTS:: sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend sage: g = StaticSparseBackend(graphs.PetersenGraph()) - sage: g.set_edge_label(1,2,3,True) + sage: g.del_vertex(123) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) + + Check that :issue:`39270` is fixed:: + + sage: g.del_vertex('a') + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) + """ + raise ValueError("graph is immutable; please change a copy instead (use function copy())") + + def del_vertices(self, vertices): + r""" + Delete vertices from the graph. No way + + INPUT: + + - ``vertices`` -- a list of vertices (or not?) + + TESTS:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: g = StaticSparseBackend(graphs.PetersenGraph()) + sage: g.del_vertices([123, 234]) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) + """ + raise ValueError("graph is immutable; please change a copy instead (use function copy())") + + def del_edge(self, object u, object v, object l, bint directed): + r""" + Delete an edge of the graph. No way. + + TESTS:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: g = StaticSparseBackend(graphs.PetersenGraph()) + sage: g.del_edge(1,2,3,True) + Traceback (most recent call last): + ... + ValueError: graph is immutable; please change a copy instead (use function copy()) + """ + raise ValueError("graph is immutable; please change a copy instead (use function copy())") + + def del_edges(self, edges, directed): + r""" + Delete edges of the graph. No way. + + TESTS:: + + sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend + sage: g = StaticSparseBackend(graphs.PetersenGraph()) + sage: g.del_edges([[1,2,3]], True) Traceback (most recent call last): ... ValueError: graph is immutable; please change a copy instead (use function copy()) diff --git a/src/sage/graphs/bipartite_graph.py b/src/sage/graphs/bipartite_graph.py index e21ec47e9cf..8d766556d24 100644 --- a/src/sage/graphs/bipartite_graph.py +++ b/src/sage/graphs/bipartite_graph.py @@ -1070,7 +1070,6 @@ def add_edge(self, u, v=None, label=None): # add the edge Graph.add_edge(self, u, v, label) - return def add_edges(self, edges, loops=True): """ diff --git a/src/sage/graphs/centrality.pyx b/src/sage/graphs/centrality.pyx old mode 100755 new mode 100644 index e249046ae70..6a68eab6684 --- a/src/sage/graphs/centrality.pyx +++ b/src/sage/graphs/centrality.pyx @@ -131,7 +131,7 @@ cdef dict centrality_betweenness_C(G, numerical_type _, bint normalize=True): - ``G`` -- a graph - ``_`` -- this variable is ignored, only its type matters. If it is of type - `mpq_t` then computations are made on `Q`, if it is ``double`` the + ``mpq_t`` then computations are made on `Q`, if it is ``double`` the computations are made on ``double``. - ``normalize`` -- boolean (default: ``True``); whether to renormalize the diff --git a/src/sage/graphs/chrompoly.pyx b/src/sage/graphs/chrompoly.pyx index 17a9837041b..d0ca79b60b5 100644 --- a/src/sage/graphs/chrompoly.pyx +++ b/src/sage/graphs/chrompoly.pyx @@ -31,7 +31,7 @@ from memory_allocator cimport MemoryAllocator from sage.libs.gmp.mpz cimport * from sage.rings.integer_ring import ZZ from sage.rings.integer cimport Integer -from sage.rings.ring cimport Ring +from sage.rings.ring cimport CommutativeRing from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing @@ -436,7 +436,7 @@ def chromatic_polynomial_with_cache(G, cache=None): ... TypeError: parameter cache must be a dictionary or None """ - cdef Ring R = PolynomialRing(ZZ, "x", implementation="FLINT") + cdef CommutativeRing R = PolynomialRing(ZZ, "x", implementation="FLINT") cdef Polynomial_integer_dense_flint one = R.one() cdef Polynomial_integer_dense_flint zero = R.zero() cdef Polynomial_integer_dense_flint x = R.gen() diff --git a/src/sage/graphs/comparability.pyx b/src/sage/graphs/comparability.pyx index 05d5d3b5185..88a3314b3cc 100644 --- a/src/sage/graphs/comparability.pyx +++ b/src/sage/graphs/comparability.pyx @@ -15,12 +15,12 @@ The following methods are implemented in this module :widths: 30, 70 :delim: | - :meth:`~is_comparability_MILP` | Test whether the graph is a comparability graph (MILP) - :meth:`~greedy_is_comparability` | Test whether the graph is a comparability graph (greedy algorithm) - :meth:`~greedy_is_comparability_with_certificate` | Test whether the graph is a comparability graph and returns certificates (greedy algorithm) - :meth:`~is_comparability` | Test whether the graph is a comparability graph - :meth:`~is_permutation` | Test whether the graph is a permutation graph. - :meth:`~is_transitive` | Test whether the digraph is transitive. + :meth:`~is_comparability_MILP` | Check whether the graph is a comparability graph (MILP) + :meth:`~greedy_is_comparability` | Check whether the graph is a comparability graph (greedy algorithm) + :meth:`~greedy_is_comparability_with_certificate` | Check whether the graph is a comparability graph and returns certificates (greedy algorithm) + :meth:`~is_comparability` | Check whether the graph is a comparability graph + :meth:`~is_permutation` | Check whether the graph is a permutation graph. + :meth:`~is_transitive` | Check whether the digraph is transitive. Author: @@ -210,7 +210,7 @@ from copy import copy def greedy_is_comparability(g, no_certificate=False, equivalence_class=False): r""" - Test whether the graph is a comparability graph (greedy algorithm). + Check whether the graph is a comparability graph (greedy algorithm). This method only returns no-certificates. @@ -219,6 +219,8 @@ def greedy_is_comparability(g, no_certificate=False, equivalence_class=False): INPUT: + - ``g`` -- a graph + - ``no_certificate`` -- whether to return a *no*-certificate when the graph is not a comparability graph. This certificate is an odd cycle of edges, each of which implies the next. It is set to ``False`` by default. @@ -239,23 +241,33 @@ def greedy_is_comparability(g, no_certificate=False, equivalence_class=False): The Petersen Graph is not transitively orientable:: - sage: from sage.graphs.comparability import greedy_is_comparability as is_comparability - sage: g = graphs.PetersenGraph() - sage: is_comparability(g) - False - sage: is_comparability(g, no_certificate=True) - (False, [2, 1, 0, 4, 3, 2]) + sage: from sage.graphs.comparability import greedy_is_comparability as is_comparability + sage: g = graphs.PetersenGraph() + sage: is_comparability(g) + False + sage: is_comparability(g, no_certificate=True) + (False, [2, 1, 0, 4, 3, 2]) But the Bull graph is:: - sage: g = graphs.BullGraph() - sage: is_comparability(g) - True + sage: g = graphs.BullGraph() + sage: is_comparability(g) + True + + TESTS: + + Check that the method is working even when vertices are of incomparable + types:: + + sage: from sage.graphs.comparability import greedy_is_comparability + sage: G = Graph([('a', 1), (1, 2), (2, 3)]) + sage: greedy_is_comparability(G, equivalence_class=True) + (True, [('a', 1), (2, 1), (2, 3)]) """ cdef int i, j # Each vertex can partition its neighbors into equivalence classes - equivalence_classes = {} + cdef dict equivalence_classes = {} for v in g: equivalence_classes[v] = g.subgraph(vertices=g.neighbors(v)).complement().connected_components(sort=False) @@ -286,39 +298,43 @@ def greedy_is_comparability(g, no_certificate=False, equivalence_class=False): if isit: if equivalence_class: + # We use a mapping between vertices and integers to deal with + # vertices of different types + int_to_vertex = list(g) + vertex_to_int = {u: i for i, u in enumerate(int_to_vertex)} # Returning the largest equivalence class - cc = sorted(h.connected_components(sort=False), key=len)[-1] + cc = max(h.connected_components(sort=False), key=len) edges = [] for v, sid in cc: s = equivalence_classes[v][sid] # For each edge we pick the good orientations + vi = vertex_to_int[v] if certif[v, sid] == 1: - for vv in s: - edges.append((v, vv)) + edges.extend((vi, vertex_to_int[vv]) for vv in s) else: - for vv in s: - edges.append((vv, v)) + edges.extend((vertex_to_int[vv], vi) for vv in s) # We return the value but take care of removing edges that were # added twice. - return True, sorted(set(edges)) + edges = [(int_to_vertex[u], int_to_vertex[v]) for u, v in sorted(set(edges))] + return True, edges return True if no_certificate: - certif.append(certif[0]) cycle = [v for v, _ in certif] + cycle.append(cycle[0]) return False, cycle return False def greedy_is_comparability_with_certificate(g, certificate=False): r""" - Test whether the graph is a comparability graph and returns - certificates(greedy algorithm). + Check whether the graph is a comparability graph and returns + certificates (greedy algorithm). This method can return certificates of both *yes* and *no* answers. @@ -327,6 +343,8 @@ def greedy_is_comparability_with_certificate(g, certificate=False): INPUT: + - ``g`` -- a graph + - ``certificate`` -- boolean; whether to return a certificate. *Yes*-answers the certificate is a transitive orientation of `G`, and a *no* certificates is an odd cycle of sequentially forcing @@ -336,24 +354,34 @@ def greedy_is_comparability_with_certificate(g, certificate=False): The 5-cycle or the Petersen Graph are not transitively orientable:: - sage: from sage.graphs.comparability import greedy_is_comparability_with_certificate as is_comparability - sage: is_comparability(graphs.CycleGraph(5), certificate=True) - (False, [2, 1, 0, 4, 3, 2]) - sage: g = graphs.PetersenGraph() - sage: is_comparability(g) - False - sage: is_comparability(g, certificate=True) - (False, [2, 1, 0, 4, 3, 2]) + sage: from sage.graphs.comparability import greedy_is_comparability_with_certificate as is_comparability + sage: is_comparability(graphs.CycleGraph(5), certificate=True) + (False, [2, 1, 0, 4, 3, 2]) + sage: g = graphs.PetersenGraph() + sage: is_comparability(g) + False + sage: is_comparability(g, certificate=True) + (False, [2, 1, 0, 4, 3, 2]) But the Bull graph is:: - sage: g = graphs.BullGraph() - sage: is_comparability(g) - True - sage: is_comparability(g, certificate = True) - (True, Digraph on 5 vertices) - sage: is_comparability(g, certificate = True)[1].is_transitive() - True + sage: g = graphs.BullGraph() + sage: is_comparability(g) + True + sage: is_comparability(g, certificate = True) + (True, Digraph on 5 vertices) + sage: is_comparability(g, certificate = True)[1].is_transitive() + True + + TESTS: + + Check that the method is working even when vertices are of incomparable + types:: + + sage: from sage.graphs.comparability import greedy_is_comparability_with_certificate + sage: G = Graph([('a', 1), (1, 2), (2, 3)]) + sage: greedy_is_comparability_with_certificate(G, certificate=True) + (True, Digraph on 4 vertices) """ isit, certif = greedy_is_comparability(g, no_certificate=True, equivalence_class=True) if not isit: @@ -393,73 +421,70 @@ def greedy_is_comparability_with_certificate(g, certificate=False): def is_comparability_MILP(g, certificate=False, solver=None, verbose=0): r""" - Test whether the graph is a comparability graph (MILP). + Check whether the graph is a comparability graph (MILP). INPUT: - - ``certificate`` -- boolean; whether to return a certificate for - yes instances. This method cannot return negative certificates. + - ``g`` -- a graph - - ``solver`` -- (default: ``None``) specify a Linear Program (LP) solver to - be used. If set to ``None``, the default one is used. For more information - on LP solvers and which default solver is used, see the method - :meth:`~sage.numerical.mip.MixedIntegerLinearProgram.solve` of the class - :class:`~sage.numerical.mip.MixedIntegerLinearProgram`. + - ``certificate`` -- boolean (default: ``False``); whether to return a + certificate for yes instances. This method cannot return negative + certificates. + + - ``solver`` -- string (default: ``None``); specifies a Mixed Integer Linear + Programming (MILP) solver to be used. If set to ``None``, the default one + is used. For more information on MILP solvers and which default solver is + used, see the method :meth:`solve + ` of the class + :class:`MixedIntegerLinearProgram + `. - ``verbose`` -- integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet. - EXAMPLES: + EXAMPLES: The 5-cycle or the Petersen Graph are not transitively orientable:: - sage: from sage.graphs.comparability import is_comparability_MILP as is_comparability - sage: is_comparability(graphs.CycleGraph(5), certificate=True) # needs sage.numerical.mip - (False, None) - sage: g = graphs.PetersenGraph() - sage: is_comparability(g, certificate=True) # needs sage.numerical.mip - (False, None) + sage: from sage.graphs.comparability import is_comparability_MILP as is_comparability + sage: is_comparability(graphs.CycleGraph(5), certificate=True) # needs sage.numerical.mip + (False, None) + sage: g = graphs.PetersenGraph() + sage: is_comparability(g, certificate=True) # needs sage.numerical.mip + (False, None) But the Bull graph is:: - sage: g = graphs.BullGraph() - sage: is_comparability(g) # needs sage.numerical.mip - True - sage: is_comparability(g, certificate=True) # needs sage.numerical.mip - (True, Digraph on 5 vertices) - sage: is_comparability(g, certificate=True)[1].is_transitive() # needs sage.numerical.mip - True + sage: g = graphs.BullGraph() + sage: is_comparability(g) # needs sage.numerical.mip + True + sage: is_comparability(g, certificate=True) # needs sage.numerical.mip + (True, Digraph on 5 vertices) + sage: is_comparability(g, certificate=True)[1].is_transitive() # needs sage.numerical.mip + True """ from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException - cdef int i - p = MixedIntegerLinearProgram(solver=solver) o = p.new_variable(binary=True) for u, v in g.edge_iterator(labels=False): p.add_constraint(o[u, v] + o[v, u] == 1) + from itertools import combinations for u in g: - neighbors = g.neighbors(u) - - for i in range(len(neighbors)): - v = neighbors[i] - for j in range(i + 1, len(neighbors)): - vv = neighbors[j] - - # If there is an edge between v and vv, we must be - # sure it is in the good direction when v-u-vv is a - # directed path - if g.has_edge(v, vv): - p.add_constraint(o[u, v] + o[vv, u] - o[vv, v] <= 1) - p.add_constraint(o[u, vv] + o[v, u] - o[v, vv] <= 1) - - # If there is no edge, there are only two - # orientations possible (see the module's documentation - # about edges which imply each other) - else: - p.add_constraint(o[u, v] + o[vv, u] <= 1) - p.add_constraint(o[u, vv] + o[v, u] <= 1) + for v, vv in combinations(g.neighbors(u), 2): + + # If there is an edge between v and vv, we must be sure it is in the + # good direction when v-u-vv is a directed path + if g.has_edge(v, vv): + p.add_constraint(o[u, v] + o[vv, u] - o[vv, v] <= 1) + p.add_constraint(o[u, vv] + o[v, u] - o[v, vv] <= 1) + + # If there is no edge, there are only two orientations possible (see + # the module's documentation about edges which imply each other) + else: + p.add_constraint(o[u, v] + o[vv, u] <= 1) + p.add_constraint(o[u, vv] + o[v, u] <= 1) try: p.solve(log=verbose) @@ -494,11 +519,14 @@ def is_comparability_MILP(g, certificate=False, solver=None, verbose=0): def is_comparability(g, algorithm='greedy', certificate=False, check=True, solver=None, verbose=0): r""" - Test whether the graph is a comparability graph. + Check whether the graph is a comparability graph. INPUT: - - ``algorithm`` -- choose the implementation used to do the test + - ``g`` -- a graph + + - ``algorithm`` -- string (default: ``'greedy'``); choose the implementation + used to do the test - ``'greedy'`` -- a greedy algorithm (see the documentation of the :mod:`comparability module `) @@ -508,20 +536,22 @@ def is_comparability(g, algorithm='greedy', certificate=False, check=True, certificates ! When ``certificate = True``, negative certificates are always equal to ``None``. ``True`` certificates are valid, though. - - ``certificate`` -- boolean; whether to return a + - ``certificate`` -- boolean (default: ``False``); whether to return a certificate. *Yes*-answers the certificate is a transitive orientation of `G`, and a *no* certificates is an odd cycle of sequentially forcing edges. - - ``check`` -- boolean; whether to check that the + - ``check`` -- boolean (default: ``True``); whether to check that the yes-certificates are indeed transitive. As it is very quick compared to the rest of the operation, it is enabled by default. - - ``solver`` -- (default: ``None``) specify a Linear Program (LP) solver to - be used. If set to ``None``, the default one is used. For more information - on LP solvers and which default solver is used, see the method - :meth:`~sage.numerical.mip.MixedIntegerLinearProgram.solve` of the class - :class:`~sage.numerical.mip.MixedIntegerLinearProgram`. + - ``solver`` -- string (default: ``None``); specifies a Mixed Integer Linear + Programming (MILP) solver to be used. If set to ``None``, the default one + is used. For more information on MILP solvers and which default solver is + used, see the method :meth:`solve + ` of the class + :class:`MixedIntegerLinearProgram + `. - ``verbose`` -- integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet. @@ -537,15 +567,14 @@ def is_comparability(g, algorithm='greedy', certificate=False, check=True, TESTS: - Let us ensure that no exception is raised when we go over all - small graphs:: + Let us ensure that no exception is raised when we go over all small graphs:: sage: from sage.graphs.comparability import is_comparability sage: [len([g for g in graphs(i) if is_comparability(g, certificate=True)[0]]) for i in range(7)] [1, 1, 2, 4, 11, 33, 144] """ g._scream_if_not_simple() - if g.size() == 0: + if not g.size(): if certificate: from sage.graphs.digraph import DiGraph return True, DiGraph(g) @@ -568,8 +597,8 @@ def is_comparability(g, algorithm='greedy', certificate=False, check=True, if check and isit and (not certif.is_transitive()): raise ValueError("Looks like there is a bug somewhere. The " "algorithm thinks that the orientation is " - "transitive, but we just checked and it is not." - "Please report the bug on sage-devel, and give" + "transitive, but we just checked and it is not. " + "Please report the bug on sage-devel, and give " "us the graph that made this method fail !") return isit, certif @@ -578,15 +607,17 @@ def is_comparability(g, algorithm='greedy', certificate=False, check=True, def is_permutation(g, algorithm='greedy', certificate=False, check=True, solver=None, verbose=0): r""" - Test whether the graph is a permutation graph. + Check whether the graph is a permutation graph. For more information on permutation graphs, refer to the documentation of the :mod:`comparability module `. INPUT: - - ``algorithm`` -- choose the implementation used for the subcalls to - :meth:`is_comparability` + - ``g`` -- a graph + + - ``algorithm`` -- string (default: ``'greedy'``); choose the implementation + used for the subcalls to :meth:`is_comparability` - ``'greedy'`` -- a greedy algorithm (see the documentation of the :mod:`comparability module `) @@ -596,20 +627,23 @@ def is_permutation(g, algorithm='greedy', certificate=False, check=True, certificates ! When ``certificate = True``, negative certificates are always equal to ``None``. ``True`` certificates are valid, though. - - ``certificate`` -- boolean; whether to return a certificate for the - answer given. For ``True`` answers the certificate is a permutation, for - ``False`` answers it is a no-certificate for the test of comparability or - co-comparability. + - ``certificate`` -- boolean (default: ``False``); whether to return a + certificate for the answer given. For ``True`` answers the certificate is + a permutation, for ``False`` answers it is a no-certificate for the test + of comparability or co-comparability. - - ``check`` -- boolean; whether to check that the permutations returned - indeed create the expected Permutation graph. Pretty cheap compared to the - rest, hence a good investment. It is enabled by default. + - ``check`` -- boolean (default: ``True``); whether to check that the + permutations returned indeed create the expected Permutation graph. Pretty + cheap compared to the rest, hence a good investment. It is enabled by + default. - - ``solver`` -- (default: ``None``) specify a Linear Program (LP) solver to - be used. If set to ``None``, the default one is used. For more information - on LP solvers and which default solver is used, see the method - :meth:`~sage.numerical.mip.MixedIntegerLinearProgram.solve` of the class - :class:`~sage.numerical.mip.MixedIntegerLinearProgram`. + - ``solver`` -- string (default: ``None``); specifies a Mixed Integer Linear + Programming (MILP) solver to be used. If set to ``None``, the default one + is used. For more information on MILP solvers and which default solver is + used, see the method :meth:`solve + ` of the class + :class:`MixedIntegerLinearProgram + `. - ``verbose`` -- integer (default: 0); sets the level of verbosity. Set to 0 by default, which means quiet. @@ -644,33 +678,33 @@ def is_permutation(g, algorithm='greedy', certificate=False, check=True, Trying random permutations, first with the greedy algorithm:: - sage: from sage.graphs.comparability import is_permutation - sage: for i in range(20): - ....: p = Permutations(10).random_element() - ....: g1 = graphs.PermutationGraph(p) - ....: isit, certif = is_permutation(g1, certificate=True) - ....: if not isit: - ....: print("Something is wrong here !!") - ....: break - ....: g2 = graphs.PermutationGraph(*certif) - ....: if not g1.is_isomorphic(g2): - ....: print("Something is wrong here !!") - ....: break + sage: from sage.graphs.comparability import is_permutation + sage: for i in range(20): + ....: p = Permutations(10).random_element() + ....: g1 = graphs.PermutationGraph(p) + ....: isit, certif = is_permutation(g1, certificate=True) + ....: if not isit: + ....: print("Something is wrong here !!") + ....: break + ....: g2 = graphs.PermutationGraph(*certif) + ....: if not g1.is_isomorphic(g2): + ....: print("Something is wrong here !!") + ....: break Then with MILP:: - sage: from sage.graphs.comparability import is_permutation - sage: for i in range(20): # needs sage.numerical.mip - ....: p = Permutations(10).random_element() - ....: g1 = graphs.PermutationGraph(p) - ....: isit, certif = is_permutation(g1, algorithm='MILP', certificate=True) - ....: if not isit: - ....: print("Something is wrong here !!") - ....: break - ....: g2 = graphs.PermutationGraph(*certif) - ....: if not g1.is_isomorphic(g2): - ....: print("Something is wrong here !!") - ....: break + sage: from sage.graphs.comparability import is_permutation + sage: for i in range(20): # needs sage.numerical.mip + ....: p = Permutations(10).random_element() + ....: g1 = graphs.PermutationGraph(p) + ....: isit, certif = is_permutation(g1, algorithm='MILP', certificate=True) + ....: if not isit: + ....: print("Something is wrong here !!") + ....: break + ....: g2 = graphs.PermutationGraph(*certif) + ....: if not g1.is_isomorphic(g2): + ....: print("Something is wrong here !!") + ....: break """ if not certificate: # No certificate... A piece of cake diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index 05138c68f49..66f584fc466 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -75,7 +75,7 @@ from sage.misc.superseded import deprecation from sage.sets.disjoint_set cimport DisjointSet -def is_connected(G): +def is_connected(G, forbidden_vertices=None): """ Check whether the (di)graph is connected. @@ -85,6 +85,9 @@ def is_connected(G): - ``G`` -- the input graph + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search + .. SEEALSO:: - :meth:`~Graph.is_biconnected` @@ -100,6 +103,10 @@ def is_connected(G): sage: G.add_edge(0,3) sage: is_connected(G) True + sage: is_connected(G, forbidden_vertices=[3]) + False + sage: is_connected(G, forbidden_vertices=[1]) + True sage: D = DiGraph({0: [1, 2], 1: [2], 3: [4, 5], 4: [5]}) sage: is_connected(D) False @@ -128,14 +135,28 @@ def is_connected(G): return True try: - return G._backend.is_connected() + return G._backend.is_connected(forbidden_vertices=forbidden_vertices) except AttributeError: - v = next(G.vertex_iterator()) - conn_verts = list(G.depth_first_search(v, ignore_direction=True)) - return len(conn_verts) == G.num_verts() + # Search for a vertex in G that is not forbidden + forbidden = set(forbidden_vertices) if forbidden_vertices else set() + if forbidden: + for v in G: + if v not in forbidden: + break + else: + # The empty graph is connected, so the graph with only forbidden + # vertices is also connected + return True + else: + v = next(G.vertex_iterator()) + n = len(forbidden) + for _ in G.depth_first_search(v, ignore_direction=True, + forbidden_vertices=forbidden): + n += 1 + return n == G.num_verts() -def connected_components(G, sort=None, key=None): +def connected_components(G, sort=None, key=None, forbidden_vertices=None): """ Return the list of connected components. @@ -157,6 +178,9 @@ def connected_components(G, sort=None, key=None): vertex as its one argument and returns a value that can be used for comparisons in the sorting algorithm (we must have ``sort=True``) + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search + EXAMPLES:: sage: from sage.graphs.connectivity import connected_components @@ -171,6 +195,12 @@ def connected_components(G, sort=None, key=None): sage: connected_components(D, sort=True, key=lambda x: -x) [[3, 2, 1, 0], [6, 5, 4]] + Connected components in a graph with forbidden vertices:: + + sage: G = graphs.PathGraph(5) + sage: connected_components(G, sort=True, forbidden_vertices=[2]) + [[0, 1], [3, 4]] + TESTS: If ``G`` is not a Sage graph, an error is raised:: @@ -209,18 +239,19 @@ def connected_components(G, sort=None, key=None): if (not sort) and key: raise ValueError('sort keyword is False, yet a key function is given') - cdef set seen = set() + cdef set seen = set(forbidden_vertices) if forbidden_vertices else set() cdef list components = [] for v in G: if v not in seen: - c = connected_component_containing_vertex(G, v, sort=sort, key=key) + c = connected_component_containing_vertex(G, v, sort=sort, key=key, + forbidden_vertices=forbidden_vertices) seen.update(c) components.append(c) components.sort(key=lambda comp: -len(comp)) return components -def connected_components_number(G): +def connected_components_number(G, forbidden_vertices=None): """ Return the number of connected components. @@ -228,6 +259,9 @@ def connected_components_number(G): - ``G`` -- the input graph + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search + EXAMPLES:: sage: from sage.graphs.connectivity import connected_components_number @@ -239,6 +273,8 @@ def connected_components_number(G): sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: connected_components_number(D) 2 + sage: connected_components_number(D, forbidden_vertices=[1, 3]) + 3 TESTS: @@ -250,19 +286,29 @@ def connected_components_number(G): ... TypeError: the input must be a Sage graph """ - return len(connected_components(G, sort=False)) + return len(connected_components(G, sort=False, + forbidden_vertices=forbidden_vertices)) -def connected_components_subgraphs(G): +def connected_components_subgraphs(G, forbidden_vertices=None): """ Return a list of connected components as graph objects. + INPUT: + + - ``G`` -- the input graph + + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search + EXAMPLES:: sage: from sage.graphs.connectivity import connected_components_subgraphs sage: G = Graph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: L = connected_components_subgraphs(G) sage: graphs_list.show_graphs(L) # needs sage.plot + sage: L = connected_components_subgraphs(G, forbidden_vertices=[1, 3]) + sage: graphs_list.show_graphs(L) # needs sage.plot sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: L = connected_components_subgraphs(D) sage: graphs_list.show_graphs(L) # needs sage.plot @@ -283,10 +329,13 @@ def connected_components_subgraphs(G): if not isinstance(G, GenericGraph): raise TypeError("the input must be a Sage graph") - return [G.subgraph(c, inplace=False) for c in connected_components(G, sort=False)] + return [G.subgraph(c, inplace=False) + for c in connected_components(G, sort=False, + forbidden_vertices=forbidden_vertices)] -def connected_component_containing_vertex(G, vertex, sort=None, key=None): +def connected_component_containing_vertex(G, vertex, sort=None, key=None, + forbidden_vertices=None): """ Return a list of the vertices connected to vertex. @@ -294,7 +343,7 @@ def connected_component_containing_vertex(G, vertex, sort=None, key=None): - ``G`` -- the input graph - - ``v`` -- the vertex to search for + - ``vertex`` -- the vertex to search for - ``sort`` -- boolean (default: ``None``); if ``True``, vertices inside the component are sorted according to the default ordering @@ -307,6 +356,9 @@ def connected_component_containing_vertex(G, vertex, sort=None, key=None): vertex as its one argument and returns a value that can be used for comparisons in the sorting algorithm (we must have ``sort=True``) + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search. The start ``vertex`` cannot be in this set. + EXAMPLES:: sage: from sage.graphs.connectivity import connected_component_containing_vertex @@ -315,6 +367,8 @@ def connected_component_containing_vertex(G, vertex, sort=None, key=None): [0, 1, 2, 3] sage: G.connected_component_containing_vertex(0, sort=True) [0, 1, 2, 3] + sage: G.connected_component_containing_vertex(0, sort=True, forbidden_vertices=[1, 3]) + [0] sage: D = DiGraph({0: [1, 3], 1: [2], 2: [3], 4: [5, 6], 5: [6]}) sage: connected_component_containing_vertex(D, 0, sort=True) [0, 1, 2, 3] @@ -370,21 +424,30 @@ def connected_component_containing_vertex(G, vertex, sort=None, key=None): raise ValueError('sort keyword is False, yet a key function is given') try: - c = list(G._backend.depth_first_search(vertex, ignore_direction=True)) + c = list(G._backend.depth_first_search(vertex, ignore_direction=True, + forbidden_vertices=forbidden_vertices)) except AttributeError: - c = list(G.depth_first_search(vertex, ignore_direction=True)) + c = list(G.depth_first_search(vertex, ignore_direction=True, + forbidden_vertices=forbidden_vertices)) if sort: return sorted(c, key=key) return c -def connected_components_sizes(G): +def connected_components_sizes(G, forbidden_vertices=None): """ Return the sizes of the connected components as a list. The list is sorted from largest to lower values. + INPUT: + + - ``G`` -- the input graph + + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search + EXAMPLES:: sage: from sage.graphs.connectivity import connected_components_sizes @@ -400,6 +463,13 @@ def connected_components_sizes(G): [2, 1] [3] [3] + sage: G = graphs.PathGraph(5) + sage: G.connected_components_sizes() + [5] + sage: G.connected_components_sizes(forbidden_vertices=[1]) + [3, 1] + sage: G.connected_components_sizes(forbidden_vertices=[1, 3]) + [1, 1, 1] TESTS: @@ -416,7 +486,8 @@ def connected_components_sizes(G): raise TypeError("the input must be a Sage graph") # connected components are sorted from largest to smallest - return [len(cc) for cc in connected_components(G, sort=False)] + return [len(cc) for cc in connected_components(G, sort=False, + forbidden_vertices=forbidden_vertices)] def blocks_and_cut_vertices(G, algorithm='Tarjan_Boost', sort=False, key=None): diff --git a/src/sage/graphs/digraph_generators.py b/src/sage/graphs/digraph_generators.py index b374392163e..d484b948eb7 100644 --- a/src/sage/graphs/digraph_generators.py +++ b/src/sage/graphs/digraph_generators.py @@ -203,7 +203,7 @@ class DiGraphGenerators: 218 """ - def ButterflyGraph(self, n, vertices='strings'): + def ButterflyGraph(self, n, vertices='strings', immutable=False): r""" Return a `n`-dimensional butterfly graph. @@ -223,6 +223,9 @@ def ButterflyGraph(self, n, vertices='strings'): vertices are zero-one strings (default) or tuples over GF(2) (``vertices='vectors'``) + - ``immutable`` -- boolean (default: ``False``); whether to return + an immutable or mutable digraph. + EXAMPLES:: sage: digraphs.ButterflyGraph(2).edges(sort=True, labels=False) @@ -323,9 +326,10 @@ def ButterflyGraph(self, n, vertices='strings'): for x in range(n + 1): pos[v, x] = (dec * x, i) return DiGraph([pos.keys(), E], format='vertices_and_edges', pos=pos, - name="{}-dimensional Butterfly".format(n)) + name="{}-dimensional Butterfly".format(n), + immutable=immutable) - def Path(self, n): + def Path(self, n, immutable=False): r""" Return a directed path on `n` vertices. @@ -333,6 +337,9 @@ def Path(self, n): - ``n`` -- integer; number of vertices in the path + - ``immutable`` -- boolean (default: ``False``); whether to return + an immutable or mutable digraph. + EXAMPLES:: sage: g = digraphs.Path(5) @@ -343,15 +350,13 @@ def Path(self, n): sage: g.automorphism_group().cardinality() # needs sage.groups 1 """ - g = DiGraph(n, name='Path') - - if n: - g.add_path(list(range(n))) - + g = DiGraph([range(n), zip(range(n - 1), range(1, n))], + format='vertices_and_edges', name='Path', + immutable=immutable) g.set_pos({i: (i, 0) for i in range(n)}) return g - def StronglyRegular(self, n): + def StronglyRegular(self, n, immutable=False): r""" Return a Strongly Regular digraph with `n` vertices. @@ -362,6 +367,9 @@ def StronglyRegular(self, n): - ``n`` -- integer; the number of vertices of the digraph + - ``immutable`` -- boolean (default: ``False``); whether to return + an immutable or mutable digraph. + .. SEEALSO:: - :func:`sage.combinat.matrices.hadamard_matrix.skew_hadamard_matrix` @@ -397,15 +405,23 @@ def StronglyRegular(self, n): H = skew_hadamard_matrix(n + 1, skew_normalize=True) M = H[1:, 1:] M = (M + ones_matrix(n)) / 2 - identity_matrix(n) - return DiGraph(M, format='adjacency_matrix', name='Strongly regular digraph') + return DiGraph(M, format='adjacency_matrix', immutable=immutable, + name='Strongly regular digraph') - def Paley(self, q): + def Paley(self, q, immutable=False): r""" Return a Paley digraph on `q` vertices. Parameter `q` must be the power of a prime number and congruent to 3 mod 4. + INPUT: + + - ``q`` -- integer; the number of vertices of the digraph + + - ``immutable`` -- boolean (default: ``False``); whether to return + an immutable or mutable digraph. + .. SEEALSO:: - :wikipedia:`Paley_graph` @@ -448,13 +464,12 @@ def Paley(self, q): raise ValueError("parameter q must be a prime power") if not mod(q, 4) == 3: raise ValueError("parameter q must be congruent to 3 mod 4") - g = DiGraph([FiniteField(q, 'a'), - lambda i, j: (i != j) and (j - i).is_square()], - loops=False, - name="Paley digraph with parameter {}".format(q)) - return g + return DiGraph([FiniteField(q, 'a'), + lambda i, j: (i != j) and (j - i).is_square()], + format='rule', loops=False, immutable=immutable, + name="Paley digraph with parameter {}".format(q)) - def TransitiveTournament(self, n): + def TransitiveTournament(self, n, immutable=False): r""" Return a transitive tournament on `n` vertices. @@ -466,6 +481,9 @@ def TransitiveTournament(self, n): - ``n`` -- integer; number of vertices in the tournament + - ``immutable`` -- boolean (default: ``False``); whether to return + an immutable or mutable digraph. + EXAMPLES:: sage: g = digraphs.TransitiveTournament(5) @@ -490,17 +508,17 @@ def TransitiveTournament(self, n): ... ValueError: the number of vertices cannot be strictly negative """ - g = DiGraph(n, name="Transitive Tournament") - - for i in range(n - 1): - for j in range(i + 1, n): - g.add_edge(i, j) + if n < 0: + raise ValueError('the number of vertices cannot be strictly negative') + from itertools import combinations + g = DiGraph([range(n), combinations(range(n), 2)], + format='vertices_and_edges', immutable=immutable, + name="Transitive Tournament") g._circle_embedding(list(range(n))) - return g - def RandomTournament(self, n): + def RandomTournament(self, n, immutable=False): r""" Return a random tournament on `n` vertices. @@ -512,6 +530,9 @@ def RandomTournament(self, n): - ``n`` -- integer; number of vertices + - ``immutable`` -- boolean (default: ``False``); whether to return + an immutable or mutable digraph. + EXAMPLES:: sage: T = digraphs.RandomTournament(10); T @@ -533,15 +554,17 @@ def RandomTournament(self, n): - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.Complete` - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.RandomSemiComplete` """ - from sage.misc.prandom import random - g = DiGraph(n, name="Random Tournament") + if n < 0: + raise ValueError('the number of vertices cannot be strictly negative') - for i in range(n - 1): - for j in range(i + 1, n): - if random() <= .5: - g.add_edge(i, j) - else: - g.add_edge(j, i) + from itertools import combinations + from sage.misc.prandom import getrandbits + + bits = getrandbits(n * (n - 1) // 2) + edges = ((i, j) if (bits >> k) & 1 else (j, i) + for k, (i, j) in enumerate(combinations(range(n), 2))) + g = DiGraph([range(n), edges], format='vertices_and_edges', + immutable=immutable, name="Random Tournament") g._circle_embedding(list(range(n))) @@ -549,7 +572,8 @@ def RandomTournament(self, n): def tournaments_nauty(self, n, min_out_degree=None, max_out_degree=None, - strongly_connected=False, debug=False, options=""): + strongly_connected=False, debug=False, options="", + immutable=False): r""" Iterator over all tournaments on `n` vertices using Nauty. @@ -571,6 +595,9 @@ def tournaments_nauty(self, n, to Nauty's gentourng. See its documentation for more information : ``_. + - ``immutable`` -- boolean (default: ``False``); whether to return + immutable or mutable digraphs. + EXAMPLES:: sage: for g in digraphs.tournaments_nauty(4): @@ -612,22 +639,11 @@ def tournaments_nauty(self, n, if debug: yield sp.stderr.readline() - gen = sp.stdout - while True: - try: - s = bytes_to_str(next(gen)) - except StopIteration: - # Exhausted list of graphs from nauty geng - return - - G = DiGraph(n) + def edges(s): i = 0 j = 1 for b in s[:-1]: - if b == '0': - G.add_edge(i, j) - else: - G.add_edge(j, i) + yield (i, j) if b == '0' else (j, i) if j == n - 1: i += 1 @@ -635,9 +651,18 @@ def tournaments_nauty(self, n, else: j += 1 - yield G + gen = sp.stdout + while True: + try: + s = bytes_to_str(next(gen)) + except StopIteration: + # Exhausted list of graphs from nauty geng + return + + yield DiGraph([range(n), edges(s)], format='vertices_and_edges', + immutable=immutable) - def nauty_directg(self, graphs, options='', debug=False): + def nauty_directg(self, graphs, options='', debug=False, immutable=False): r""" Return an iterator yielding digraphs using nauty's ``directg`` program. @@ -669,6 +694,9 @@ def nauty_directg(self, graphs, options='', debug=False): - ``debug`` -- boolean (default: ``False``); if ``True`` ``directg`` standard error and standard output are displayed + - ``immutable`` -- boolean (default: ``False``); whether to return + immutable or mutable digraphs. + EXAMPLES:: sage: gen = graphs.nauty_geng("-c 3") @@ -759,9 +787,9 @@ def nauty_directg(self, graphs, options='', debug=False): # digraph6 specifications: # http://users.cecs.anu.edu.au/~bdm/data/formats.txt if line and line[0] == '&': - yield DiGraph(line[1:], format='dig6') + yield DiGraph(line[1:], format='dig6', immutable=immutable) - def nauty_posetg(self, options='', debug=False): + def nauty_posetg(self, options='', debug=False, immutable=False): r""" Return a generator which creates all posets using ``nauty``. @@ -782,6 +810,9 @@ def nauty_posetg(self, options='', debug=False): the program with some information on the arguments, while a line beginning with ">E" indicates an error with the input. + - ``immutable`` -- boolean (default: ``False``); whether to return + immutable or mutable posets. + The possible options, obtained as output of ``genposetg --help``:: n: the number of vertices, between 0 and 16 @@ -815,10 +846,9 @@ def nauty_posetg(self, options='', debug=False): except StopIteration: # Exhausted list of graphs from nauty genposetg return - G = DiGraph(s[1:-1], format='dig6') - yield G + yield DiGraph(s[1:-1], format='dig6', immutable=immutable) - def Complete(self, n, loops=False): + def Complete(self, n, loops=False, immutable=False): r""" Return the complete digraph on `n` vertices. @@ -829,6 +859,9 @@ def Complete(self, n, loops=False): - ``loops`` -- boolean (default: ``False``); whether to add loops or not, i.e., edges from `u` to itself + - ``immutable`` -- boolean (default: ``False``); whether to return + an immutable or mutable digraph. + .. SEEALSO:: - :meth:`~sage.graphs.digraph_generators.DiGraphGenerators.RandomSemiComplete` @@ -851,24 +884,32 @@ def Complete(self, n, loops=False): ... ValueError: the number of vertices cannot be strictly negative """ - G = DiGraph(n, name="Complete digraph" + (" with loops" if loops else ''), loops=loops) - - if loops: - G.add_edges((u, u) for u in range(n)) + if n < 0: + raise ValueError('the number of vertices cannot be strictly negative') - G.add_edges((u, v) for u in range(n) for v in range(n) if u != v) + edges = ((u, v) for u in range(n) for v in range(n) if u != v or loops) + G = DiGraph([range(n), edges], format='vertices_and_edges', + loops=loops, immutable=immutable, + name="Complete digraph" + (" with loops" if loops else '')) G._circle_embedding(list(range(n))) return G - def Circuit(self, n): + def Circuit(self, n, immutable=False): r""" Return the circuit on `n` vertices. The circuit is an oriented :meth:`~sage.graphs.graph_generators.GraphGenerators.CycleGraph`. + INPUT: + + - ``n`` -- integer; number of vertices + + - ``immutable`` -- boolean (default: ``False``); whether to return + an immutable or mutable digraph. + EXAMPLES: A circuit is the smallest strongly connected digraph:: @@ -877,19 +918,20 @@ def Circuit(self, n): sage: len(circuit.strongly_connected_components()) == 1 True """ - g = DiGraph(n, name='Circuit') - + if n < 0: + raise ValueError('the number of vertices cannot be strictly negative') if n == 1: - g.allow_loops(True) - g.add_edge(0, 0) - return g - elif n: - g.add_edges(zip(range(n - 1), range(1, n))) - g.add_edge(n - 1, 0) - g._circle_embedding(list(range(n))) + return DiGraph([(0, 0)], format='list_of_edges', loops=True, + immutable=immutable, name='Circuit') + + from itertools import chain + edges = zip(range(n), chain(range(1, n), [0])) + g = DiGraph([range(n), edges], format='vertices_and_edges', + immutable=immutable, name='Circuit') + g._circle_embedding(list(range(n))) return g - def Circulant(self, n, integers): + def Circulant(self, n, integers, immutable=False): r""" Return a circulant digraph on `n` vertices from a set of integers. @@ -904,6 +946,9 @@ def Circulant(self, n, integers): that there is an edge from `i` to `j` if and only if `(j-i) \pmod{n}` is an integer + - ``immutable`` -- boolean (default: ``False``); whether to return + an immutable or mutable digraph. + EXAMPLES: Construct and show the circulant graph [3, 5, 7], a digraph on 13 @@ -942,12 +987,11 @@ def Circulant(self, n, integers): if not i % n: loops = True - G = DiGraph(n, name="Circulant graph (" + str(integers) + ")", loops=loops) - + edges = ((v, (v + j) % n) for j in integers for v in range(n)) + G = DiGraph([range(n), edges], format='vertices_and_edges', + loops=loops, immutable=immutable, + name="Circulant graph (" + str(integers) + ")") G._circle_embedding(list(range(n))) - for v in range(n): - G.add_edges((v, (v + j) % n) for j in integers) - return G def DeBruijn(self, k, n, vertices='strings'): diff --git a/src/sage/graphs/domination.py b/src/sage/graphs/domination.py index 37c0ca5fb51..1803e91bb2c 100644 --- a/src/sage/graphs/domination.py +++ b/src/sage/graphs/domination.py @@ -475,6 +475,7 @@ def neighbors_iter(x): # Prevent finding twice a solution p.add_constraint(p.sum(b[u] for u in dom) <= best - 1) + def dominating_set(g, k=1, independent=False, total=False, connected=False, value_only=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" @@ -587,6 +588,7 @@ def dominating_set(g, k=1, independent=False, total=False, connected=False, valu # Enumeration of minimal dominating set as described in [BDHPR2019]_ # ============================================================================== + def _parent(G, dom, V_prev): r""" Return a subset of dom that is irredundant in ``V_prev``. diff --git a/src/sage/graphs/generators/meson.build b/src/sage/graphs/generators/meson.build index 44542f2631e..c98c2647c25 100644 --- a/src/sage/graphs/generators/meson.build +++ b/src/sage/graphs/generators/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'basic.py', 'chessboard.py', diff --git a/src/sage/graphs/generators/random.py b/src/sage/graphs/generators/random.py index 90cd8bceb93..821068763b3 100644 --- a/src/sage/graphs/generators/random.py +++ b/src/sage/graphs/generators/random.py @@ -1709,7 +1709,7 @@ def RandomKTree(n, k, seed=None): # A graph with treewidth 0 has no edges if k == 0: - g = Graph(n, name=f"Random 0-tree") + g = Graph(n, name="Random 0-tree") return g if n < k + 1: @@ -1803,7 +1803,7 @@ def RandomPartialKTree(n, k, x, seed=None): # A graph with treewidth 0 has no edges if k == 0: - g = Graph(n, name=f"Random partial 0-tree") + g = Graph(n, name="Random partial 0-tree") return g if n < k + 1: diff --git a/src/sage/graphs/generators/smallgraphs.py b/src/sage/graphs/generators/smallgraphs.py index d490eda7830..4fc69e689b6 100644 --- a/src/sage/graphs/generators/smallgraphs.py +++ b/src/sage/graphs/generators/smallgraphs.py @@ -4623,7 +4623,7 @@ def TricornGraph(): The Tricorn graph is obtained by splicing a complete graph `K_4` with the the triangular circular ladder graph `\overline{C_6}`. (Note that this - generates a unqiue graph as both of the graphs `K_4` and `\overline{C_6}` + generates a unique graph as both of the graphs `K_4` and `\overline{C_6}` are vertex-transitive). It is a nonsolid brick. This matching covered graph is one of the ten extremal cubic bricks. (A matching covered graph `G` is *extremal* if `\Phi(G) = dim(\mathcal{Lin}(G))`, where `\Phi(G)` denotes diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 101952109c3..bb804bcfd1b 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -5362,20 +5362,32 @@ def cycle_basis(self, output='vertex'): sage: g = graphs.PetersenGraph() sage: g.cycle_basis() # needs networkx, random (changes in networkx 3.2) - [[1, 6, 8, 5, 0], [4, 9, 6, 8, 5, 0], [7, 9, 6, 8, 5], - [4, 3, 8, 5, 0], [1, 2, 3, 8, 5, 0], [7, 2, 3, 8, 5]] + [[6, 8, 5, 7, 9], + [2, 3, 8, 5, 7], + [4, 3, 8, 5, 7, 9], + [4, 0, 5, 7, 9], + [2, 1, 0, 5, 7], + [6, 1, 0, 5, 7, 9]] One can also get the result as a list of lists of edges:: sage: g.cycle_basis(output='edge') # needs networkx, random (changes in networkx 3.2) - [[(1, 6, None), (6, 8, None), (8, 5, None), (5, 0, None), - (0, 1, None)], [(4, 9, None), (9, 6, None), (6, 8, None), - (8, 5, None), (5, 0, None), (0, 4, None)], [(7, 9, None), - (9, 6, None), (6, 8, None), (8, 5, None), (5, 7, None)], - [(4, 3, None), (3, 8, None), (8, 5, None), (5, 0, None), - (0, 4, None)], [(1, 2, None), (2, 3, None), (3, 8, None), - (8, 5, None), (5, 0, None), (0, 1, None)], [(7, 2, None), - (2, 3, None), (3, 8, None), (8, 5, None), (5, 7, None)]] + [[(6, 8, None), (8, 5, None), (5, 7, None), (7, 9, None), (9, 6, None)], + [(2, 3, None), (3, 8, None), (8, 5, None), (5, 7, None), (7, 2, None)], + [(4, 3, None), + (3, 8, None), + (8, 5, None), + (5, 7, None), + (7, 9, None), + (9, 4, None)], + [(4, 0, None), (0, 5, None), (5, 7, None), (7, 9, None), (9, 4, None)], + [(2, 1, None), (1, 0, None), (0, 5, None), (5, 7, None), (7, 2, None)], + [(6, 1, None), + (1, 0, None), + (0, 5, None), + (5, 7, None), + (7, 9, None), + (9, 6, None)]] Checking the given cycles are algebraically free:: @@ -5551,9 +5563,9 @@ def minimum_cycle_basis(self, algorithm=None, weight_function=None, by_weight=Fa sage: sorted(g.minimum_cycle_basis(by_weight=False)) [[1, 2, 3], [1, 3, 4], [5, 6, 7]] sage: sorted(g.minimum_cycle_basis(by_weight=True, algorithm='NetworkX')) # needs networkx, random (changes in networkx 3.2) - [[1, 2, 3], [1, 2, 3, 4], [5, 6, 7]] + [[2, 3, 1], [2, 3, 4, 1], [6, 7, 5]] sage: g.minimum_cycle_basis(by_weight=False, algorithm='NetworkX') # needs networkx, random (changes in networkx 3.2) - [[1, 2, 3], [1, 3, 4], [5, 6, 7]] + [[3, 4, 1], [2, 3, 1], [6, 7, 5]] :: @@ -5561,7 +5573,7 @@ def minimum_cycle_basis(self, algorithm=None, weight_function=None, by_weight=Fa sage: sorted(g.minimum_cycle_basis(by_weight=False)) [[1, 2, 3, 5], [3, 4, 5]] sage: sorted(g.minimum_cycle_basis(by_weight=False, algorithm='NetworkX')) # needs networkx, random (changes in networkx 3.2) - [[1, 2, 3, 5], [3, 4, 5]] + [[3, 4, 5], [5, 3, 2, 1]] TESTS:: @@ -17338,7 +17350,7 @@ def shortest_path(self, u, v, by_weight=False, algorithm=None, sage: D.shortest_path(4, 8, algorithm='Dijkstra_Bid_NetworkX') # needs networkx [4, 3, 2, 1, 8] sage: D.shortest_path(4, 9, algorithm='Dijkstra_Bid') - [4, 3, 19, 0, 10, 9] + [4, 3, 2, 1, 8, 9] sage: D.shortest_path(5, 5) [5] sage: D.delete_edges(D.edges_incident(13)) @@ -18854,7 +18866,8 @@ def average_distance(self, by_weight=False, algorithm=None, def breadth_first_search(self, start, ignore_direction=False, distance=None, neighbors=None, - report_distance=False, edges=False): + report_distance=False, edges=False, + forbidden_vertices=None): """ Return an iterator over the vertices in a breadth-first ordering. @@ -18889,6 +18902,9 @@ def breadth_first_search(self, start, ignore_direction=False, Note that parameters ``edges`` and ``report_distance`` cannot be ``True`` simultaneously. + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search. The start vertex ``v`` cannot be in this set. + .. SEEALSO:: - :meth:`breadth_first_search ` @@ -18977,6 +18993,12 @@ def breadth_first_search(self, start, ignore_direction=False, sage: list(D.breadth_first_search(1, edges=True)) [(1, 2), (1, 3), (2, 4)] + BFS in a graph with forbidden vertices:: + + sage: G = graphs.PetersenGraph() + sage: list(G.breadth_first_search(0, forbidden_vertices=[1, 2])) + [0, 4, 5, 3, 9, 7, 8, 6] + TESTS:: sage: D = DiGraph({1: [0], 2: [0]}) @@ -18995,6 +19017,18 @@ def breadth_first_search(self, start, ignore_direction=False, Traceback (most recent call last): ... ValueError: parameters edges and report_distance cannot be ``True`` simultaneously + sage: list(G.breadth_first_search(0, forbidden_vertices=[0])) + Traceback (most recent call last): + ... + ValueError: the start vertex is in the set of forbidden vertices + sage: list(G.breadth_first_search(0, forbidden_vertices=[0], distance=2)) + Traceback (most recent call last): + ... + ValueError: the start vertex is in the set of forbidden vertices + sage: list(G.breadth_first_search([0, 1], forbidden_vertices=[1])) + Traceback (most recent call last): + ... + ValueError: start vertex 1 is in the set of forbidden vertices """ from sage.rings.semirings.non_negative_integer_semiring import NN if (distance is not None and distance not in NN): @@ -19008,17 +19042,23 @@ def breadth_first_search(self, start, ignore_direction=False, and hasattr(self._backend, "breadth_first_search")): yield from self._backend.breadth_first_search( start, ignore_direction=ignore_direction, - report_distance=report_distance, edges=edges) + report_distance=report_distance, edges=edges, + forbidden_vertices=forbidden_vertices) else: if neighbors is None: if not self._directed or ignore_direction: neighbors = self.neighbor_iterator else: neighbors = self.neighbor_out_iterator - seen = set() + seen = set() if forbidden_vertices is None else set(forbidden_vertices) if isinstance(start, list): + for s in start: + if s in seen: + raise ValueError(f"start vertex {s} is in the set of forbidden vertices") queue = [(v, 0) for v in start] else: + if start in seen: + raise ValueError("the start vertex is in the set of forbidden vertices") queue = [(start, 0)] # Non-existing start vertex is detected later if distance > 0. @@ -19050,7 +19090,7 @@ def breadth_first_search(self, start, ignore_direction=False, yield w def depth_first_search(self, start, ignore_direction=False, - neighbors=None, edges=False): + neighbors=None, edges=False, forbidden_vertices=None): """ Return an iterator over the vertices in a depth-first ordering. @@ -19073,6 +19113,9 @@ def depth_first_search(self, start, ignore_direction=False, of the DFS tree in the order of visit or the vertices (default). Edges are directed in root to leaf orientation of the tree. + - ``forbidden_vertices`` -- list (default: ``None``); set of vertices to + avoid during the search. The start vertex ``v`` cannot be in this set. + .. SEEALSO:: - :meth:`breadth_first_search` @@ -19132,6 +19175,12 @@ def depth_first_search(self, start, ignore_direction=False, sage: list(D.depth_first_search(2, edges=True, ignore_direction=True)) [(2, 3), (3, 4), (2, 1), (1, 0)] + DFS in a graph with forbidden vertices:: + + sage: G = graphs.PetersenGraph() + sage: list(G.depth_first_search(0, forbidden_vertices=[1, 2])) + [0, 5, 8, 6, 9, 7, 4, 3] + TESTS:: sage: D = DiGraph({1: [0], 2: [0]}) @@ -19155,22 +19204,40 @@ def depth_first_search(self, start, ignore_direction=False, [1, 3, 6, 4, 5, 7, 2] sage: list(D.depth_first_search(1, ignore_direction=True, edges=True)) [(1, 3), (3, 6), (6, 7), (7, 5), (5, 4), (1, 2)] + sage: list(G.depth_first_search(0, forbidden_vertices=[0])) + Traceback (most recent call last): + ... + ValueError: the start vertex is in the set of forbidden vertices + sage: list(G.depth_first_search(0, forbidden_vertices=[0], edges=True)) + Traceback (most recent call last): + ... + ValueError: the start vertex is in the set of forbidden vertices + sage: list(G.depth_first_search([0, 1], forbidden_vertices=[1])) + Traceback (most recent call last): + ... + ValueError: start vertex 1 is in the set of forbidden vertices """ # Preferably use the Cython implementation if (neighbors is None and not isinstance(start, list) and hasattr(self._backend, "depth_first_search") and not edges): - yield from self._backend.depth_first_search(start, ignore_direction=ignore_direction) + yield from self._backend.depth_first_search(start, ignore_direction=ignore_direction, + forbidden_vertices=forbidden_vertices) else: if neighbors is None: if not self._directed or ignore_direction: neighbors = self.neighbor_iterator else: neighbors = self.neighbor_out_iterator - seen = set() + seen = set(forbidden_vertices) if forbidden_vertices else set() if isinstance(start, list): + for s in start: + if s in seen: + raise ValueError(f"start vertex {s} is in the set of forbidden vertices") # Reverse the list so that the initial vertices come out in the same order queue = [(v, 0) for v in reversed(start)] else: + if start in seen: + raise ValueError("the start vertex is in the set of forbidden vertices") queue = [(start, 0)] if not edges: @@ -23009,68 +23076,55 @@ def eigenvectors(self, laplacian=False): sage: P = graphs.PetersenGraph() sage: P.eigenvectors() # needs sage.modules sage.rings.number_field - [(3, [ - (1, 1, 1, 1, 1, 1, 1, 1, 1, 1) - ], 1), (-2, [ - (1, 0, 0, 0, -1, -1, -1, 0, 1, 1), - (0, 1, 0, 0, -1, 0, -2, -1, 1, 2), - (0, 0, 1, 0, -1, 1, -1, -2, 0, 2), - (0, 0, 0, 1, -1, 1, 0, -1, -1, 1) - ], 4), (1, [ - (1, 0, 0, 0, 0, 1, -1, 0, 0, -1), - (0, 1, 0, 0, 0, -1, 1, -1, 0, 0), - (0, 0, 1, 0, 0, 0, -1, 1, -1, 0), - (0, 0, 0, 1, 0, 0, 0, -1, 1, -1), - (0, 0, 0, 0, 1, -1, 0, 0, -1, 1) - ], 5)] + [(3, [(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)], 1), + (-2, + [(1, 0, 0, 0, -1, -1, -1, 0, 1, 1), + (0, 1, 0, 0, -1, 0, -2, -1, 1, 2), + (0, 0, 1, 0, -1, 1, -1, -2, 0, 2), + (0, 0, 0, 1, -1, 1, 0, -1, -1, 1)], + 4), + (1, + [(1, 0, 0, 0, 0, 1, -1, 0, 0, -1), + (0, 1, 0, 0, 0, -1, 1, -1, 0, 0), + (0, 0, 1, 0, 0, 0, -1, 1, -1, 0), + (0, 0, 0, 1, 0, 0, 0, -1, 1, -1), + (0, 0, 0, 0, 1, -1, 0, 0, -1, 1)], + 5)] Eigenspaces for the Laplacian should be identical since the Petersen graph is regular. However, since the output also contains the eigenvalues, the two outputs are slightly different:: sage: P.eigenvectors(laplacian=True) # needs sage.modules sage.rings.number_field - [(0, [ - (1, 1, 1, 1, 1, 1, 1, 1, 1, 1) - ], 1), (5, [ - (1, 0, 0, 0, -1, -1, -1, 0, 1, 1), - (0, 1, 0, 0, -1, 0, -2, -1, 1, 2), - (0, 0, 1, 0, -1, 1, -1, -2, 0, 2), - (0, 0, 0, 1, -1, 1, 0, -1, -1, 1) - ], 4), (2, [ - (1, 0, 0, 0, 0, 1, -1, 0, 0, -1), - (0, 1, 0, 0, 0, -1, 1, -1, 0, 0), - (0, 0, 1, 0, 0, 0, -1, 1, -1, 0), - (0, 0, 0, 1, 0, 0, 0, -1, 1, -1), - (0, 0, 0, 0, 1, -1, 0, 0, -1, 1) - ], 5)] + [(0, [(1, 1, 1, 1, 1, 1, 1, 1, 1, 1)], 1), + (5, + [(1, 0, 0, 0, -1, -1, -1, 0, 1, 1), + (0, 1, 0, 0, -1, 0, -2, -1, 1, 2), + (0, 0, 1, 0, -1, 1, -1, -2, 0, 2), + (0, 0, 0, 1, -1, 1, 0, -1, -1, 1)], + 4), + (2, + [(1, 0, 0, 0, 0, 1, -1, 0, 0, -1), + (0, 1, 0, 0, 0, -1, 1, -1, 0, 0), + (0, 0, 1, 0, 0, 0, -1, 1, -1, 0), + (0, 0, 0, 1, 0, 0, 0, -1, 1, -1), + (0, 0, 0, 0, 1, -1, 0, 0, -1, 1)], + 5)] :: sage: C = graphs.CycleGraph(8) sage: C.eigenvectors() # needs sage.modules sage.rings.number_field - [(2, - [ - (1, 1, 1, 1, 1, 1, 1, 1) - ], - 1), - (-2, - [ - (1, -1, 1, -1, 1, -1, 1, -1) - ], - 1), - (0, - [ - (1, 0, -1, 0, 1, 0, -1, 0), - (0, 1, 0, -1, 0, 1, 0, -1) - ], - 2), - (-1.4142135623..., - [(1, 0, -1, 1.4142135623..., -1, 0, 1, -1.4142135623...), - (0, 1, -1.4142135623..., 1, 0, -1, 1.4142135623..., -1)], + [(2, [(1, 1, 1, 1, 1, 1, 1, 1)], 1), + (-2, [(1, -1, 1, -1, 1, -1, 1, -1)], 1), + (0, [(1, 0, -1, 0, 1, 0, -1, 0), (0, 1, 0, -1, 0, 1, 0, -1)], 2), + (-1.414213562373095?, + [(1, 0, -1, 1.414213562373095?, -1, 0, 1, -1.414213562373095?), + (0, 1, -1.414213562373095?, 1, 0, -1, 1.414213562373095?, -1)], 2), - (1.4142135623..., - [(1, 0, -1, -1.4142135623..., -1, 0, 1, 1.4142135623...), - (0, 1, 1.4142135623..., 1, 0, -1, -1.4142135623..., -1)], + (1.414213562373095?, + [(1, 0, -1, -1.414213562373095?, -1, 0, 1, 1.414213562373095?), + (0, 1, 1.414213562373095?, 1, 0, -1, -1.414213562373095?, -1)], 2)] A digraph may have complex eigenvalues. Previously, the complex parts of @@ -23078,16 +23132,12 @@ def eigenvectors(self, laplacian=False): sage: T = DiGraph({0:[1], 1:[2], 2:[0]}) sage: T.eigenvectors() # needs sage.modules sage.rings.number_field - [(1, - [ - (1, 1, 1) - ], + [(1, [(1, 1, 1)], 1), + (-0.50000000000000000? - 0.866025403784439?*I, + [(1, -0.50000000000000000? - 0.866025403784439?*I, -0.50000000000000000? + 0.866025403784439?*I)], 1), - (-0.5000000000... - 0.8660254037...*I, - [(1, -0.5000000000... - 0.8660254037...*I, -0.5000000000... + 0.8660254037...*I)], - 1), - (-0.5000000000... + 0.8660254037...*I, - [(1, -0.5000000000... + 0.8660254037...*I, -0.5000000000... - 0.8660254037...*I)], + (-0.50000000000000000? + 0.866025403784439?*I, + [(1, -0.50000000000000000? + 0.866025403784439?*I, -0.50000000000000000? - 0.866025403784439?*I)], 1)] """ if laplacian: @@ -23119,48 +23169,50 @@ def eigenspaces(self, laplacian=False): sage: P = graphs.PetersenGraph() sage: P.eigenspaces() # needs sage.modules sage.rings.number_field - [ - (3, Vector space of degree 10 and dimension 1 over Rational Field - User basis matrix: - [1 1 1 1 1 1 1 1 1 1]), - (-2, Vector space of degree 10 and dimension 4 over Rational Field - User basis matrix: - [ 1 0 0 0 -1 -1 -1 0 1 1] - [ 0 1 0 0 -1 0 -2 -1 1 2] - [ 0 0 1 0 -1 1 -1 -2 0 2] - [ 0 0 0 1 -1 1 0 -1 -1 1]), - (1, Vector space of degree 10 and dimension 5 over Rational Field - User basis matrix: - [ 1 0 0 0 0 1 -1 0 0 -1] - [ 0 1 0 0 0 -1 1 -1 0 0] - [ 0 0 1 0 0 0 -1 1 -1 0] - [ 0 0 0 1 0 0 0 -1 1 -1] - [ 0 0 0 0 1 -1 0 0 -1 1]) - ] + [(3, + Vector space of degree 10 and dimension 1 over Rational Field + User basis matrix: + [1 1 1 1 1 1 1 1 1 1]), + (-2, + Vector space of degree 10 and dimension 4 over Rational Field + User basis matrix: + [ 1 0 0 0 -1 -1 -1 0 1 1] + [ 0 1 0 0 -1 0 -2 -1 1 2] + [ 0 0 1 0 -1 1 -1 -2 0 2] + [ 0 0 0 1 -1 1 0 -1 -1 1]), + (1, + Vector space of degree 10 and dimension 5 over Rational Field + User basis matrix: + [ 1 0 0 0 0 1 -1 0 0 -1] + [ 0 1 0 0 0 -1 1 -1 0 0] + [ 0 0 1 0 0 0 -1 1 -1 0] + [ 0 0 0 1 0 0 0 -1 1 -1] + [ 0 0 0 0 1 -1 0 0 -1 1])] Eigenspaces for the Laplacian should be identical since the Petersen graph is regular. However, since the output also contains the eigenvalues, the two outputs are slightly different:: sage: P.eigenspaces(laplacian=True) # needs sage.modules sage.rings.number_field - [ - (0, Vector space of degree 10 and dimension 1 over Rational Field - User basis matrix: - [1 1 1 1 1 1 1 1 1 1]), - (5, Vector space of degree 10 and dimension 4 over Rational Field - User basis matrix: - [ 1 0 0 0 -1 -1 -1 0 1 1] - [ 0 1 0 0 -1 0 -2 -1 1 2] - [ 0 0 1 0 -1 1 -1 -2 0 2] - [ 0 0 0 1 -1 1 0 -1 -1 1]), - (2, Vector space of degree 10 and dimension 5 over Rational Field - User basis matrix: - [ 1 0 0 0 0 1 -1 0 0 -1] - [ 0 1 0 0 0 -1 1 -1 0 0] - [ 0 0 1 0 0 0 -1 1 -1 0] - [ 0 0 0 1 0 0 0 -1 1 -1] - [ 0 0 0 0 1 -1 0 0 -1 1]) - ] + [(0, + Vector space of degree 10 and dimension 1 over Rational Field + User basis matrix: + [1 1 1 1 1 1 1 1 1 1]), + (5, + Vector space of degree 10 and dimension 4 over Rational Field + User basis matrix: + [ 1 0 0 0 -1 -1 -1 0 1 1] + [ 0 1 0 0 -1 0 -2 -1 1 2] + [ 0 0 1 0 -1 1 -1 -2 0 2] + [ 0 0 0 1 -1 1 0 -1 -1 1]), + (2, + Vector space of degree 10 and dimension 5 over Rational Field + User basis matrix: + [ 1 0 0 0 0 1 -1 0 0 -1] + [ 0 1 0 0 0 -1 1 -1 0 0] + [ 0 0 1 0 0 0 -1 1 -1 0] + [ 0 0 0 1 0 0 0 -1 1 -1] + [ 0 0 0 0 1 -1 0 0 -1 1])] Notice how one eigenspace below is described with a square root of 2. For the two possible values (positive and negative) there is a @@ -23168,38 +23220,38 @@ def eigenspaces(self, laplacian=False): sage: C = graphs.CycleGraph(8) sage: C.eigenspaces() # needs sage.modules sage.rings.number_field - [ - (2, Vector space of degree 8 and dimension 1 over Rational Field - User basis matrix: - [1 1 1 1 1 1 1 1]), - (-2, Vector space of degree 8 and dimension 1 over Rational Field - User basis matrix: - [ 1 -1 1 -1 1 -1 1 -1]), - (0, Vector space of degree 8 and dimension 2 over Rational Field - User basis matrix: - [ 1 0 -1 0 1 0 -1 0] - [ 0 1 0 -1 0 1 0 -1]), - (a3, Vector space of degree 8 and dimension 2 over - Number Field in a3 with defining polynomial x^2 - 2 - User basis matrix: - [ 1 0 -1 -a3 -1 0 1 a3] - [ 0 1 a3 1 0 -1 -a3 -1]) - ] + [(2, + Vector space of degree 8 and dimension 1 over Rational Field + User basis matrix: + [1 1 1 1 1 1 1 1]), + (-2, + Vector space of degree 8 and dimension 1 over Rational Field + User basis matrix: + [ 1 -1 1 -1 1 -1 1 -1]), + (0, + Vector space of degree 8 and dimension 2 over Rational Field + User basis matrix: + [ 1 0 -1 0 1 0 -1 0] + [ 0 1 0 -1 0 1 0 -1]), + (a3, + Vector space of degree 8 and dimension 2 over Number Field in a3 with defining polynomial x^2 - 2 + User basis matrix: + [ 1 0 -1 -a3 -1 0 1 a3] + [ 0 1 a3 1 0 -1 -a3 -1])] A digraph may have complex eigenvalues and eigenvectors. For a 3-cycle, we have:: sage: T = DiGraph({0: [1], 1: [2], 2: [0]}) sage: T.eigenspaces() # needs sage.modules sage.rings.number_field - [ - (1, Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [1 1 1]), - (a1, Vector space of degree 3 and dimension 1 over Number Field in a1 - with defining polynomial x^2 + x + 1 - User basis matrix: - [ 1 a1 -a1 - 1]) - ] + [(1, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [1 1 1]), + (a1, + Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 + x + 1 + User basis matrix: + [ 1 a1 -a1 - 1])] """ if laplacian: M = self.kirchhoff_matrix(vertices=list(self)) diff --git a/src/sage/graphs/graph.py b/src/sage/graphs/graph.py index 38714a483fe..7c640ee3c70 100644 --- a/src/sage/graphs/graph.py +++ b/src/sage/graphs/graph.py @@ -88,6 +88,8 @@ - Jean-Florent Raymond (2019-04): is_redundant, is_dominating, private_neighbors +- Cyril Bouvier (2024-11): is_module + Graph Format ------------ @@ -5821,12 +5823,6 @@ def cliques_maximal(self, algorithm='native'): implementation of the Bron and Kerbosch Algorithm [BK1973]_ - .. NOTE:: - - This method sorts its output before returning it. If you prefer to - save the extra time, you can call - :class:`sage.graphs.independent_sets.IndependentSets` directly. - .. NOTE:: Sage's implementation of the enumeration of *maximal* independent @@ -7181,8 +7177,109 @@ def cores(self, k=None, with_labels=False): return core return list(core.values()) - @doc_index("Leftovers") - def modular_decomposition(self, algorithm=None, style='tuple'): + @doc_index("Modules") + def is_module(self, vertices): + r""" + Check whether ``vertices`` is a module of ``self``. + + A subset `M` of the vertices of a graph is a module if for every + vertex `v` outside of `M`, either all vertices of `M` are neighbors of + `v` or all vertices of `M` are not neighbors of `v`. + + INPUT: + + - ``vertices`` -- iterable; a subset of vertices of ``self`` + + EXAMPLES: + + The whole graph, the empty set and singletons are trivial modules:: + + sage: G = graphs.PetersenGraph() + sage: G.is_module([]) + True + sage: G.is_module([G.random_vertex()]) + True + sage: G.is_module(G) + True + + Prime graphs only have trivial modules:: + + sage: G = graphs.PathGraph(5) + sage: G.is_prime() + True + sage: all(not G.is_module(S) for S in subsets(G) + ....: if len(S) > 1 and len(S) < G.order()) + True + + For edgeless graphs and complete graphs, all subsets are modules:: + + sage: G = Graph(5) + sage: all(G.is_module(S) for S in subsets(G)) + True + sage: G = graphs.CompleteGraph(5) + sage: all(G.is_module(S) for S in subsets(G)) + True + + The modules of a graph and of its complements are the same:: + + sage: G = graphs.TuranGraph(10, 3) + sage: G.is_module([0,1,2]) + True + sage: G.complement().is_module([0,1,2]) + True + sage: G.is_module([3,4,5]) + True + sage: G.complement().is_module([3,4,5]) + True + sage: G.is_module([2,3,4]) + False + sage: G.complement().is_module([2,3,4]) + False + sage: G.is_module([3,4,5,6,7,8,9]) + True + sage: G.complement().is_module([3,4,5,6,7,8,9]) + True + + Elements of ``vertices`` must be in ``self``:: + + sage: G = graphs.PetersenGraph() + sage: G.is_module(['Terry']) + Traceback (most recent call last): + ... + LookupError: vertex (Terry) is not a vertex of the graph + sage: G.is_module([1, 'Graham']) + Traceback (most recent call last): + ... + LookupError: vertex (Graham) is not a vertex of the graph + """ + M = set(vertices) + + for v in M: + if v not in self: + raise LookupError(f"vertex ({v}) is not a vertex of the graph") + + if len(M) <= 1 or len(M) == self.order(): + return True + + N = None # will contains the neighborhood of M + for v in M: + if N is None: + # first iteration, the neighborhood N must be computed + N = {u for u in self.neighbor_iterator(v) if u not in M} + else: + # check that the neighborhood of v is N + n = 0 + for u in self.neighbor_iterator(v): + if u not in M: + n += 1 + if u not in N: + return False # u is a splitter + if n != len(N): + return False + return True + + @doc_index("Modules") + def modular_decomposition(self, algorithm=None, style="tuple"): r""" Return the modular decomposition of the current graph. @@ -7190,11 +7287,21 @@ def modular_decomposition(self, algorithm=None, style='tuple'): vertex outside the module is either connected to all members of the module or to none of them. Every graph that has a nontrivial module can be partitioned into modules, and the increasingly fine partitions into - modules form a tree. The ``modular_decomposition`` function returns - that tree, using an `O(n^3)` algorithm of [HM1979]_. + modules form a tree. The ``modular_decomposition`` method returns + that tree. INPUT: + - ``algorithm`` -- string (default: ``None``); the algorithm to use + among: + + - ``None`` or ``'corneil_habib_paul_tedder'`` -- will use the + Corneil-Habib-Paul-Tedder algorithm from [TCHP2008]_, its complexity + is linear in the number of vertices and edges. + + - ``'habib_maurer'`` -- will use the Habib-Maurer algorithm from + [HM1979]_, its complexity is cubic in the number of vertices. + - ``style`` -- string (default: ``'tuple'``); specifies the output format: @@ -7204,16 +7311,10 @@ def modular_decomposition(self, algorithm=None, style='tuple'): OUTPUT: - A pair of two values (recursively encoding the decomposition) : - - * The type of the current module : - - * ``'PARALLEL'`` - * ``'PRIME'`` - * ``'SERIES'`` - - * The list of submodules (as list of pairs ``(type, list)``, - recursively...) or the vertex's name if the module is a singleton. + The modular decomposition tree, either as nested tuples (if + ``style='tuple'``) or as an object of + :class:`~sage.combinat.rooted_tree.LabelledRootedTree` (if + ``style='tree'``) Crash course on modular decomposition: @@ -7266,7 +7367,19 @@ def modular_decomposition(self, algorithm=None, style='tuple'): The Petersen Graph too:: sage: graphs.PetersenGraph().modular_decomposition() - (PRIME, [1, 4, 5, 0, 2, 6, 3, 7, 8, 9]) + (PRIME, [1, 4, 5, 0, 6, 2, 3, 9, 7, 8]) + + Graph from the :wikipedia:`Modular_decomposition`:: + + sage: G = Graph('Jv\\zoKF@wN?', format='graph6') + sage: G.relabel([1..11]) + sage: G.modular_decomposition() + (PRIME, + [(SERIES, [4, (PARALLEL, [2, 3])]), + 1, + 5, + (PARALLEL, [6, 7]), + (SERIES, [(PARALLEL, [10, 11]), 9, 8])]) This a clique on 5 vertices with 2 pendant edges, though, has a more interesting decomposition:: @@ -7275,14 +7388,20 @@ def modular_decomposition(self, algorithm=None, style='tuple'): sage: g.add_edge(0,5) sage: g.add_edge(0,6) sage: g.modular_decomposition() - (SERIES, [(PARALLEL, [(SERIES, [1, 2, 3, 4]), 5, 6]), 0]) + (SERIES, [(PARALLEL, [(SERIES, [3, 4, 2, 1]), 5, 6]), 0]) + + Turán graphs are co-graphs:: + + sage: graphs.TuranGraph(11, 3).modular_decomposition() + (SERIES, + [(PARALLEL, [7, 8, 9, 10]), (PARALLEL, [3, 4, 5, 6]), (PARALLEL, [0, 1, 2])]) We can choose output to be a :class:`~sage.combinat.rooted_tree.LabelledRootedTree`:: sage: g.modular_decomposition(style='tree') SERIES[0[], PARALLEL[5[], 6[], SERIES[1[], 2[], 3[], 4[]]]] - sage: ascii_art(g.modular_decomposition(style='tree')) + sage: ascii_art(g.modular_decomposition(algorithm="habib_maurer",style='tree')) __SERIES / / 0 ___PARALLEL @@ -7293,7 +7412,9 @@ def modular_decomposition(self, algorithm=None, style='tuple'): ALGORITHM: - This function uses the algorithm of M. Habib and M. Maurer [HM1979]_. + This function can use either the algorithm of D. Corneil, M. Habib, C. + Paul and M. Tedder [TCHP2008]_ or the algorithm of M. Habib and M. + Maurer [HM1979]_. .. SEEALSO:: @@ -7301,10 +7422,16 @@ def modular_decomposition(self, algorithm=None, style='tuple'): - :class:`~sage.combinat.rooted_tree.LabelledRootedTree`. + - :func:`~sage.graphs.graph_decompositions.modular_decomposition.corneil_habib_paul_tedder_algorithm` + + - :func:`~sage.graphs.graph_decompositions.modular_decomposition.habib_maurer_algorithm` + .. NOTE:: - A buggy implementation of linear time algorithm from [TCHP2008]_ was - removed in Sage 9.7, see :issue:`25872`. + A buggy implementation of the linear time algorithm from [TCHP2008]_ + was removed in Sage 9.7, see :issue:`25872`. A new implementation + was reintroduced in Sage 10.6 after some corrections to the original + algorithm, see :issue:`39038`. TESTS: @@ -7343,41 +7470,33 @@ def modular_decomposition(self, algorithm=None, style='tuple'): sage: G2 = Graph('F@Nfg') sage: G1.is_isomorphic(G2) True - sage: G1.modular_decomposition() + sage: G1.modular_decomposition(algorithm="habib_maurer") (PRIME, [1, 2, 5, 6, 0, (PARALLEL, [3, 4])]) - sage: G2.modular_decomposition() + sage: G2.modular_decomposition(algorithm="habib_maurer") (PRIME, [5, 6, 3, 4, 2, (PARALLEL, [0, 1])]) + sage: G1.modular_decomposition(algorithm="corneil_habib_paul_tedder") + (PRIME, [6, 5, 1, 2, 0, (PARALLEL, [3, 4])]) + sage: G2.modular_decomposition(algorithm="corneil_habib_paul_tedder") + (PRIME, [6, 5, (PARALLEL, [0, 1]), 2, 3, 4]) Check that :issue:`37631` is fixed:: sage: G = Graph('GxJEE?') - sage: G.modular_decomposition(style='tree') + sage: G.modular_decomposition(algorithm="habib_maurer",style='tree') PRIME[2[], SERIES[0[], 1[]], PARALLEL[3[], 4[]], PARALLEL[5[], 6[], 7[]]] """ - from sage.graphs.graph_decompositions.modular_decomposition import (NodeType, - habib_maurer_algorithm, - create_prime_node, - create_normal_node) - - if algorithm is not None: - from sage.misc.superseded import deprecation - deprecation(25872, "algorithm=... parameter is obsolete and has no effect.") - self._scream_if_not_simple() + from sage.graphs.graph_decompositions.modular_decomposition import \ + modular_decomposition - if not self.order(): - D = None - elif self.order() == 1: - D = create_normal_node(next(self.vertex_iterator())) - else: - D = habib_maurer_algorithm(self) + D = modular_decomposition(self, algorithm=algorithm) if style == 'tuple': - if D is None: + if D.is_empty(): return tuple() def relabel(x): - if x.node_type == NodeType.NORMAL: + if x.is_leaf(): return x.children[0] return x.node_type, [relabel(y) for y in x.children] @@ -7385,11 +7504,11 @@ def relabel(x): elif style == 'tree': from sage.combinat.rooted_tree import LabelledRootedTree - if D is None: + if D.is_empty(): return LabelledRootedTree([]) def to_tree(x): - if x.node_type == NodeType.NORMAL: + if x.is_leaf(): return LabelledRootedTree([], label=x.children[0]) return LabelledRootedTree([to_tree(y) for y in x.children], label=x.node_type) @@ -7640,7 +7759,14 @@ def is_prime(self, algorithm=None): A graph is prime if all its modules are trivial (i.e. empty, all of the graph or singletons) -- see :meth:`modular_decomposition`. - Use the `O(n^3)` algorithm of [HM1979]_. + This method computes the modular decomposition tree using + :meth:`~sage.graphs.graph.Graph.modular_decomposition`. + + INPUT: + + - ``algorithm`` -- string (default: ``None``); the algorithm used to + compute the modular decomposition tree; the value is forwarded + directly to :meth:`~sage.graphs.graph.Graph.modular_decomposition`. EXAMPLES: @@ -7661,17 +7787,15 @@ def is_prime(self, algorithm=None): sage: graphs.EmptyGraph().is_prime() True """ - if algorithm is not None: - from sage.misc.superseded import deprecation - deprecation(25872, "algorithm=... parameter is obsolete and has no effect.") - from sage.graphs.graph_decompositions.modular_decomposition import NodeType + from sage.graphs.graph_decompositions.modular_decomposition import \ + modular_decomposition if self.order() <= 1: return True - D = self.modular_decomposition() + MD = modular_decomposition(self, algorithm=algorithm) - return D[0] == NodeType.PRIME and len(D[1]) == self.order() + return MD.is_prime() and len(MD.children) == self.order() @doc_index("Connectivity, orientations, trees") def gomory_hu_tree(self, algorithm=None, solver=None, verbose=0, diff --git a/src/sage/graphs/graph_decompositions/meson.build b/src/sage/graphs/graph_decompositions/meson.build index 0d9778ae2ba..913c682ebac 100644 --- a/src/sage/graphs/graph_decompositions/meson.build +++ b/src/sage/graphs/graph_decompositions/meson.build @@ -1,12 +1,18 @@ -tdlib = cc.find_library('tdlib', required: false, disabler: true) +# tdlib is a header-only library +if cc.has_header('treedec/combinations.hpp') + tdlib = declare_dependency() +else + tdlib = disabler() +endif # Cannot be found via pkg-config rw = cc.find_library('rw') py.install_sources( + '__init__.py', 'all.py', 'all__sagemath_tdlib.py', 'fast_digraph.pxd', - 'modular_decomposition.py', + 'modular_decomposition.pxd', 'rankwidth.pxd', 'slice_decomposition.pxd', 'tree_decomposition.pxd', @@ -38,6 +44,7 @@ endforeach extension_data_cpp = { 'clique_separators': files('clique_separators.pyx'), 'slice_decomposition' : files('slice_decomposition.pyx'), + 'modular_decomposition' : files('modular_decomposition.pyx'), } foreach name, pyx : extension_data_cpp diff --git a/src/sage/graphs/graph_decompositions/modular_decomposition.hpp b/src/sage/graphs/graph_decompositions/modular_decomposition.hpp new file mode 100644 index 00000000000..4b14b03c1bf --- /dev/null +++ b/src/sage/graphs/graph_decompositions/modular_decomposition.hpp @@ -0,0 +1,857 @@ +/* + * Copyright (C) 2024 Cyril Bouvier + * + * 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/ + */ + +/* + * This file contains inline implementations of utility structs, classes and + * functions used in the implementation of the modular decomposition method + * + * AUTHORS: + * + * - Cyril Bouvier (2024): code for second implementation of the linear time + * algorithm of D. Corneil, M. Habib, C. Paul and M. Tedder [TCHP2008]_ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Labels attached to nodes of a partitive forest. For the meaning of the + * different values, see algorithms 3 and 4 of [TCHP2008]_. + */ +enum class Label : uint8_t { + EMPTY = 0b00, + HOMOGENEOUS = 0b01, + BROKEN = 0b10, + DEAD = 0b11 +}; + +/* + * Flags attached to nodes of a partitive forest. For the meaning of the flag, + * see algorithms 3 and 4 of [TCHP2008]_. + */ +enum class Flag : uint8_t { + UNFLAGGED = 0b00, + FLAGGED = 0b01 +}; + +/* + * A node of a modular decomposition tree is either a leaf or an internal node. + * An internal node can be prime, series or parallel. + */ +enum class Type : uint8_t { + PRIME = 0, + SERIES = 1, + PARALLEL = 2, + LEAF = 3 +}; + +/* + * This struct is used to have a nice interface to the data describing a slice + * decomposition. The slice decomposition is needed by the algorithm that + * compute the modular decomposition. + */ +struct SDData { + /* + * Set the members of the struct; it is useful to initialized the struct + * from the output of the extended_lex_BFS method. + */ + void set_from_data(size_t lex_label_offset_arg, + const int* sigma_arg, + const size_t *xslice_len_arg, + const std::vector *lex_label_arg) { + lex_label_offset = lex_label_offset_arg; + sigma = sigma_arg; + xslice_len = xslice_len_arg; + lex_label = lex_label_arg; + } + + /* + * Set the members of the struct to represent the subslice of sd starting at + * the given offset. + */ + void set_to_subslice(const SDData &sd, size_t offset) { + lex_label_offset = sd.lex_label[offset].size(); + sigma = sd.sigma + offset; + xslice_len = sd.xslice_len + offset; + lex_label = sd.lex_label + offset; + } + + /* + * Return the number of lexicographic labels of the ith vertex of the slice + * decomposition. + */ + size_t lex_label_size(size_t i) const { + if (lex_label[i].size() <= lex_label_offset) { + return 0; + } else { + return lex_label[i].size() - lex_label_offset; + } + } + + /* + * Return the pointer to the lexicographic labels of the ith vertex of the + * slice decomposition. + */ + const int * lex_label_ptr(size_t i) const { + if (lex_label[i].size() <= lex_label_offset) { + return nullptr; + } else { + return lex_label[i].data() + lex_label_offset; + } + } + + /* Return the index of the first slice (always 1). */ + size_t first_slice_index() const { + return 1; + } + + /* Return the index of the slice following the one starting at idx. */ + size_t next_slice_index(size_t idx) const { + return idx + xslice_len[idx]; + } + + /* Return the number of vertices in the slice decomposition. */ + size_t size() const { + return xslice_len[0]; + } + + /* + * Check whether the pivot has any neighbor (i.e., the first slice has no + * lexicographic labels). + */ + bool is_pivot_isolated () const { + return lex_label[1].size() <= lex_label_offset; + } + + size_t lex_label_offset; + const int *sigma; + const size_t *xslice_len; + const std::vector *lex_label; +}; + +/* + * This struct represents a node of a modular decomposition tree. It contains a + * pointer to its parent (or nullptr for the root), a list of children (must be + * empty for leaf) and a type (from the enum Type). + * A leaf of a modular decomposition tree corresponds to a vertex of the graph. + * The id of the vertex is stored in the vertex attribute of the struct. For + * internal nodes, the vertex attribute is used to store the id of any vertex + * belonging to the corresponding module. + * The attributes label, flag, slice, cc_tag are used by the different parts of + * the algorithm that computes the modular decomposition tree. + */ +struct md_tree_node { + /* ctor for non-leaf node */ + md_tree_node(Type type, Label label, Flag flag) + : parent(nullptr), vertex(INT_MAX), type(type), + label(label), flag(flag), + slice(SIZE_MAX), cc_tag(SIZE_MAX) { + } + + /* ctor for leaf */ + md_tree_node(int vertex) + : parent(nullptr), vertex(vertex), type(Type::LEAF), + label(Label::EMPTY), flag(Flag::UNFLAGGED), + slice(SIZE_MAX), cc_tag(SIZE_MAX) { + } + + /* ctor for non-leaf node, with default label and flag. */ + md_tree_node(Type type) + : md_tree_node(type, Label::EMPTY, Flag::UNFLAGGED) { + } + + /* check whether the node is a leaf. */ + bool is_leaf() const { + return type == Type::LEAF; + } + + /* check whether the node is prime. */ + bool is_prime() const { + return type == Type::PRIME; + } + + /* check whether the node is series. */ + bool is_series() const { + return type == Type::SERIES; + } + + /* check whether the node is parallel. */ + bool is_parallel() const { + return type == Type::PARALLEL; + } + + /* check whether the node is degenerate (i.e., series or parallel). */ + bool is_degenerate() const { + return type == Type::SERIES || type == Type::PARALLEL; + } + + /* + * The following methods are used to check the different possible status of + * the label of the node + */ + bool is_empty() const { + return label == Label::EMPTY; + } + + bool is_homogeneous() const { + return label == Label::HOMOGENEOUS; + } + + bool is_homogeneous_or_empty() const { + return !(static_cast(label) >> 1U); + } + + bool is_broken() const { + return label == Label::BROKEN; + } + + bool is_dead() const { + return label == Label::DEAD; + } + + bool is_dead_or_broken() const { + return static_cast(label) >> 1U; + } + + /* add the node c at the beginning of the list of children. */ + void prepend_new_child(md_tree_node *c) { + c->parent = this; + if (children.empty()) { + vertex = c->vertex; + } + children.push_front(c); + } + + /* add the node c at the end of the list of children. */ + void append_new_child(md_tree_node *c) { + c->parent = this; + if (children.empty()) { + vertex = c->vertex; + } + children.push_back(c); + } + + /* + * "Stole" the children from the node n and add them at the end of the list + * of children. ("stole" here means that at the end of this method, the list + * of children of n will be empty). + */ + void append_stolen_children_from(md_tree_node *n) { + if (!n->children.empty()) { + for (md_tree_node *c: n->children) { + c->parent = this; + } + if (children.empty()) { + vertex = n->children.front()->vertex; + } + children.splice(children.end(), n->children); + } + } + + /* Set the label and flag for all nodes of the tree. */ + void set_label_and_flag_recursively(Label l, Flag f) { + label = l; + flag = f; + for (md_tree_node *c: children) { + c->set_label_and_flag_recursively(l, f); + } + } + + md_tree_node *parent; + std::list children; + int vertex; + Type type; + Label label; + Flag flag; + size_t slice; + size_t cc_tag; +}; + +/* A forest is a list of tree */ +using md_forest = std::list; + +/* + * This struct is used to gather data structures needed by the different parts + * of the algorithm computing the modular decomposition tree. It is created + * at the beginning of the algorithm and pass along to any function that needs + * it. The hope is that it will reduce the number of allocations/deallocations + * because the number of creations and destructions of objects will be reduced. + */ +struct ScratchData { + /* + * Sub structure containing objects needed by the implementation of + * algorithms 3 and 4 of [TCHP2008]_. + */ + struct MDSequences { + std::unordered_map leaves; + std::unordered_set Marked; + std::unordered_set Full; + std::deque Explore; + }; + + /* + * Sub structure containing objects needed by the implementation of + * algorithms 5 and 6 of [TCHP2008]_. + */ + struct Clusters { + /* Assumes i < p < j where p is the index of the "cluster" {x}. */ + bool are_clusters_non_adjacent(size_t i, size_t j) const { + size_t sj = clusters[j].front()->slice; + auto e = std::make_pair(0, sj); + for (const md_tree_node *mi: clusters[i]) { + e.first = mi->vertex; + auto it = module_slice_adjacency.find(e); + if (it != module_slice_adjacency.end()) { + return false; + } + } + return true; + } + + struct pair_hash { + inline size_t operator()(const std::pair &v) const { + return ((size_t) v.first)*31+v.second; + } + }; + + std::vector> clusters; + /* adjacency list between a module (represented using the corresponding + * .vertex from the root node) and a slice. + */ + std::unordered_set, pair_hash> module_slice_adjacency; + std::vector Left; + std::vector Right; + std::unordered_map cluster_of_v; + }; + + /* Allocate the node corresponding to the vertex, and add it to the map */ + md_tree_node *new_leaf(int vertex) { + return mdseq.leaves[vertex] = new md_tree_node(vertex); + } + + MDSequences mdseq; + Clusters clusters; +}; + +/* + * This function deallocate (using delete) the node n and all of its + * descendants. It is needed to deallocate the modular decomposition tree + * computed by the function corneil_habib_paul_tedder_inner. + */ +void dealloc_md_tree_nodes_recursively(md_tree_node *n) { + for (md_tree_node *c: n->children) { + dealloc_md_tree_nodes_recursively(c); + } + delete n; +} + +/* Preprocess the trees in the forest: set the label to empty and the flag to + * unflagged for all the nodes, and set the cc_tag needed to compute the cluster + * later. + */ +void md_forest_preprocess(md_forest &MDi) { + Type one_cc_type = Type::PARALLEL; /* only for first iteration */ + size_t s = 0; + for (md_tree_node *md: MDi) { + md->set_label_and_flag_recursively(Label::EMPTY, Flag::UNFLAGGED); + md->slice = s; + if (md->type == Type::PRIME || md->type == one_cc_type) { + md->cc_tag = 0; + } else { + md->cc_tag = SIZE_MAX; + size_t i = 0; + for (md_tree_node *c: md->children) { + c->cc_tag = i; + i++; + } + } + one_cc_type = Type::SERIES; + s += 1; + } +} + +/* + * This function set to BROKEN the ancestors of DEAD nodes and gather into one + * node the HOMOGENEOUS and EMPTY childrend of a broken and degenerate node. + * Corresponds to the end of algorithm 3 of [TCHP2008]_. + */ +void mark_partitive_forest_finish_inner_rec(md_tree_node *r) { + size_t nb = 0; /* number of HOMOGENEOUS or EMPTY children */ + + /* Do a postorder visit: so we first visit the children */ + for (md_tree_node *c: r->children) { + mark_partitive_forest_finish_inner_rec(c); + nb += c->is_homogeneous_or_empty(); + } + + if (r->is_dead_or_broken()) { + if (r->parent != nullptr && !(r->parent->is_dead())) { + /* if parent.label is not DEAD set it to BROKEN */ + r->parent->label = Label::BROKEN; + } + if (r->is_broken() && r->is_degenerate() && nb > 1) { + md_tree_node *newnode = new md_tree_node(r->type, Label::EMPTY, + Flag::UNFLAGGED); + + /* Iterate over the children to gather HOMOGENEOUS and EMPTY + * child under newnode + * */ + auto it = r->children.begin(); + while (it != r->children.end()) { + if ((*it)->is_homogeneous_or_empty()) { + newnode->append_new_child(*it); + it = r->children.erase(it); /* get iterator to next child */ + } else { + ++it; + } + + } + r->append_new_child(newnode); + } + } +} + +/* This is an implementation of algorithm 3 of [TCHP2008]_. */ +void md_forest_mark_partitive_forest(md_forest &MDi, const SDData &sd, + ScratchData::MDSequences &scratch) { + size_t i = sd.first_slice_index(); + i = sd.next_slice_index(i); /* skip first slice */ + scratch.Explore.clear(); + for (; i < sd.size(); i = sd.next_slice_index(i)) { + scratch.Marked.clear(); + scratch.Full.clear(); + + for (auto it = sd.lex_label[i].begin() + sd.lex_label_offset; + it != sd.lex_label[i].end() ; ++it) { + scratch.Explore.push_back(scratch.leaves.at(*it)); + } + + while (scratch.Explore.size() > 0) { + md_tree_node *n = scratch.Explore.front(); + scratch.Explore.pop_front(); + md_tree_node *p = n->parent; + scratch.Full.insert(n); + if (n->is_empty()) { + n->label = Label::HOMOGENEOUS; + } + if (p) { + scratch.Marked.insert(p); + /* if all children of p are Full, move p to Explore */ + bool b = true; + for (md_tree_node *c: p->children) { + if (scratch.Full.find(c) == scratch.Full.end()) { + b = false; + break; + } + } + if (b) { + scratch.Marked.erase(p); + scratch.Explore.push_back(p); + } + } + } + + for (md_tree_node *n: scratch.Marked) { + /* If n is SERIES or PARALLEL => gather children of n in Full below + * the same new node A (needed only if there are >= 2 such children) + * and the children of n not in Full below the same new node B + * (needed only if there is >= 2 such children). + */ + if (n->is_degenerate() && n->children.size() > 2) { + Type t = n->type; + md_tree_node *newnodes[2] = { + new md_tree_node(t, Label::HOMOGENEOUS, Flag::FLAGGED), + new md_tree_node(t, Label::EMPTY, Flag::UNFLAGGED) + }; + auto end = n->children.end(); + for (auto it = n->children.begin(); it != end; ++it){ + bool notFull = scratch.Full.find(*it) == scratch.Full.end(); + newnodes[notFull]->append_new_child(*it); + } + n->children.clear(); + for (size_t i = 0; i < 2; i++) { + if (newnodes[i]->children.size() == 1) { + n->append_new_child(newnodes[i]->children.front()); + } else { + n->append_new_child(newnodes[i]); + } + } + } + + if (n->label != Label::DEAD) { + n->label = Label::DEAD; + /* Set flag to * for children of n that are in Full */ + for (md_tree_node *c: n->children) { + if (scratch.Full.find(c) != scratch.Full.end()) { + c->flag = Flag::FLAGGED; + } + } + } + } + } + + for (md_tree_node *md: MDi) { + mark_partitive_forest_finish_inner_rec(md); + } +} + +/* This function is needed by md_forest_extract_and_sort. */ +void sort_broken_nodes_recursively(md_tree_node *n, + bool dead_and_broken_first) { + if (n->is_dead_or_broken()) { + /* If the label is not DEAD or BROKEN, no need to go deeper: they + * will not be any DEAD or BROKEN nodes. + */ + for (md_tree_node *c: n->children) { + sort_broken_nodes_recursively(c, dead_and_broken_first); + } + + if (n->is_broken()) { + /* if dead_and_broken_first is true + * => put DEAD and BROKEN children at the beginning + * if dead_and_broken_first is false + * => put EMPTY and HOMOGENEOUS children at the beginning + */ + auto b = n->children.begin(); + auto end = n->children.end(); + for (auto it = n->children.begin(); it != end; ++it) { + if (dead_and_broken_first == (*it)->is_dead_or_broken()) { + std::iter_swap(it, b); + ++b; + } + } + } + } +} + +/* This function is needed by md_forest_extract_and_sort. */ +void sort_dead_nodes_recursively(md_tree_node *n, bool flagged_first) { + if (n->is_dead_or_broken()) { + /* If the label is not DEAD or BROKEN, no need to go deeper: they + * will not be any DEAD or BROKEN nodes. + */ + for (md_tree_node *c: n->children) { + sort_dead_nodes_recursively(c, flagged_first); + } + + if (n->is_dead()) { + /* if flagged_first is true => put flagged children at the beginning + * if flagged_first is talse => put unflagged children at the beginning + */ + auto b = n->children.begin(); + auto end = n->children.end(); + for (auto it = n->children.begin(); it != end; ++it) { + if (flagged_first == ((*it)->flag == Flag::FLAGGED)) { + std::iter_swap(it, b); + ++b; + } + } + } + } +} + +/* This is an implementation of algorithm 4 of [TCHP2008]_. */ +void md_forest_extract_and_sort(md_forest &MDi) { + bool is_first_slice = true; + auto it = MDi.begin(); + while (it != MDi.end()) { + md_tree_node *md = *it; + /* sort children of DEAD nodes */ + sort_dead_nodes_recursively(md, is_first_slice); + /* sort children of BROKEN nodes */ + sort_broken_nodes_recursively(md, is_first_slice); + + /* remove DEAD and BROKEN nodes */ + auto it_delete = it; + ++it; + while (it_delete != it) { + md_tree_node *r = *it_delete; + if (r->is_dead_or_broken()) { + for (md_tree_node *c: r->children) { + /* propagate cc tag and slice, if set */ + c->cc_tag = r->cc_tag != SIZE_MAX ? r->cc_tag : c->cc_tag; + c->slice = r->slice != SIZE_MAX ? r->slice : c->slice; + c->parent = nullptr; + } + auto insert_it = MDi.erase(it_delete); + it_delete = r->children.begin(); + MDi.splice(insert_it, r->children); + delete r; + } else { + it_delete++; + } + } + + is_first_slice = false; + } +} + +/* + * This function gathers the trees of the forest in clusters. A cluster is a set + * of trees that belongs to the same slice and (co)connected components. + * It also computes the Left and Right of the clusters (see section 5.2 of + * [TCHP2008]_. + */ +void md_forest_clusters_computation(const md_forest &MDi, const SDData &sd, + ScratchData::Clusters &scratch) { + scratch.clusters.clear(); + scratch.cluster_of_v.clear(); + size_t prev_cc = SIZE_MAX, prev_slice = SIZE_MAX; + for (md_tree_node *n: MDi) { + size_t cc = n->cc_tag; + size_t slice = n->slice; + int v = n->vertex; /* a vertex belonging to the module */ + + if (cc == SIZE_MAX) { /* n is alone in the cluster */ + scratch.clusters.emplace_back(1, n); /* new cluster */ + } else { + if (cc != prev_cc || slice != prev_slice) { + scratch.clusters.emplace_back(); /* start new cluster */ + } + scratch.clusters.back().push_back(n); + } + + prev_cc = cc; + prev_slice = slice; + scratch.cluster_of_v[v] = scratch.clusters.size()-1; + } + + size_t p = scratch.cluster_of_v[sd.sigma[0]]; + size_t q = scratch.clusters.size(); + + /* Left and Right computation. + * Left(i) == i if i <= p + * Left(i) == Left(j) for p < i,j if clusters Ki and Kj in same slice + * Right(i) = p for 0 <= i <= p + * Also compute adjacency between modules and slices (except the first one). + */ + scratch.Left.clear(); + scratch.Right.clear(); + scratch.module_slice_adjacency.clear(); + scratch.Left.reserve(q); + scratch.Right.reserve(q); + for (size_t i = 0; i <= p; i++) { + scratch.Left.push_back(i); + } + scratch.Right.resize(p+1, p); /* Right[i] = p for 0 <= i <= p */ + for (size_t i = p+1; i < q; i++) { + scratch.Right.push_back(i); + } + for (size_t i = sd.first_slice_index(), s = 0, j = 0; i < sd.size(); + i = sd.next_slice_index(i), s++) { + size_t j0 = j; + /* Compute j, the highest index of a cluster of the current slice s */ + for (; j+1 < q && scratch.clusters[j+1].front()->slice == s; j++); + + if (s == 0) { /* nothing to do for the first slice */ + j += 1; /* skip "cluster" {x} */ + } else { + /* for Right and module_slice_adjacency: iterate over the + * lexicographic labels of the slice. + */ + for (auto it = sd.lex_label[i].begin() + sd.lex_label_offset; + it != sd.lex_label[i].end() ; ++it) { + auto c = scratch.cluster_of_v.find(*it); + if (c != scratch.cluster_of_v.end()) { + scratch.module_slice_adjacency.emplace(*it, s); + /* cluster j is adjacent to cluster containing c so Right of + * the cluster c is >= j + */ + scratch.Right[c->second] = j; + } + } + + /* for Left: find the cluster of the first non adjacent module */ + size_t lp; /* lp will be the Left for all clusters of the slice */ + for (lp = 0; lp < p; lp++) { + bool adj = true; + for (const md_tree_node *m: scratch.clusters[lp]) { + if (scratch.module_slice_adjacency.find(std::make_pair(m->vertex, s)) == scratch.module_slice_adjacency.end()) { + adj = false; + break; + } + } + if (!adj) { + break; + } + } + /* Left is lp for all clusters of the slice s */ + std::fill_n(std::back_inserter(scratch.Left), j-j0, lp); + } + } + +} + +/* This is an implementation of algorithms 5 and 6 of [TCHP2008]_. */ +md_tree_node *md_forest_parse_and_assemble(md_tree_node *root, size_t p, + const ScratchData::Clusters &scratch) { + size_t q = scratch.clusters.size(); + size_t l = p; + size_t r = p; + while (l > 0 || r+1 < q) { + Type t; + size_t i; + size_t lp, old_l = l; + size_t rp, old_r = r; + + if (r+1 == q || (l>0 && scratch.are_clusters_non_adjacent(l-1, r+1))) { + lp = l-1; + rp = r; + t = Type::SERIES; + } else { + lp = l; + rp = r+1; + t = Type::PARALLEL; + } + + while (lp < l || r < rp) { + if (lp < l) { + i = l = l-1; + } else { + i = r = r+1; + } + lp = std::min(lp, scratch.Left[i]); + rp = std::max(rp, scratch.Right[i]); + } + + t = (r-l)-(old_r-old_l) > 1 ? Type::PRIME : t; + md_tree_node *old_root = root; + root = new md_tree_node(t); + + for (size_t i = l; i <= r; i++) { + if (i == old_l) { /* add the previous root */ + root->append_new_child(old_root); + i = old_r; + } else { + for (md_tree_node *m: scratch.clusters[i]) { + if (t != Type::PRIME && m->type == t) { + root->append_stolen_children_from(m); + delete m; + } else { + root->append_new_child(m); + } + } + } + } + } + return root; +} + +/* This is the main function: it corresponds to algorithms 7 of [TCHP2008]_. */ +md_tree_node *corneil_habib_paul_tedder_inner_rec(const SDData &sd, + ScratchData &scratch) { + if (sd.size() == 0) { /* empty graph */ + return nullptr; + } + + SDData sub_sd; + std::list MDi; + int x = sd.sigma[0]; + + /* First create a new leaf for x */ + md_tree_node *root = scratch.new_leaf(x); + + if (sd.size() == 1) { /* graph with one vertex */ + return root; + } else if (sd.size() == 2) { /* graph with two vertices */ + int y = sd.sigma[1]; + /* root is SERIES if there is an edge between x and y, else PARALLEL */ + Type t = sd.is_pivot_isolated() ? Type::PARALLEL : Type::SERIES; + root = new md_tree_node(t); + root->append_new_child(scratch.mdseq.leaves[x]); + root->append_new_child(scratch.new_leaf(y)); + return root; + } + + /* Now it is known that the graph has more than two vertices */ + + /* Recursive calls on all the slices */ + size_t first_of_last_slice = 1; /* set to 1 to remove warning */ + for (size_t i = sd.first_slice_index(); i < sd.size(); + i = sd.next_slice_index(i)) { + first_of_last_slice = i; + sub_sd.set_to_subslice(sd, i); + md_tree_node *md = corneil_habib_paul_tedder_inner_rec(sub_sd, scratch); + MDi.push_back(md); + } + + if (sd.is_pivot_isolated()) { /* x is isolated (i.e., has no neighbor) */ + md_tree_node *md = MDi.front(); /* only one slice in this case */ + if (md->type == Type::PARALLEL) { + root = md; + } else { + root = new md_tree_node(Type::PARALLEL); + root->append_new_child(md); + } + root->prepend_new_child(scratch.mdseq.leaves[x]); + return root; + } + + /* Now, it is known that x has at least one neighbor, so the first slice + * contains the neighborhood of x. + * If G is not connected, the last slice is all the connected components + * that do not contains x, it should be treated separately: the tree + * corresponding to the last slice is removed from MDi and will be added + * back before the clusters computation. + */ + md_tree_node *last_md = nullptr; + if (sd.lex_label_size(first_of_last_slice) == 0) { /* not connected */ + last_md = MDi.back(); + last_md->slice = MDi.size()-1; /* remember the slice */ + MDi.pop_back(); + } + + /* Preprocessing of the sub md trees: + * - set the slice attribute + * - set the connected components tag (for clusters computation later) + * - set label to EMPTY and flag to UNFLAGGED on all nodes + */ + md_forest_preprocess(MDi); + + /* Add the pivot {x} in MDi after the first slice (= the neighbors of x) */ + MDi.insert(++MDi.begin(), root); + + /* Mark partitive forest */ + md_forest_mark_partitive_forest(MDi, sd, scratch.mdseq); + + /* Extract and sort */ + md_forest_extract_and_sort(MDi); + + /* Add back the last slice if graph is not connected */ + if (last_md != nullptr) { + MDi.push_back(last_md); + } + + /* Postprocessing for connected (co-)components of slices: compute the + * factoring x-m-cluster sequence + */ + md_forest_clusters_computation(MDi, sd, scratch.clusters); + + size_t p = scratch.clusters.cluster_of_v[x]; + + /* Parse and assemble */ + root = md_forest_parse_and_assemble(root, p, scratch.clusters); + + return root; +} + +/* + * It is the function exported in the pxd file. It creates the ScratchData + * struct before calling the algorithm. + */ +md_tree_node *corneil_habib_paul_tedder_inner(const SDData &sd) { + ScratchData tmp; + return corneil_habib_paul_tedder_inner_rec(sd, tmp); +} diff --git a/src/sage/graphs/graph_decompositions/modular_decomposition.pxd b/src/sage/graphs/graph_decompositions/modular_decomposition.pxd new file mode 100644 index 00000000000..f8807be6266 --- /dev/null +++ b/src/sage/graphs/graph_decompositions/modular_decomposition.pxd @@ -0,0 +1,26 @@ +from libcpp cimport bool +from libcpp.list cimport list as cpplist +from libcpp.vector cimport vector + +cdef extern from "modular_decomposition.hpp": + cdef cppclass SDData: + void set_from_data(size_t lex_label_offset, const int* sigma, + const size_t *xslice_len, + const vector[int] *lex_label) + + cdef cppclass md_tree_node: + bool is_leaf() const + bool is_prime() const + bool is_parallel() const + bool is_series() const + cpplist[md_tree_node *] children + # If is_leaf() is true, the attribute 'vertex' contains the id of the + # corresponding vertex. If is_leaf() is false, the attribute 'vertex' + # contains the id of a vertex corresponding to any leaf below + # the node (i.e., 'vertex' contains the id of a vertex belonging to the + # module corresponding to the node). + int vertex + + void dealloc_md_tree_nodes_recursively(md_tree_node *) + + cdef md_tree_node * corneil_habib_paul_tedder_inner(const SDData &SD) diff --git a/src/sage/graphs/graph_decompositions/modular_decomposition.py b/src/sage/graphs/graph_decompositions/modular_decomposition.pyx similarity index 70% rename from src/sage/graphs/graph_decompositions/modular_decomposition.py rename to src/sage/graphs/graph_decompositions/modular_decomposition.pyx index 001f127d63d..3616f63259b 100644 --- a/src/sage/graphs/graph_decompositions/modular_decomposition.py +++ b/src/sage/graphs/graph_decompositions/modular_decomposition.pyx @@ -1,11 +1,25 @@ +# distutils: language = c++ +# distutils: extra_compile_args = -std=c++11 r""" Modular Decomposition This module implements the function for computing the modular decomposition of undirected graphs. + +AUTHORS: + +- Lokesh Jain (2017): first implementation of the linear time algorithm of + D. Corneil, M. Habib, C. Paul and M. Tedder [TCHP2008]_ + +- David Einstein (2018): added the algorithm of M. Habib and M. Maurer [HM1979]_ + +- Cyril Bouvier (2024): second implementation of the linear time algorithm + of D. Corneil, M. Habib, C. Paul and M. Tedder [TCHP2008]_ """ # **************************************************************************** # Copyright (C) 2017 Lokesh Jain +# 2018 David Einstein +# 2024 Cyril Bouvier # # 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 @@ -13,15 +27,144 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** +from cython.operator cimport dereference as deref -from enum import Enum, IntEnum +from enum import IntEnum +from sage.graphs.base.c_graph cimport CGraph, CGraphBackend +from sage.graphs.graph_decompositions.slice_decomposition cimport \ + extended_lex_BFS +from sage.groups.perm_gps.permgroup_element import PermutationGroupElement from sage.misc.lazy_import import lazy_import from sage.misc.random_testing import random_testing -lazy_import('sage.groups.perm_gps.permgroup_element', 'PermutationGroupElement') + +################################################################################ +# Corneil-Habib-Paul-Tedder algorithm # +################################################################################ +def corneil_habib_paul_tedder_algorithm(G): + r""" + Compute the modular decomposition by the algorithm of Corneil, Habib, Paul + and Tedder. + + INPUT: + + - ``G`` -- the graph for which modular decomposition tree needs to be + computed + + OUTPUT: an object of type Node representing the modular decomposition tree + of the graph G + + This function computes the modular decomposition of the given graph by the + algorithm of Corneil, Habib, Paul and Tedder [TCHP2008]_. It is a recursive, + linear-time algorithm that first computes the slice decomposition of the + graph (via the extended lexBFS algorithm) and then computes the modular + decomposition by calling itself recursively on the slices of the previously + computed slice decomposition. + + This functions is based on the last version of the paper [TCHP2008]_. + Previous versions of the paper and previous implementations were found to + contains errors, see [AP2024]_. + + .. SEEALSO:: + + * :mod:`~sage.graphs.graph_decompositions.slice_decomposition` -- + compute a slice decomposition of the simple undirect graph + + This function should not be used directly, it should be called via the + ``modular_decomposition`` method of ``Graph`` with the parameter + ``algorithm='corneil_habib_paul_tedder'``. + + This functions assumes that ``graph`` is a object of the class ``Graph`` and + is a simple graph. + + TESTS:: + + sage: from sage.graphs.graph_decompositions.modular_decomposition import * + sage: recreate_decomposition(15, corneil_habib_paul_tedder_algorithm, + ....: 3, 4, 0.2) + sage: recreate_decomposition(10, corneil_habib_paul_tedder_algorithm, + ....: 4, 5, 0.2) + sage: recreate_decomposition(3, corneil_habib_paul_tedder_algorithm, + ....: 6, 5, 0.2) + + sage: H = Graph('Hv|mmjz', format='graph6') + sage: H.relabel('abcdefghi') # counter-exemple graph from [AP2024]_ + sage: H.modular_decomposition() + (SERIES, + [(PRIME, ['e', (PARALLEL, ['g', 'h']), 'b', 'c']), + (PARALLEL, [(SERIES, ['i', 'd', 'a']), 'f'])]) + """ + cdef CGraphBackend Gbackend = G._backend + cdef CGraph cg = Gbackend.cg() + + cdef vector[int] sigma + cdef vector[vector[int]] lex_label + cdef vector[size_t] xslice_len + + # Compute the slice decomposition using the extended lexBFS algorithm + extended_lex_BFS(cg, sigma, NULL, -1, NULL, &xslice_len, &lex_label) + + cdef SDData SD + SD.set_from_data(0, sigma.data(), xslice_len.data(), lex_label.data()) + + MD = corneil_habib_paul_tedder_inner(SD) + + r = md_tree_node_to_md_tree(MD, Gbackend) + dealloc_md_tree_nodes_recursively(MD) + return r + + +cdef object _md_tree_node_to_md_tree_inner_rec(const md_tree_node *n, + CGraphBackend Gb): + """ + Utility function for :func:`md_tree_node_to_md_tree`. + """ + cdef md_tree_node *c + if deref(n).is_leaf(): + return Node.create_leaf(Gb.vertex_label(deref(n).vertex)) + + if deref(n).is_series(): + node = Node(NodeType.SERIES) + elif deref(n).is_parallel(): + node = Node(NodeType.PARALLEL) + else: # is_prime + node = Node(NodeType.PRIME) + node.children.extend(_md_tree_node_to_md_tree_inner_rec(c, Gb) + for c in deref(n).children) + return node + + +cdef object md_tree_node_to_md_tree(const md_tree_node *n, CGraphBackend Gb): + """ + This function converts a modular decomposition tree (given as a pointer to a + md_tree_node) into an object of the Python class Node (which is then + converted into the correct output by :meth:`Graph.modular_decomposition`). + + The graph backend is needed to convert the int stored into the md_tree_node + into the corresponding vertex of the Python graph. + + This function deals with the case of an empty tree and then delegates the + actual conversion to :func:`_md_tree_node_to_md_tree_inner_rec`. + + TESTS: + + Indirect doctests:: + + sage: from sage.graphs.graph_decompositions.modular_decomposition import * + sage: corneil_habib_paul_tedder_algorithm(Graph(1)) + NORMAL [0] + sage: corneil_habib_paul_tedder_algorithm(Graph(2)) + PARALLEL [NORMAL [0], NORMAL [1]] + sage: corneil_habib_paul_tedder_algorithm(graphs.CompleteGraph(3)) + SERIES [NORMAL [1], NORMAL [2], NORMAL [0]] + """ + if n == NULL: + return Node(NodeType.EMPTY) + return _md_tree_node_to_md_tree_inner_rec(n, Gb) +################################################################################ class NodeType(IntEnum): """ NodeType is an enumeration class used to define the various types of nodes @@ -35,7 +178,7 @@ class NodeType(IntEnum): - ``PRIME`` -- indicates the node is a prime module - - ``FOREST`` -- indicates a forest containing trees + - ``EMPTY`` -- indicates a empty tree - ``NORMAL`` -- indicates the node is normal containing a vertex """ @@ -43,101 +186,33 @@ class NodeType(IntEnum): SERIES = 1 PARALLEL = 2 NORMAL = 3 - FOREST = -1 + EMPTY = -1 def __repr__(self) -> str: r""" - String representation of this node type. + Return a string representation of a ``NodeType`` object. - EXAMPLES:: + TESTS:: sage: from sage.graphs.graph_decompositions.modular_decomposition import NodeType sage: repr(NodeType.PARALLEL) 'PARALLEL' + sage: str(NodeType.PRIME) + 'PRIME' """ return self.name - def __str__(self): - """ - String representation of this node type. - - EXAMPLES:: - - sage: from sage.graphs.graph_decompositions.modular_decomposition import NodeType - sage: str(NodeType.PARALLEL) - 'PARALLEL' - """ - return repr(self) - - -class NodeSplit(Enum): - """ - Enumeration class used to specify the split that has occurred at the node or - at any of its descendants. - - ``NodeSplit`` is defined for every node in modular decomposition tree and is - required during the refinement and promotion phase of modular decomposition - tree computation. Various node splits defined are - - - ``LEFT_SPLIT`` -- indicates a left split has occurred - - - ``RIGHT_SPLIT`` -- indicates a right split has occurred - - - ``BOTH_SPLIT`` -- indicates both left and right split have occurred - - - ``NO_SPLIT`` -- indicates no split has occurred - """ - LEFT_SPLIT = 1 - RIGHT_SPLIT = 2 - BOTH_SPLIT = 3 - NO_SPLIT = 0 - - -class VertexPosition(Enum): - """ - Enumeration class used to define position of a vertex w.r.t source in - modular decomposition. - - For computing modular decomposition of connected graphs a source vertex is - chosen. The position of vertex is w.r.t this source vertex. The various - positions defined are - - - ``LEFT_OF_SOURCE`` -- indicates vertex is to left of source and is a - neighbour of source vertex - - - ``RIGHT_OF_SOURCE`` -- indicates vertex is to right of source and is - connected to but not a neighbour of source vertex - - - ``SOURCE`` -- indicates vertex is source vertex - """ - LEFT_OF_SOURCE = -1 - RIGHT_OF_SOURCE = 1 - SOURCE = 0 + __str__ = __repr__ class Node: """ - Node class stores information about the node type, node split and index of - the node in the parent tree. + Node class stores information about the node type. Node type can be ``PRIME``, ``SERIES``, ``PARALLEL``, ``NORMAL`` or - ``FOREST``. Node split can be ``NO_SPLIT``, ``LEFT_SPLIT``, ``RIGHT_SPLIT`` - or ``BOTH_SPLIT``. A node is split in the refinement phase and the split - used is propagated to the ancestors. + ``EMPTY``. - ``node_type`` -- is of type NodeType and specifies the type of node - - - ``node_split`` -- is of type NodeSplit and specifies the type of splits - which have occurred in the node and its descendants - - - ``index_in_root`` -- specifies the index of the node in the forest - obtained after promotion phase - - - ``comp_num`` -- specifies the number given to nodes in a (co)component - before refinement - - - ``is_separated`` -- specifies whether a split has occurred with the node - as the root """ def __init__(self, node_type): r""" @@ -152,83 +227,72 @@ def __init__(self, node_type): [] """ self.node_type = node_type - self.node_split = NodeSplit.NO_SPLIT - self.index_in_root = -1 - self.comp_num = -1 - self.is_separated = False self.children = [] - def set_node_split(self, node_split): - """ - Add node_split to the node split of ``self``. + def is_prime(self): + r""" + Check whether ``self`` is a prime node. - ``LEFT_SPLIT`` and ``RIGHT_SPLIT`` can exist together in ``self`` as - ``BOTH_SPLIT``. + EXAMPLES:: - INPUT: + sage: from sage.graphs.graph_decompositions.modular_decomposition import * + sage: n = Node(NodeType.PRIME) + sage: n.children.append(Node.create_leaf(1)) + sage: n.children.append(Node.create_leaf(2)) + sage: n.is_prime() + True + sage: (n.children[0].is_prime(), n.children[1].is_prime()) + (False, False) + """ + return self.node_type == NodeType.PRIME - - ``node_split`` -- ``node_split`` to be added to ``self`` + def is_series(self): + r""" + Check whether ``self`` is a series node. EXAMPLES:: sage: from sage.graphs.graph_decompositions.modular_decomposition import * - sage: node = Node(NodeType.PRIME) - sage: node.set_node_split(NodeSplit.LEFT_SPLIT) - sage: node.node_split == NodeSplit.LEFT_SPLIT - True - sage: node.set_node_split(NodeSplit.RIGHT_SPLIT) - sage: node.node_split == NodeSplit.BOTH_SPLIT + sage: n = Node(NodeType.SERIES) + sage: n.children.append(Node.create_leaf(1)) + sage: n.children.append(Node.create_leaf(2)) + sage: n.is_series() True - sage: node = Node(NodeType.PRIME) - sage: node.set_node_split(NodeSplit.BOTH_SPLIT) - sage: node.node_split == NodeSplit.BOTH_SPLIT - True - """ - if self.node_split == NodeSplit.NO_SPLIT: - self.node_split = node_split - elif ((self.node_split == NodeSplit.LEFT_SPLIT and - node_split == NodeSplit.RIGHT_SPLIT) or - (self.node_split == NodeSplit.RIGHT_SPLIT and - node_split == NodeSplit.LEFT_SPLIT)): - self.node_split = NodeSplit.BOTH_SPLIT - - def has_left_split(self): + sage: (n.children[0].is_series(), n.children[1].is_series()) + (False, False) """ - Check whether ``self`` has ``LEFT_SPLIT``. + return self.node_type == NodeType.SERIES + + def is_empty(self): + r""" + Check whether ``self`` is an empty node. EXAMPLES:: sage: from sage.graphs.graph_decompositions.modular_decomposition import * - sage: node = Node(NodeType.PRIME) - sage: node.set_node_split(NodeSplit.LEFT_SPLIT) - sage: node.has_left_split() - True - sage: node = Node(NodeType.PRIME) - sage: node.set_node_split(NodeSplit.BOTH_SPLIT) - sage: node.has_left_split() + sage: Node(NodeType.EMPTY).is_empty() True + sage: Node.create_leaf(1).is_empty() + False """ - return (self.node_split == NodeSplit.LEFT_SPLIT or - self.node_split == NodeSplit.BOTH_SPLIT) + return self.node_type == NodeType.EMPTY - def has_right_split(self): - """ - Check whether ``self`` has ``RIGHT_SPLIT``. + def is_leaf(self): + r""" + Check whether ``self`` is a leaf. EXAMPLES:: sage: from sage.graphs.graph_decompositions.modular_decomposition import * - sage: node = Node(NodeType.PRIME) - sage: node.set_node_split(NodeSplit.RIGHT_SPLIT) - sage: node.has_right_split() - True - sage: node = Node(NodeType.PRIME) - sage: node.set_node_split(NodeSplit.BOTH_SPLIT) - sage: node.has_right_split() + sage: n = Node(NodeType.PRIME) + sage: n.children.append(Node.create_leaf(1)) + sage: n.children.append(Node.create_leaf(2)) + sage: n.is_leaf() + False + sage: all(c.is_leaf() for c in n.children) True """ - return (self.node_split == NodeSplit.RIGHT_SPLIT or - self.node_split == NodeSplit.BOTH_SPLIT) + return self.node_type == NodeType.NORMAL def __repr__(self): r""" @@ -238,24 +302,12 @@ def __repr__(self): sage: from sage.graphs.graph_decompositions.modular_decomposition import * sage: n = Node(NodeType.PRIME) - sage: n.children.append(create_normal_node(1)) - sage: n.children.append(create_normal_node(2)) + sage: n.children.append(Node.create_leaf(1)) + sage: n.children.append(Node.create_leaf(2)) sage: str(n) 'PRIME [NORMAL [1], NORMAL [2]]' """ - if self.node_type == NodeType.SERIES: - s = "SERIES " - elif self.node_type == NodeType.PARALLEL: - s = "PARALLEL " - elif self.node_type == NodeType.PRIME: - s = "PRIME " - elif self.node_type == NodeType.FOREST: - s = "FOREST " - else: - s = "NORMAL " - - s += str(self.children) - return s + return f"{self.node_type} {self.children}" def __eq__(self, other): r""" @@ -273,82 +325,30 @@ def __eq__(self, other): False """ return (self.node_type == other.node_type and - self.node_split == other.node_split and - self.index_in_root == other.index_in_root and - self.comp_num == other.comp_num and - self.is_separated == other.is_separated and self.children == other.children) + @classmethod + def create_leaf(cls, v): + """ + Return Node object that is a leaf corresponding to the vertex ``v``. -def create_prime_node(): - """ - Return a prime node with no children. - - OUTPUT: a node object with ``node_type`` set as ``NodeType.PRIME`` - - EXAMPLES:: - - sage: from sage.graphs.graph_decompositions.modular_decomposition import create_prime_node - sage: node = create_prime_node() - sage: node - PRIME [] - """ - return Node(NodeType.PRIME) - - -def create_parallel_node(): - """ - Return a parallel node with no children. - - OUTPUT: a node object with ``node_type`` set as ``NodeType.PARALLEL`` - - EXAMPLES:: - - sage: from sage.graphs.graph_decompositions.modular_decomposition import create_parallel_node - sage: node = create_parallel_node() - sage: node - PARALLEL [] - """ - return Node(NodeType.PARALLEL) - - -def create_series_node(): - """ - Return a series node with no children. - - OUTPUT: a node object with ``node_type`` set as ``NodeType.SERIES`` - - EXAMPLES:: - - sage: from sage.graphs.graph_decompositions.modular_decomposition import create_series_node - sage: node = create_series_node() - sage: node - SERIES [] - """ - return Node(NodeType.SERIES) - - -def create_normal_node(vertex): - """ - Return a normal node with no children. - - INPUT: + INPUT: - - ``vertex`` -- vertex number + - ``vertex`` -- vertex number - OUTPUT: a node object representing the vertex with ``node_type`` set as - ``NodeType.NORMAL`` + OUTPUT: a node object representing the vertex with ``node_type`` set as + ``NodeType.NORMAL`` - EXAMPLES:: + EXAMPLES:: - sage: from sage.graphs.graph_decompositions.modular_decomposition import create_normal_node - sage: node = create_normal_node(2) - sage: node - NORMAL [2] - """ - node = Node(NodeType.NORMAL) - node.children.append(vertex) - return node + sage: from sage.graphs.graph_decompositions.modular_decomposition import Node + sage: node = Node.create_leaf(2) + sage: node + NORMAL [2] + """ + node = cls(NodeType.NORMAL) + node.children.append(v) + return node def print_md_tree(root): @@ -362,7 +362,7 @@ def print_md_tree(root): EXAMPLES:: sage: from sage.graphs.graph_decompositions.modular_decomposition import * - sage: print_md_tree(modular_decomposition(graphs.IcosahedralGraph())) + sage: print_md_tree(habib_maurer_algorithm(graphs.IcosahedralGraph())) PRIME 3 4 @@ -467,6 +467,13 @@ def habib_maurer_algorithm(graph, g_classes=None): classes for the current root and each of the submodules. See also [BM1983]_ for an equivalent algorithm described in greater detail. + This function should not be used directly, it should be called via the + ``modular_decomposition`` method of ``Graph`` with the parameter + ``algorithm='habib_maurer'``. + + This functions assumes that ``graph`` is a object of the class ``Graph``, is + a simple graph and has at least 1 vertex. + INPUT: - ``graph`` -- the graph for which modular decomposition tree needs to be @@ -546,16 +553,6 @@ def habib_maurer_algorithm(graph, g_classes=None): sage: test_modular_decomposition(habib_maurer_algorithm(g), g) True - Graph from the :wikipedia:`Modular_decomposition`:: - - sage: d2 = {1:[2,3,4], 2:[1,4,5,6,7], 3:[1,4,5,6,7], 4:[1,2,3,5,6,7], - ....: 5:[2,3,4,6,7], 6:[2,3,4,5,8,9,10,11], - ....: 7:[2,3,4,5,8,9,10,11], 8:[6,7,9,10,11], 9:[6,7,8,10,11], - ....: 10:[6,7,8,9], 11:[6,7,8,9]} - sage: g = Graph(d2) - sage: test_modular_decomposition(habib_maurer_algorithm(g), g) - True - Tetrahedral Graph is Series:: sage: print_md_tree(habib_maurer_algorithm(graphs.TetrahedralGraph())) @@ -581,39 +578,18 @@ def habib_maurer_algorithm(graph, g_classes=None): TESTS: - Bad Input:: - - sage: g = DiGraph() - sage: habib_maurer_algorithm(g) - Traceback (most recent call last): - ... - ValueError: Graph must be undirected - - Empty Graph is Prime:: - - sage: g = Graph() - sage: habib_maurer_algorithm(g) - PRIME [] - - Ensure that a random graph and an isomorphic graph have identical modular decompositions. :: sage: from sage.graphs.graph_decompositions.modular_decomposition import permute_decomposition sage: permute_decomposition(2, habib_maurer_algorithm, 20, 0.5) # needs sage.groups """ - if graph.is_directed(): - raise ValueError("Graph must be undirected") - - if not graph.order(): - return create_prime_node() - if graph.order() == 1: - root = create_normal_node(next(graph.vertex_iterator())) + root = Node.create_leaf(next(graph.vertex_iterator())) return root elif not graph.is_connected(): - root = create_parallel_node() + root = Node(NodeType.PARALLEL) root.children = [habib_maurer_algorithm(graph.subgraph(vertices=sg), g_classes) for sg in graph.connected_components(sort=False)] return root @@ -621,7 +597,7 @@ def habib_maurer_algorithm(graph, g_classes=None): g_comp = graph.complement() if g_comp.is_connected(): from collections import defaultdict - root = create_prime_node() + root = Node(NodeType.PRIME) if g_classes is None: g_classes = gamma_classes(graph) vertex_set = frozenset(graph) @@ -638,19 +614,97 @@ def habib_maurer_algorithm(graph, g_classes=None): for sg in d1.values()] return root - root = create_series_node() + root = Node(NodeType.SERIES) root.children = [habib_maurer_algorithm(graph.subgraph(vertices=sg), g_classes) for sg in g_comp.connected_components(sort=False)] return root -modular_decomposition = habib_maurer_algorithm +################################################################################ +# Exported modular_decomposition function # +################################################################################ +def modular_decomposition(G, algorithm=None): + r""" + Return the modular decomposition of the current graph. + + This function should not be used directly, it should be called via the + ``modular_decomposition`` method of ``Graph``. + + INPUT: + + - ``G`` -- graph whose modular decomposition tree is to be computed + + - ``algorithm`` -- string (default: ``None``); the algorithm to use among: + + - ``None`` or ``'corneil_habib_paul_tedder'`` -- will use the + Corneil-Habib-Paul-Tedder algorithm from [TCHP2008]_, its complexity + is linear in the number of vertices and edges. + + - ``'habib_maurer'`` -- will use the Habib-Maurer algorithm from + [HM1979]_, its complexity is cubic in the number of vertices. + + OUTPUT: The modular decomposition tree, as an object of type ``Node``. + + TESTS:: + + sage: from sage.graphs.graph_decompositions.modular_decomposition import * + + sage: modular_decomposition(Graph()) + EMPTY [] + + sage: modular_decomposition(Graph(1)) + NORMAL [0] + + sage: check_algos_are_equivalent(5,\ + ....: lambda : graphs.RandomProperIntervalGraph(100)) + + sage: check_algos_are_equivalent(5, lambda : graphs.RandomGNM(75, 1000)) + + sage: modular_decomposition(DiGraph()) + Traceback (most recent call last): + ... + TypeError: the input must be an undirected Sage graph + + sage: modular_decomposition(Graph(5, loops=True)) + Traceback (most recent call last): + ... + ValueError: This method is not known to work on graphs with loops... + + sage: modular_decomposition(Graph(5, multiedges=True)) + Traceback (most recent call last): + ... + ValueError: This method is not known to work on graphs with multiedges... + + sage: modular_decomposition(Graph(), algorithm='silly walk') + Traceback (most recent call last): + ... + ValueError: unknown algorithm "silly walk" + """ + from sage.graphs.graph import Graph + if not isinstance(G, Graph): + raise TypeError("the input must be an undirected Sage graph") + G._scream_if_not_simple() + + if algorithm is None: + algorithm = "corneil_habib_paul_tedder" + + if algorithm not in ("habib_maurer", "corneil_habib_paul_tedder"): + raise ValueError(f'unknown algorithm "{algorithm}"') + + if not G.order(): + return Node(NodeType.EMPTY) + if G.order() == 1: + D = Node(NodeType.NORMAL) + D.children.append(next(G.vertex_iterator())) + return D + if algorithm == "habib_maurer": + return habib_maurer_algorithm(G) + return corneil_habib_paul_tedder_algorithm(G) # ============================================================================ # Below functions are implemented to test the modular decomposition tree # ============================================================================ - # Function implemented for testing def test_modular_decomposition(tree_root, graph): """ @@ -758,19 +812,19 @@ def get_vertices(component_root): EXAMPLES:: sage: from sage.graphs.graph_decompositions.modular_decomposition import * - sage: forest = Node(NodeType.FOREST) - sage: forest.children = [create_normal_node(2), - ....: create_normal_node(3), create_normal_node(1)] + sage: forest = Node(NodeType.PRIME) + sage: forest.children = [Node.create_leaf(2), Node.create_leaf(0), + ....: Node.create_leaf(3), Node.create_leaf(1)] sage: series_node = Node(NodeType.SERIES) - sage: series_node.children = [create_normal_node(4), - ....: create_normal_node(5)] + sage: series_node.children = [Node.create_leaf(4), + ....: Node.create_leaf(5)] sage: parallel_node = Node(NodeType.PARALLEL) - sage: parallel_node.children = [create_normal_node(6), - ....: create_normal_node(7)] + sage: parallel_node.children = [Node.create_leaf(6), + ....: Node.create_leaf(7)] sage: forest.children.insert(1, series_node) sage: forest.children.insert(3, parallel_node) sage: get_vertices(forest) - [2, 4, 5, 3, 6, 7, 1] + [2, 4, 5, 0, 6, 7, 3, 1] """ vertices = [] @@ -963,17 +1017,17 @@ def children_node_type(module, node_type): sage: from sage.graphs.graph_decompositions.modular_decomposition import * sage: g = graphs.OctahedralGraph() sage: tree_root = modular_decomposition(g) - sage: print_md_tree(modular_decomposition(g)) + sage: print_md_tree(tree_root) SERIES PARALLEL - 0 - 5 + 2 + 3 PARALLEL 1 4 PARALLEL - 2 - 3 + 0 + 5 sage: children_node_type(tree_root, NodeType.SERIES) False sage: children_node_type(tree_root, NodeType.PARALLEL) @@ -1003,14 +1057,14 @@ def either_connected_or_not_connected(v, vertices_in_module, graph): sage: print_md_tree(modular_decomposition(g)) SERIES PARALLEL - 0 - 5 + 2 + 3 PARALLEL 1 4 PARALLEL - 2 - 3 + 0 + 5 sage: either_connected_or_not_connected(2, [1, 4], g) True sage: either_connected_or_not_connected(2, [3, 4], g) @@ -1043,7 +1097,7 @@ def tree_to_nested_tuple(root): sage: from sage.graphs.graph_decompositions.modular_decomposition import * sage: g = graphs.OctahedralGraph() sage: tree_to_nested_tuple(modular_decomposition(g)) - (SERIES, [(PARALLEL, [0, 5]), (PARALLEL, [1, 4]), (PARALLEL, [2, 3])]) + (SERIES, [(PARALLEL, [2, 3]), (PARALLEL, [1, 4]), (PARALLEL, [0, 5])]) """ if root.node_type == NodeType.NORMAL: return root.children[0] @@ -1075,7 +1129,7 @@ def nested_tuple_to_tree(nest): 4 """ if not isinstance(nest, tuple): - return create_normal_node(nest) + return Node.create_leaf(nest) root = Node(nest[0]) root.children = [nested_tuple_to_tree(n) for n in nest[1:]] @@ -1187,7 +1241,7 @@ def relabel_tree(root, perm): raise TypeError("type of perm is not supported for relabeling") if root.node_type == NodeType.NORMAL: - return create_normal_node(perm[root.children[0]]) + return Node.create_leaf(perm[root.children[0]]) else: new_root = Node(root.node_type) new_root.children = [relabel_tree(child, perm) for child in root.children] @@ -1304,7 +1358,7 @@ def rand_md_tree(max_depth, parent_type): is one less than its parent's. """ if random() < leaf_probability or max_depth == 1: - root = create_normal_node(current_leaf[0]) + root = Node.create_leaf(current_leaf[0]) current_leaf[0] += 1 return root if parent_type == NodeType.PRIME: @@ -1332,18 +1386,18 @@ def rand_md_tree(max_depth, parent_type): return root -def md_tree_to_graph(root): +def md_tree_to_graph(root, prime_node_generator=None): r""" Create a graph having the given MD tree. - For the prime nodes we use that every path of length 4 or more is prime. - - TODO: accept a function that generates prime graphs as a parameter and - use that in the prime nodes. + For the prime nodes, the parameter ``prime_node_generator`` is called with + the number of vertices as the only argument. If it is ``None``, the path + graph is used (it is prime when the length is 4 or more). EXAMPLES:: sage: from sage.graphs.graph_decompositions.modular_decomposition import * + sage: from sage.graphs.graph_generators import graphs sage: tup1 = (NodeType.PRIME, 1, (NodeType.SERIES, 2, 3), ....: (NodeType.PARALLEL, 4, 5), 6) sage: tree1 = nested_tuple_to_tree(tup1) @@ -1352,30 +1406,54 @@ def md_tree_to_graph(root): ....: 4: [2, 3, 6], 5: [2, 3, 6], 6: [4, 5]}) sage: g1.is_isomorphic(g2) True + + sage: G = md_tree_to_graph(Node(NodeType.EMPTY)) + sage: G.is_isomorphic(Graph()) + True + + sage: tree = Node(NodeType.SERIES) + sage: tree.children.extend(Node.create_leaf(i) for i in range(5)) + sage: G = md_tree_to_graph(tree) + sage: G.is_isomorphic(graphs.CompleteGraph(5)) + True + + sage: tree = Node(NodeType.PRIME) + sage: tree.children.extend(Node.create_leaf(i) for i in range(5)) + sage: png = lambda n: (graphs.PathGraph if n == 4 else graphs.CycleGraph)(n) + sage: G = md_tree_to_graph(tree, prime_node_generator=png) + sage: G.is_isomorphic(graphs.CycleGraph(5)) + True """ from itertools import product, combinations from sage.graphs.graph import Graph + if prime_node_generator is None: + from sage.graphs.graph_generators import graphs + prime_node_generator = graphs.PathGraph + def tree_to_vertices_and_edges(root): r""" Give the list of vertices and edges of the graph having the given md tree. """ - if root.node_type == NodeType.NORMAL: + if root.is_leaf(): return (root.children, []) children_ve = [tree_to_vertices_and_edges(child) for child in root.children] vertices = [v for vs, es in children_ve for v in vs] edges = [e for vs, es in children_ve for e in es] vertex_lists = [vs for vs, es in children_ve] - if root.node_type == NodeType.PRIME: - for vs1, vs2 in zip(vertex_lists, vertex_lists[1:]): - for v1, v2 in product(vs1, vs2): - edges.append((v1, v2)) - elif root.node_type == NodeType.SERIES: + if root.is_prime(): + G = prime_node_generator(len(vertex_lists)) + G.relabel(range(len(vertex_lists))) + for i1, i2 in G.edge_iterator(labels=False): + edges.extend(product(vertex_lists[i1], vertex_lists[i2])) + elif root.is_series(): for vs1, vs2 in combinations(vertex_lists, 2): - for v1, v2 in product(vs1, vs2): - edges.append((v1, v2)) + edges.extend(product(vs1, vs2)) + # else: no edge to be created for PARALLEL nodes return (vertices, edges) + if root.is_empty(): + return Graph() vs, es = tree_to_vertices_and_edges(root) return Graph([vs, es], format='vertices_and_edges') @@ -1410,3 +1488,45 @@ def recreate_decomposition(trials, algorithm, max_depth, max_fan_out, assert equivalent_trees(rand_tree, reconstruction) if verbose: print("Passes!") + + +@random_testing +def check_algos_are_equivalent(trials, graph_gen, verbose=False): + r""" + Verify that both algorithms compute the same tree (up to equivalence) for + random graphs. + + INPUT: + + - ``trials`` -- integer; the number of tests the function will run. + + - ``graph_gen`` -- function; a function that can be called without argument + and returns a random graph. + + - ``verbose`` -- boolean (defaul: ``False``); enable printing debug + information. + + OUTPUT: ``None``. Raises an ``AssertionError`` on failure. + + EXAMPLES:: + + sage: from sage.graphs.graph_decompositions.modular_decomposition import * + sage: check_algos_are_equivalent(3, lambda : graphs.RandomGNP(10, 0.1)) + sage: check_algos_are_equivalent(3, lambda : graphs.RandomGNP(10, 0.5)) + sage: check_algos_are_equivalent(3, lambda : graphs.RandomGNP(10, 0.9)) + """ + for _ in range(trials): + graph = graph_gen() + if verbose: + print(graph.graph6_string()) + print(graph.to_dictionary()) + MD = [] + for algo in ('habib_maurer', 'corneil_habib_paul_tedder'): + md = modular_decomposition(graph, algorithm=algo) + MD.append(md) + if verbose: + print(f'Using {algo}:') + print_md_tree(md) + assert equivalent_trees(MD[0], MD[1]) + if verbose: + print("Passes!") diff --git a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx index 8ed9ee9d224..da385943bd1 100644 --- a/src/sage/graphs/graph_decompositions/tree_decomposition.pyx +++ b/src/sage/graphs/graph_decompositions/tree_decomposition.pyx @@ -75,7 +75,7 @@ The treewidth of a clique is `n-1` and its treelength is 1:: :meth:`treewidth` | Compute the treewidth of `G` (and provide a decomposition). :meth:`treelength` | Compute the treelength of `G` (and provide a decomposition). - :meth:`make_nice_tree_decomposition` | Return a *nice* tree decomposition (TD) of the TD `tree_decomp`. + :meth:`make_nice_tree_decomposition` | Return a *nice* tree decomposition (TD) of the TD ``tree_decomp``. :meth:`label_nice_tree_decomposition` | Return a nice tree decomposition with nodes labelled accordingly. :meth:`is_valid_tree_decomposition` | Check whether `T` is a valid tree-decomposition for `G`. :meth:`reduced_tree_decomposition` | Return a reduced tree-decomposition of `T`. @@ -830,7 +830,7 @@ def make_nice_tree_decomposition(graph, tree_decomp): .. WARNING:: - This method assumes that the vertices of the input tree `tree_decomp` + This method assumes that the vertices of the input tree ``tree_decomp`` are hashable and have attribute ``issuperset``, e.g., ``frozenset`` or :class:`~sage.sets.set.Set_object_enumerated_with_category`. diff --git a/src/sage/graphs/graph_plot.py b/src/sage/graphs/graph_plot.py index 40b6ecc764d..5102c92120d 100644 --- a/src/sage/graphs/graph_plot.py +++ b/src/sage/graphs/graph_plot.py @@ -181,6 +181,9 @@ 'a dictionary keyed by vertices and associating to each vertex ' 'a label string, or a function taking as input a vertex and returning ' 'a label string.', + 'vertex_label_shift': + 'If layout is circular and we have vertex labels, will shift vertices ' + 'away from center of circle in coordinate fashion `(x, y)`.', 'vertex_color': 'Default color for vertices not listed ' 'in vertex_colors dictionary.', @@ -197,10 +200,19 @@ 'Whether or not to draw edge labels.', 'edge_style': 'The linestyle of the edges. It should be ' - 'one of "solid", "dashed", "dotted", dashdot", ' + 'one of "solid", "dashed", "dotted", "dashdot", ' 'or "-", "--", ":", "-.", respectively. ', + 'edge_styles': + 'A dictionary specifying edge styles: ' + 'each key is an edge or a label (all same) and value is the linestyle ' + 'of the edge. It should be one of "solid", "dashed", "dotted", ' + '"dashdot", or "-", "--", ":", "-.", respectively.', 'edge_thickness': 'The thickness of the edges.', + 'edge_thicknesses': + 'A dictionary specifying edge thicknesses: ' + 'each key is an edge or a label (all same) and thickness of the ' + 'corresponding edge.', 'edge_color': 'The default color for edges not listed in edge_colors.', 'edge_colors': @@ -215,12 +227,16 @@ 'cell in a different color; vertex_colors takes precedence.', 'loop_size': 'The radius of the smallest loop.', + 'arrowsize': + 'Size of arrows.', 'dist': 'The distance between multiedges.', 'max_dist': 'The max distance range to allow multiedges.', 'talk': 'Whether to display the vertices in talk mode (larger and white).', + 'label_fontsize': + 'font size of all labels', 'graph_border': 'Whether or not to draw a frame around the graph.', 'edge_labels_background': @@ -238,9 +254,12 @@ DEFAULT_PLOT_OPTIONS = { 'vertex_size' : 200, 'vertex_labels' : True, + 'vertex_label_shift' : None, 'layout' : None, 'edge_style' : 'solid', + 'edge_styles' : None, 'edge_thickness' : 1, + 'edge_thicknesses' : None, 'edge_color' : 'black', 'edge_colors' : None, 'edge_labels' : False, @@ -253,6 +272,7 @@ 'partition' : None, 'dist' : .075, 'max_dist' : 1.5, + 'label_fontsize' : 10, 'loop_size' : .075, 'edge_labels_background' : 'white'} @@ -568,9 +588,26 @@ def vfun(x): return vlabels.get(x, "") else: vfun = vlabels + # TODO: allow text options - self._plot_components['vertex_labels'] = [text(vfun(v), self._pos[v], color='black', zorder=8) - for v in self._nodelist] + if self._options['layout'] == 'circular' and self._options['vertex_label_shift'] is not None: + def pos_shift(v, shift): + return (v[0] + (v[0] * shift[0])/100, v[1] + (v[1] * shift[1])/100) + self._plot_components['vertex_labels'] = [ + text( + vfun(v), + pos_shift(self._pos[v], self._options['vertex_label_shift']), + fontsize=self._options['label_fontsize'], + color='black', + zorder=8 + ) + for v in self._nodelist + ] + else: + self._plot_components['vertex_labels'] = [ + text(vfun(v), self._pos[v], color='black', zorder=8, fontsize=self._options['label_fontsize']) + for v in self._nodelist + ] def set_edges(self, **edge_options): """ @@ -709,15 +746,20 @@ def set_edges(self, **edge_options): if self._options['edge_labels_background'] == "transparent": self._options['edge_labels_background'] = "None" - # Handle base edge options: thickness, linestyle + # Whether a key is an edge or not: + # None => edge_x is not set + # True => keys are edges + # False => keys are labels + style_key_edges = None + thickness_key_edges = None + if isinstance(self._options['edge_styles'], dict): + style_key_edges = next(iter(self._options['edge_styles'])) in self._graph.edges() + if isinstance(self._options['edge_thicknesses'], dict): + thickness_key_edges = next(iter(self._options['edge_thicknesses'])) in self._graph.edges() + eoptions = {} - if 'edge_style' in self._options: - from sage.plot.misc import get_matplotlib_linestyle - eoptions['linestyle'] = get_matplotlib_linestyle( - self._options['edge_style'], - return_type='long') - if 'edge_thickness' in self._options: - eoptions['thickness'] = self._options['edge_thickness'] + if 'arrowsize' in self._options: + eoptions['arrowsize'] = self._options['arrowsize'] # Set labels param to add labels on the fly labels = False @@ -812,12 +854,24 @@ def set_edges(self, **edge_options): # Now add all the loops at this vertex, varying their size for lab, col, _ in local_labels: x, y = self._pos[a][0], self._pos[a][1] - loop_size - c = circle((x, y), loop_size, rgbcolor=col, **eoptions) + + estyle = self._options['edge_style'] + ethickness = self._options['edge_thickness'] + if (style_key_edges is not None + and ((style_key_edges and (x, y) in self._options['edge_styles']) + or (not style_key_edges and lab in self._options['edge_styles']))): + estyle = style_key_edges and self._options['edge_styles'][(x, y)] or self._options['edge_styles'][lab] + if (thickness_key_edges is not None + and ((thickness_key_edges and (x, y) in self._options['edge_thicknesses']) + or (not thickness_key_edges and lab in self._options['edge_thicknesses']))): + ethickness = thickness_key_edges and self._options['edge_thicknesses'][(x, y)] or self._options['edge_thicknesses'][lab] + + c = circle((x, y), loop_size, rgbcolor=col, linestyle=estyle, thickness=ethickness) self._plot_components['edges'].append(c) if labels: bg = self._options['edge_labels_background'] y -= loop_size # place label at bottom of loop - t = text(lab, (x, y), background_color=bg) + t = text(lab, (x, y), background_color=bg, fontsize=self._options['label_fontsize']) self._plot_components['edge_labels'].append(t) loop_size += loop_size_increment elif len(edges_to_draw[a, b]) > 1: @@ -883,6 +937,9 @@ def even_xy(d): distance = float(max_dist) / len_local_labels for i in range(len_local_labels // 2): k = (i + 1.0) * distance + estyle = self._options['edge_style'] + ethickness = self._options['edge_thickness'] + if self._arcdigraph: vr = self._vertex_radius ph = self._polar_hack_for_multidigraph @@ -890,73 +947,112 @@ def even_xy(d): odd_end = ph(odd_xy(k), p2, vr)[1] even_start = ph(p1, even_xy(k), vr)[0] even_end = ph(even_xy(k), p2, vr)[1] + self._plot_components['edges'].append( arrow(path=[[odd_start, odd_xy(k), odd_end]], head=local_labels[2 * i][2], zorder=1, rgbcolor=local_labels[2 * i][1], - **eoptions)) + linestyle=estyle, + width=ethickness, + **eoptions + )) self._plot_components['edges'].append( arrow(path=[[even_start, even_xy(k), even_end]], head=local_labels[2 * i + 1][2], zorder=1, rgbcolor=local_labels[2 * i + 1][1], - **eoptions)) + linestyle=estyle, + width=ethickness, + **eoptions + )) else: self._plot_components['edges'].append( bezier_path([[p1, odd_xy(k), p2]], zorder=1, rgbcolor=local_labels[2 * i][1], - **eoptions)) + linestyle=estyle, + thickness=ethickness + )) self._plot_components['edges'].append( bezier_path([[p1, even_xy(k), p2]], zorder=1, rgbcolor=local_labels[2 * i + 1][1], - **eoptions)) + linestyle=estyle, + thickness=ethickness + )) if labels: j = k / 2.0 bg = self._options['edge_labels_background'] self._plot_components['edge_labels'].append( text(local_labels[2 * i][0], odd_xy(j), - background_color=bg)) + background_color=bg, fontsize=self._options['label_fontsize'])) self._plot_components['edge_labels'].append( text(local_labels[2 * i + 1][0], even_xy(j), - background_color=bg)) + background_color=bg, fontsize=self._options['label_fontsize'])) if len_local_labels % 2: # draw line for last odd edges_to_draw[a, b] = [local_labels[-1]] is_directed = self._graph.is_directed() for a, b in edges_to_draw: + elabel = edges_to_draw[a, b][0][0] + ecolor = edges_to_draw[a, b][0][1] + ehead = edges_to_draw[a, b][0][2] + e = (a, b, elabel) + + estyle = self._options['edge_style'] + ethickness = self._options['edge_thickness'] + if (style_key_edges is not None + and ((style_key_edges and e in self._options['edge_styles']) + or (not style_key_edges and elabel in self._options['edge_styles']))): + estyle = style_key_edges and self._options['edge_styles'][e] or self._options['edge_styles'][elabel] + if (thickness_key_edges is not None + and ((thickness_key_edges and e in self._options['edge_thicknesses']) + or (not thickness_key_edges and elabel in self._options['edge_thicknesses']))): + ethickness = thickness_key_edges and self._options['edge_thicknesses'][e] or self._options['edge_thicknesses'][elabel] + if self._arcdigraph: ph = self._polar_hack_for_multidigraph C, D = ph(self._pos[a], self._pos[b], self._vertex_radius) self._plot_components['edges'].append( arrow(C, D, - rgbcolor=edges_to_draw[a, b][0][1], - head=edges_to_draw[a, b][0][2], - **eoptions)) + rgbcolor=ecolor, + head=ehead, + linestyle=estyle, + width=ethickness, + **eoptions + )) if labels: bg = self._options['edge_labels_background'] self._plot_components['edge_labels'].append( - text(str(edges_to_draw[a, b][0][0]), + text(str(elabel), [(C[0] + D[0]) / 2., (C[1] + D[1]) / 2.], - background_color=bg)) + background_color=bg, + fontsize=self._options['label_fontsize'] + )) elif is_directed: self._plot_components['edges'].append( arrow(self._pos[a], self._pos[b], - rgbcolor=edges_to_draw[a, b][0][1], + rgbcolor=ecolor, arrowshorten=self._arrowshorten, - head=edges_to_draw[a, b][0][2], - **eoptions)) + head=ehead, + linestyle=estyle, + width=ethickness, + **eoptions + )) else: self._plot_components['edges'].append( line([self._pos[a], self._pos[b]], - rgbcolor=edges_to_draw[a, b][0][1], - **eoptions)) + rgbcolor=ecolor, + linestyle=estyle, + thickness=ethickness + )) if labels and not self._arcdigraph: bg = self._options['edge_labels_background'] self._plot_components['edge_labels'].append( text(str(edges_to_draw[a, b][0][0]), [(self._pos[a][0] + self._pos[b][0]) / 2., (self._pos[a][1] + self._pos[b][1]) / 2.], - background_color=bg)) + background_color=bg, + fontsize=self._options['label_fontsize'] + )) def _polar_hack_for_multidigraph(self, A, B, VR): """ @@ -1148,6 +1244,31 @@ def plot(self, **kwds): D.set_edge_label(u, v, f'({u},{v})') sphinx_plot(D.graphplot(edge_labels=True, layout='circular')) + For graphs with ``circular`` layouts, one may shift the vertex labels by + specifying coordinates to shift by:: + + 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: []}) + sage: for u, v, l in D.edges(sort=True): + ....: D.set_edge_label(u, v, f'({u},{v})') + sage: D.graphplot(edge_labels=True, layout='circular', vertex_label_shift=(15,10)).show() + + .. PLOT:: + + 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: []}) + for u, v, l in D.edges(sort=True): + D.set_edge_label(u, v, f'({u},{v})') + sphinx_plot(D.graphplot(edge_labels=True, layout='circular', vertex_label_shift=(15,10))) + This example shows off the coloring of edges:: sage: from sage.plot.colors import rainbow @@ -1237,6 +1358,17 @@ def plot(self, **kwds): P = g.graphplot(pos=pos, layout='spring', iterations=0).plot() sphinx_plot(P) + :: + + sage: D = graphs.CubeGraph(3) + sage: D.graphplot(layout='planar').plot() + Graphics object consisting of 21 graphics primitives + + .. PLOT:: + + D = graphs.CubeGraph(3) + sphinx_plot(D.graphplot(layout='planar')) + :: sage: G = Graph() @@ -1345,6 +1477,17 @@ def plot(self, **kwds): D = DiGraph({0:[1,2,3], 2:[1,4], 3:[0]}) sphinx_plot(D.graphplot()) + :: + + sage: D = DiGraph({0:[1,2,3], 2:[1,4], 3:[0]}) + sage: D.graphplot(label_fontsize=20, arrowsize=10).show() + + .. PLOT:: + + D = DiGraph({0:[1,2,3], 2:[1,4], 3:[0]}) + sphinx_plot(D.graphplot(label_fontsize=20, arrowsize=10)) + + :: sage: D = DiGraph(multiedges=True, sparse=True) @@ -1389,12 +1532,64 @@ def plot(self, **kwds): The ``edge_style`` option may be provided in the short format too:: + sage: g.graphplot(edge_labels=True, ....: color_by_label=True, ....: edge_style='--' ....: ).plot() Graphics object consisting of 22 graphics primitives + The ``edge_styles`` option may be provided if you need only certain edges + to have certain styles:: + + sage: g = Graph(loops=True, multiedges=True, sparse=True) + sage: g.add_edges([(0, 0, 'a'), (0, 0, 'b'), (0, 1, 'c'), + ....: (0, 1, 'd'), (0, 1, 'e'), (0, 1, 'f'), + ....: (0, 1, 'f'), (2, 1, 'g'), (2, 2, 'h')]) + sage: GP = g.graphplot(vertex_size=100, edge_labels=True, + ....: color_by_label=True, edge_style='dashed') + sage: GP.set_edges(edge_styles={'a':'dashed', 'g':'dotted'}) + sage: GP.plot() + Graphics object consisting of 22 graphics primitives + + .. PLOT:: + + g = Graph(loops=True, multiedges=True, sparse=True) + g.add_edges([(0, 0, 'a'), (0, 0, 'b'), (0, 1, 'c'), + (0, 1, 'd'), (0, 1, 'e'), (0, 1, 'f'), + (0, 1, 'f'), (2, 1, 'g'), (2, 2, 'h')]) + GP = g.graphplot(vertex_size=100, edge_labels=True, + color_by_label=True, edge_style='dashed') + GP.set_edges(edge_style='solid') + GP.set_edges(edge_color='black') + GP.set_edges(edge_styles={'a':'dashed', 'g':'dotted'}) + sphinx_plot(GP) + + :: + + sage: g = Graph(loops=True, multiedges=True, sparse=True) + sage: g.add_edges([(0, 0, 'a'), (0, 0, 'b'), (0, 1, 'c'), + ....: (0, 1, 'd'), (0, 1, 'e'), (0, 1, 'f'), + ....: (0, 1, 'f'), (2, 1, 'g'), (2, 2, 'h')]) + sage: GP = g.graphplot(vertex_size=100, edge_labels=True, + ....: color_by_label=True, edge_thickness=3) + sage: GP.set_edges(edge_thicknesses={'a':1, 'g':5}) + sage: GP.plot() + Graphics object consisting of 22 graphics primitives + + .. PLOT:: + + g = Graph(loops=True, multiedges=True, sparse=True) + g.add_edges([(0, 0, 'a'), (0, 0, 'b'), (0, 1, 'c'), + (0, 1, 'd'), (0, 1, 'e'), (0, 1, 'f'), + (0, 1, 'f'), (2, 1, 'g'), (2, 2, 'h')]) + GP = g.graphplot(vertex_size=100, edge_labels=True, + color_by_label=True, edge_thickness=3) + GP.set_edges(edge_style='solid') + GP.set_edges(edge_color='black') + GP.set_edges(edge_thicknesses={'a':1, 'g':5}) + sphinx_plot(GP) + TESTS: Make sure that show options work with plot also:: diff --git a/src/sage/graphs/matching_covered_graph.py b/src/sage/graphs/matching_covered_graph.py index 2a9b8916c90..370fc1f9cad 100644 --- a/src/sage/graphs/matching_covered_graph.py +++ b/src/sage/graphs/matching_covered_graph.py @@ -57,7 +57,6 @@ ``delete_multiedge()`` | Delete all edges from ``u`` to ``v``. ``disjoint_union()`` | Return the disjoint union of ``self`` and ``other``. ``disjunctive_product()`` | Return the disjunctive product of ``self`` and ``other``. - ``has_loops()`` | Return whether there are loops in the matching covered graph. ``is_biconnected()`` | Check if the matching covered graph is biconnected. ``is_block_graph()`` | Check whether the matching covered graph is a block graph. ``is_cograph()`` | Check whether the matching covered graph is cograph. @@ -69,12 +68,8 @@ ``join()`` | Return the join of ``self`` and ``other``. ``lexicographic_product()`` | Return the lexicographic product of ``self`` and ``other``. ``load_afile()`` | Load the matching covered graph specified in the given file into the current object. - ``loop_edges()`` | Return a list of all loops in the matching covered graph. - ``loop_vertices()`` | Return a list of vertices with loops. ``merge_vertices()`` | Merge vertices. - ``number_of_loops()`` | Return the number of edges that are loops. ``random_subgraph()`` | Return a random matching covered subgraph containing each vertex with probability ``p``. - ``remove_loops()`` | Remove loops on vertices in ``vertices``. ``save_afile()`` | Save the graph to file in alist format. ``strong_product()`` | Return the strong product of ``self`` and ``other``. ``subdivide_edge()`` | Subdivide an edge `k` times. @@ -89,16 +84,6 @@ ``transitive_reduction()`` | Return a transitive reduction of the matching covered graph. ``union()`` | Return the union of ``self`` and ``other``. - **Barriers and canonical partition** - - .. csv-table:: - :class: contentstable - :widths: 30, 70 - :delim: | - - ``canonical_partition()`` | Return the canonical partition of the (matching covered) graph. - ``maximal_barrier()`` | Return the (unique) maximal barrier of the (matching covered) graph containing the (provided) vertex. - **Bricks, braces and tight cut decomposition** .. csv-table:: @@ -165,6 +150,7 @@ from sage.graphs.graph import Graph from sage.misc.rest_index_of_methods import doc_index, gen_thematic_rest_table_index + class MatchingCoveredGraph(Graph): r""" Matching covered graph @@ -1627,6 +1613,16 @@ def allow_loops(self, new, check=True): Traceback (most recent call last): ... ValueError: loops are not allowed in matching covered graphs + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ if new: raise ValueError('loops are not allowed in ' @@ -1658,9 +1654,97 @@ def allows_loops(self): sage: G = MatchingCoveredGraph(P) sage: G.allows_loops() False + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` """ return False + @doc_index('Barriers and canonical partition') + def canonical_partition(self): + r""" + Return the canonical partition of the (matching covered) graph. + + For a matching covered graph `G`, a subset `B` of the vertex set `V` is + a barrier if `|B| = o(G - B)`, where `|B|` denotes the cardinality of + the set `B` and `o(G - B)` denotes the number of odd components in the + graph `G - B`. And a barrier `B` is a maximal barrier if `C` is not a + barrier for each `C` such that `B \subset C \subseteq V`. + + Note that in a matching covered graph, each vertex belongs to a unique + maximal barrier. The maximal barriers of a matching covered graph + partitions its vertex set and the partition of the vertex set of a + matching covered graph into its maximal barriers is called as its + *canonical* *partition*. + + OUTPUT: + + - A list of sets that constitute a (canonical) partition of the vertex + set, wherein each set is a (unique) maximal barrier of the (matching + covered) graph. + + EXAMPLES: + + Show the maximal barrier of the graph `K_4 \odot K_{3, 3}`:: + + sage: G = Graph([ + ....: (0, 2), (0, 3), (0, 4), (1, 2), + ....: (1, 3), (1, 4), (2, 5), (3, 6), + ....: (4, 7), (5, 6), (5, 7), (6, 7) + ....: ]) + sage: H = MatchingCoveredGraph(G) + sage: H.canonical_partition() + [{0}, {1}, {2, 3, 4}, {5}, {6}, {7}] + + For a bicritical graph (for instance, the Petersen graph), the + canonical parition constitutes of only singleton sets each containing + an individual vertex:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: G.canonical_partition() + [{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}] + + For a bipartite matching covered graph (for instance, the Hexahedral + graph), the canonical partition consists of two sets each of which + corresponds to the individual color class:: + + sage: H = graphs.HexahedralGraph() + sage: G = MatchingCoveredGraph(H) + sage: G.canonical_partition() + [{0, 2, 5, 7}, {1, 3, 4, 6}] + sage: B = BipartiteGraph(H) + sage: list(B.bipartition()) == G.canonical_partition() + True + + REFERENCES: + + - [LM2024]_ + + .. SEEALSO:: + + - :meth:`~sage.graphs.graph.Graph.is_bicritical` + - :meth:`~sage.graphs.graph.Graph.is_matching_covered` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.maximal_barrier` + """ + visited = set() + + maximal_barriers = [] + for v in self: + if v not in visited: + B = self.maximal_barrier(v) + visited.update(B) + maximal_barriers.append(B) + + return maximal_barriers + @doc_index('Overwritten methods') def delete_vertex(self, vertex, in_order=False): r""" @@ -1918,6 +2002,265 @@ def get_matching(self): """ return self._matching + @doc_index('Barriers and canonical partition') + def maximal_barrier(self, vertex): + r""" + Return the (unique) maximal barrier containing the vertex. + + For a matching covered graph `G`, a subset `B` of the vertex set `V` is + a barrier if `|B| = o(G - B)`, where `|B|` denotes the cardinality of + the set `B` and `o(G - B)` denotes the number of odd components in the + graph `G - B`. And a barrier `B` is a maximal barrier if `C` is not a + barrier for each `C` such that `B \subset C \subseteq V`. + + In a matching covered graph, each vertex belongs to a unique maximal + barrier, which is a consequence of the following theorem. + + .. RUBRIC:: Theorem [LM2024]_: + + Let `u` and `v` be any two vertices in a matchable graph `G`. Then the + graph `G - u - v` is matchable if and only if there is no barrier of + `G` which contains both `u` and `v`. + + And in order to find the vertices that do not lie in the maximal + barrier containing the provided vertex in linear time we take + inspiration of the `M` alternating tree seach method [LR2004]_. + + INPUT: + + - ``vertex`` -- a vertex of the graph + + OUTPUT: + + - A :exc:`~ValueError` is returned if ``vertex`` is not a vertex of the + graph, otherwise a set of vertices that constitute the (unique) + maximal barrier containing the vertex is returned. + + EXAMPLES: + + The graph `K_4 \odot K_{3, 3}` is matching covered. Show the set of + vertices in the (unique) maximal barrier containing the vertex `2`:: + + sage: G = Graph([ + ....: (0, 2), (0, 3), (0, 4), (1, 2), + ....: (1, 3), (1, 4), (2, 5), (3, 6), + ....: (4, 7), (5, 6), (5, 7), (6, 7) + ....: ]) + sage: H = MatchingCoveredGraph(G) + sage: B = H.maximal_barrier(2) + sage: B + {2, 3, 4} + + Let `B` be a maximal barrier of a matching covered graph `G` (which is, + of course, a matchable graph). The graph, `J := G - B` has no even + component:: + + sage: J = G.copy() + sage: J.delete_vertices(B) + sage: all(len(K)%2 != 0 for K in J.connected_components()) + ... + True + + Let `B` be a maximal barrier in a matching covered graph `G` and let + `M` be a perfect matching of `G`. If `K` is an odd component of + `J := G - B`, then `M \cap \partial_G(K)` has precisely one edge and if + `v` is the end of that edge in `V(K)`, then `M \cap E(K)` is a perfect + matching of `K - v`:: + + sage: K = J.subgraph(vertices=(J.connected_components())[0]) + sage: # Let F := \partial_G(K) and T := M \cap F + sage: F = [edge for edge in G.edge_iterator() + ....: if (edge[0] in K and edge[1] not in K) + ....: or (edge[0] not in K and edge[1] in K) + ....: ] + sage: M = H.get_matching() + sage: T = [edge for edge in F if edge in M] + sage: len(T) == 1 + True + sage: v = T[0][0] if T[0][0] in K else T[0][1] + sage: # Let N := M \cap E(K) and L := K - v + sage: N = Graph([edge for edge in K.edge_iterator() if edge in M]) + sage: L = K.copy() + sage: L.delete_vertex(v) + sage: # Check if N is a perfect matching of L + sage: L.order() == 2*N.size() + True + + Let `B` be a maximal barrier of a matching covered graph `G` (which is, + of course, a matchable graph). The graph induced by each component of + `G - B` is factor critical:: + + sage: all((K.subgraph(vertices=connected_component)).is_factor_critical() + ....: for connected_component in K.connected_components() + ....: ) + True + + For a bicritical graph (for instance, the Petersen graph), for each + vertex the maximal barrier is a singleton set containing only that + vertex:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: u = 0 + sage: set([u]) == G.maximal_barrier(u) + True + + In a bipartite matching covered graph (for instance, the Hexahedral + graph), for a vertex, the maximal barrier is the set of vertices of + the color class that the particular vertex belongs to. In other words, + there are precisely two maximal barriers in a bipartite matching + covered graph, that is, the vertex sets of the individual color class:: + + sage: G = graphs.HexahedralGraph() + sage: H = MatchingCoveredGraph(G) + sage: A, _ = H.bipartite_sets() + sage: # needs random + sage: import random + sage: a = random.choice(list(A)) + sage: A == H.maximal_barrier(a) + True + + Maximal barriers of matching covered graph constitute a partition of + its vertex set:: + + sage: S = set() + sage: for v in H: + ....: B = tuple(sorted(list(H.maximal_barrier(v)))) + ....: S.add(B) + sage: S = list(S) + sage: # Check that S is a partition of the vertex set of H + sage: # Part 1: Check if S spans the vertex set of H + sage: sorted([u for B in S for u in B]) == sorted(list(H)) + True + sage: # Part 2: Check if each maximal barrier in S is disjoint + sage: is_disjoint = True + sage: for i in range(len(S)): + ....: for j in range(i+1, len(S)): + ....: c = [v for v in S[i] if v in S[j]] + ....: is_disjoint = (len(c) == 0) + sage: is_disjoint + True + + TESTS: + + Providing with a nonexistent vertex:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: G.maximal_barrier('') + Traceback (most recent call last): + ... + ValueError: vertex not in the graph + sage: G.maximal_barrier(100) + Traceback (most recent call last): + ... + ValueError: vertex 100 not in the graph + + REFERENCES: + + - [LZ2004]_ + - [LM2024]_ + + .. SEEALSO:: + + - :meth:`~sage.graphs.graph.Graph.is_bicritical` + - :meth:`~sage.graphs.graph.Graph.is_matching_covered` + - :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.canonical_partition` + """ + if vertex not in self: + raise ValueError('vertex {} not in the graph'.format(vertex)) + + # u: The M neighbor of vertex + matching = self.get_matching() + u = next((a if b == vertex else b) for a, b, *_ in matching if vertex in [a, b]) + + # Goal: Find the vertices w such that G - w - vertex is matchable. + # In other words, there exists an odd length M-alternating vertex-w + # path in G, starting and ending with edges in M. Alternatively, there + # exists an even length M-alternating u-w path in the graph G - vertex + # starting with an edge not in M and ending with and edge in M. + + # even: The set of all such vertex w + from sage.graphs.matching import M_alternating_even_mark + even = M_alternating_even_mark(G=self, matching=matching, + vertex=u) + + B = set([vertex]) + B.update(v for v in self if v not in even) + + return B + + @doc_index('Overwritten methods') + def has_loops(self): + r""" + Check whether there are loops in the (matching covered) graph. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.has_loops` method in + order to return ``False`` as matching covered graphs are always + free of looped edges. + + OUTPUT: + + - A boolean ``False`` is returned since matching covered graphs, by + definition, are free of self-loops. + + EXAMPLES: + + A matching covered graph, for instance the Petersen graph, is always free + of loops:: + + sage: P = graphs.PetersenGraph() + sage: G = MatchingCoveredGraph(P) + sage: G + Matching covered petersen graph: graph on 10 vertices + sage: G.has_loops() + False + sage: G.allows_loops() + False + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + + A matching covered graph may support multiple edges, still no + loops are allowed:: + + sage: K = graphs.CompleteGraph(2) + sage: G = MatchingCoveredGraph(K) + sage: G.allow_multiple_edges(True) + sage: G + Matching covered complete graph: multi-graph on 2 vertices + sage: G.add_edge(0, 1, 'label') + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label')] + sage: G.allows_loops() + False + sage: G.has_loops() + False + sage: G.allow_loops(True) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + """ + return False + @doc_index('Overwritten methods') def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, *, integrality_tolerance=1e-3): @@ -2003,6 +2346,321 @@ def has_perfect_matching(G, algorithm='Edmonds', solver=None, verbose=0, raise ValueError('algorithm must be set to \'Edmonds\', ' '\'LP_matching\' or \'LP\'') + @doc_index('Overwritten methods') + def loop_edges(self, labels=True): + r""" + Return a list of all loops in the (matching covered) graph. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.loop_edges` method + in order to return an empty list as matching covered graphs are + free of looped edges. + + INPUT: + + - ``labels`` -- boolean (default: ``True``); whether returned edges + have labels (``(u,v,l)``) or not (``(u,v)``). + + OUTPUT: + + - A list capturing the edges that are loops in the matching covered + graph; note that, the list is empty since matching covered graphs do + not contain any looped edges. + + EXAMPLES: + + A matching covered graph, for instance the Heawood graph, by + definition, is always free of loops:: + + sage: H = graphs.HeawoodGraph() + sage: G = MatchingCoveredGraph(H) + sage: G + Matching covered heawood graph: graph on 14 vertices + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.loops() + [] + sage: G.loop_edges() + [] + + A matching covered graph may support multiple edges, still no + loops are allowed:: + + sage: C = graphs.CycleGraph(4) + sage: G = MatchingCoveredGraph(C) + sage: G.allow_multiple_edges(True) + sage: G + Matching covered cycle graph: multi-graph on 4 vertices + sage: G.add_edge(0, 1, 'label') + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label'), (0, 3, None), (1, 2, None), (2, 3, None)] + sage: G.loops() + [] + sage: G.loop_edges() + [] + + One may set the ``label`` to either ``True`` or ``False``:: + + sage: G.loop_edges(labels=False) + [] + sage: G.loops(labels=True) + [] + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + """ + return [] + + @doc_index('Overwritten methods') + def loop_vertices(self): + r""" + Return a list of vertices with loops. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.loop_vertices` + method in order to return an empty list as matching covered graphs + are free of vertices that have looped edges. + + OUTPUT: + + - A list capturing the vertices that have loops in the matching covered + graph; note that, the list is empty since matching covered graphs do + not contain any looped edges. + + EXAMPLES: + + A matching covered graph, for instance the Möbius graph of order 8, by + definition, is always free of loops:: + + sage: M = graphs.MoebiusLadderGraph(4) + sage: G = MatchingCoveredGraph(M) + sage: G + Matching covered moebius ladder graph: graph on 8 vertices + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.loop_vertices() + [] + + A matching covered graph may support multiple edges, still no + loops are allowed:: + + sage: S = graphs.StaircaseGraph(4) + sage: G = MatchingCoveredGraph(S) + sage: G.allow_multiple_edges(True) + sage: G + Matching covered staircase graph: multi-graph on 8 vertices + sage: G.add_edge(0, 1, 'label') + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label'), (0, 3, None), (0, 6, None), + (1, 2, None), (1, 4, None), (2, 5, None), (2, 7, None), + (3, 4, None), (3, 6, None), (4, 5, None), (5, 7, None), + (6, 7, None)] + sage: G.loop_vertices() + [] + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + """ + return [] + + loops = loop_edges + + @doc_index('Overwritten methods') + def number_of_loops(self): + r""" + Return the number of edges that are loops. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.number_of_loops` + method in order to return 0 as matching covered graphs are free + of looped edges. + + OUTPUT: + + - An integer, 0 is returned, since matching covered graphs do not + contain zero loops. + + EXAMPLES: + + A matching covered graph, for instance the Truncated biwheel graph, + by definition, is always free of loops:: + + sage: T = graphs.TruncatedBiwheelGraph(5) + sage: G = MatchingCoveredGraph(T) + sage: G + Matching covered truncated biwheel graph: graph on 10 vertices + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.loop_vertices() + [] + sage: G.number_of_loops() + 0 + + A matching covered graph may support multiple edges, still no + loops are allowed:: + + sage: B = graphs.BiwheelGraph(4) + sage: G = MatchingCoveredGraph(B) + sage: G.allow_multiple_edges(True) + sage: G + Matching covered biwheel graph: multi-graph on 8 vertices + sage: G.add_edge(0, 1, 'label') + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label'), (0, 5, None), (0, 7, None), + (1, 2, None), (1, 6, None), (2, 3, None), (2, 7, None), + (3, 4, None), (3, 6, None), (4, 5, None), (4, 7, None), + (5, 6, None)] + sage: G.loop_vertices() + [] + sage: G.number_of_loops() + 0 + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.remove_loops` + """ + return 0 + + @doc_index('Overwritten methods') + def remove_loops(self, vertices=None): + r""" + Remove loops on vertices in ``vertices``. + + .. NOTE:: + + This method overwrites the + :meth:`~sage.graphs.generic_graph.GenericGraph.remove_loops` method + in order to return without any alteration as matching covered + graphs are free of looped edges. + + INPUT: + + - ``vertices`` -- (default: ``None``) iterator container of vertex + labels corresponding to which the looped edges are to be removed. If + ``vertices`` is ``None``, remove all loops. + + OUTPUT: + + - Nothing is returned, as a matching covered graph is already devoid of + any loops. + + EXAMPLES: + + A matching covered graph, for instance the Wheel graph of order six, is + always free of loops:: + + sage: W = graphs.WheelGraph(6) + sage: G = MatchingCoveredGraph(W) + sage: G + Matching covered wheel graph: graph on 6 vertices + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.remove_loops() + sage: G.edges(sort=True) + [(0, 1, None), (0, 2, None), (0, 3, None), (0, 4, None), + (0, 5, None), (1, 2, None), (1, 5, None), (2, 3, None), + (3, 4, None), (4, 5, None)] + + A matching covered graph may support multiple edges, still no + loops are allowed:: + + sage: K = graphs.CompleteGraph(2) + sage: G = MatchingCoveredGraph(K) + sage: G.allow_multiple_edges(True) + sage: G + Matching covered complete graph: multi-graph on 2 vertices + sage: G.add_edge(0, 1, 'label') + sage: G.add_edge(0, 0) + Traceback (most recent call last): + ... + ValueError: loops are not allowed in matching covered graphs + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label')] + sage: G.remove_loops(vertices=[0, 1]) + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label')] + sage: G.remove_loops(vertices=[0..100]) + + Note that the parameter ``vertices`` must be either ``None`` or an + iterable:: + + sage: G.remove_loops(vertices='') + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label')] + sage: G.remove_loops(vertices=None) + sage: G.edges(sort=False) + [(0, 1, None), (0, 1, 'label')] + sage: G.remove_loops(vertices=0) + Traceback (most recent call last): + ... + TypeError: 'Integer' object is not iterable + sage: G.remove_loops(vertices=False) + Traceback (most recent call last): + ... + TypeError: 'bool' object is not iterable + + .. SEEALSO:: + + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allow_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.allows_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.has_loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_edges`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loop_vertices`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.loops`, + :meth:`~sage.graphs.matching_covered_graph.MatchingCoveredGraph.number_of_loops` + """ + from collections.abc import Iterable + + if vertices is not None and not isinstance(vertices, Iterable): + raise TypeError(f'\'{vertices.__class__.__name__}\' ' + 'object is not iterable') + @doc_index('Miscellaneous methods') def update_matching(self, matching): r""" @@ -2090,4 +2748,4 @@ def update_matching(self, matching): raise exception -__doc__ = __doc__.replace('{INDEX_OF_METHODS}', gen_thematic_rest_table_index(MatchingCoveredGraph, only_local_functions=False)) \ No newline at end of file +__doc__ = __doc__.replace('{INDEX_OF_METHODS}', gen_thematic_rest_table_index(MatchingCoveredGraph, only_local_functions=False)) diff --git a/src/sage/graphs/meson.build b/src/sage/graphs/meson.build index d88f1942daf..842501734e5 100644 --- a/src/sage/graphs/meson.build +++ b/src/sage/graphs/meson.build @@ -1,11 +1,17 @@ bliss = cc.find_library('bliss', required: false, disabler: true) -mcqd = cc.find_library('mcqd', required: false, disabler: true) +# mcqd is a header-only library +if cc.has_header('mcqd.h') + mcqd = declare_dependency() +else + mcqd = disabler() +endif cliquer = cc.find_library('cliquer') # Cannot be found via pkg-config planarity = cc.find_library('planarity') py.install_sources( + '__init__.py', 'all.py', 'all__sagemath_bliss.py', 'all__sagemath_mcqd.py', diff --git a/src/sage/graphs/path_enumeration.pyx b/src/sage/graphs/path_enumeration.pyx index 50b992692e4..aa16b1dc7b1 100644 --- a/src/sage/graphs/path_enumeration.pyx +++ b/src/sage/graphs/path_enumeration.pyx @@ -361,7 +361,7 @@ def shortest_simple_paths(self, source, target, weight_function=None, ....: report_edges=True, report_weight=True)) [(20, [(1, 3), (3, 5)]), (40, [(1, 2), (2, 5)]), (60, [(1, 4), (4, 5)])] sage: list(g.shortest_simple_paths(1, 5, report_edges=True, report_weight=True)) - [(2, [(1, 4), (4, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 2), (2, 5)])] + [(2, [(1, 2), (2, 5)]), (2, [(1, 3), (3, 5)]), (2, [(1, 4), (4, 5)])] sage: list(g.shortest_simple_paths(1, 5, by_weight=True, report_edges=True)) [[(1, 3), (3, 5)], [(1, 2), (2, 5)], [(1, 4), (4, 5)]] sage: list(g.shortest_simple_paths(1, 5, by_weight=True, algorithm='Feng', @@ -432,12 +432,12 @@ def shortest_simple_paths(self, source, target, weight_function=None, ....: (6, 9, 1), (9, 5, 1), (4, 2, 1), (9, 3, 1), ....: (9, 10, 1), (10, 5, 1), (9, 11, 1), (11, 10, 1)]) sage: list(g.shortest_simple_paths(1, 5, algorithm='Feng')) - [[1, 7, 8, 5], - [1, 6, 9, 5], - [1, 6, 9, 10, 5], + [[1, 6, 9, 5], + [1, 7, 8, 5], [1, 2, 3, 4, 5], - [1, 6, 9, 3, 4, 5], - [1, 6, 9, 11, 10, 5]] + [1, 6, 9, 10, 5], + [1, 6, 9, 11, 10, 5], + [1, 6, 9, 3, 4, 5]] sage: # needs sage.combinat sage: G = digraphs.DeBruijn(2, 3) @@ -957,11 +957,11 @@ def feng_k_shortest_simple_paths(self, source, target, weight_function=None, sage: list(feng_k_shortest_simple_paths(g, 1, 5, by_weight=True)) [[1, 3, 5], [1, 2, 5], [1, 4, 5]] sage: list(feng_k_shortest_simple_paths(g, 1, 5)) - [[1, 4, 5], [1, 3, 5], [1, 2, 5]] + [[1, 2, 5], [1, 3, 5], [1, 4, 5]] sage: list(feng_k_shortest_simple_paths(g, 1, 1)) [[1]] sage: list(feng_k_shortest_simple_paths(g, 1, 5, report_edges=True, labels=True)) - [[(1, 4, 30), (4, 5, 30)], [(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)]] + [[(1, 2, 20), (2, 5, 20)], [(1, 3, 10), (3, 5, 10)], [(1, 4, 30), (4, 5, 30)]] sage: list(feng_k_shortest_simple_paths(g, 1, 5, report_edges=True, labels=True, by_weight=True)) [[(1, 3, 10), (3, 5, 10)], [(1, 2, 20), (2, 5, 20)], [(1, 4, 30), (4, 5, 30)]] sage: list(feng_k_shortest_simple_paths(g, 1, 5, report_edges=True, labels=True, by_weight=True, report_weight=True)) @@ -974,7 +974,7 @@ def feng_k_shortest_simple_paths(self, source, target, weight_function=None, sage: list(feng_k_shortest_simple_paths(g, 1, 6, by_weight = True)) [[1, 3, 5, 6], [1, 2, 5, 6], [1, 4, 5, 6], [1, 6]] sage: list(feng_k_shortest_simple_paths(g, 1, 6)) - [[1, 6], [1, 4, 5, 6], [1, 3, 5, 6], [1, 2, 5, 6]] + [[1, 6], [1, 2, 5, 6], [1, 3, 5, 6], [1, 4, 5, 6]] sage: list(feng_k_shortest_simple_paths(g, 1, 6, report_edges=True, labels=True, by_weight=True, report_weight=True)) [(25, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), (45, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), @@ -982,9 +982,9 @@ def feng_k_shortest_simple_paths(self, source, target, weight_function=None, (100, [(1, 6, 100)])] sage: list(feng_k_shortest_simple_paths(g, 1, 6, report_edges=True, labels=True, report_weight=True)) [(1, [(1, 6, 100)]), - (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)]), + (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)]), (3, [(1, 3, 10), (3, 5, 10), (5, 6, 5)]), - (3, [(1, 2, 20), (2, 5, 20), (5, 6, 5)])] + (3, [(1, 4, 30), (4, 5, 30), (5, 6, 5)])] sage: from sage.graphs.path_enumeration import feng_k_shortest_simple_paths sage: g = DiGraph([(1, 2, 5), (2, 3, 0), (1, 4, 2), (4, 5, 1), (5, 3, 0)]) sage: list(feng_k_shortest_simple_paths(g, 1, 3, by_weight=True)) @@ -1031,30 +1031,30 @@ def feng_k_shortest_simple_paths(self, source, target, weight_function=None, (27, [(1, 2, 1), (2, 3, 1), (3, 8, 5), (8, 9, 2), (9, 11, 10), (11, 6, 8)]), (105, [(1, 2, 1), (2, 3, 1), (3, 4, 1), (4, 5, 2), (5, 6, 100)])] sage: list(feng_k_shortest_simple_paths(g, 1, 6)) - [[1, 2, 3, 8, 9, 6], + [[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 7, 6], - [1, 2, 3, 4, 5, 6], - [1, 2, 3, 8, 9, 10, 6], - [1, 2, 3, 8, 9, 11, 6]] + [1, 2, 3, 8, 9, 6], + [1, 2, 3, 8, 9, 11, 6], + [1, 2, 3, 8, 9, 10, 6]] sage: from sage.graphs.path_enumeration import feng_k_shortest_simple_paths sage: g = DiGraph([(1, 2, 1), (2, 3, 1), (3, 4, 1), (4, 5, 1), ....: (1, 7, 1), (7, 8, 1), (8, 5, 1), (1, 6, 1), ....: (6, 9, 1), (9, 5, 1), (4, 2, 1), (9, 3, 1), ....: (9, 10, 1), (10, 5, 1), (9, 11, 1), (11, 10, 1)]) sage: list(feng_k_shortest_simple_paths(g, 1, 5)) - [[1, 7, 8, 5], - [1, 6, 9, 5], - [1, 6, 9, 10, 5], + [[1, 6, 9, 5], + [1, 7, 8, 5], [1, 2, 3, 4, 5], - [1, 6, 9, 3, 4, 5], - [1, 6, 9, 11, 10, 5]] - sage: list(feng_k_shortest_simple_paths(g, 1, 5, by_weight=True)) - [[1, 7, 8, 5], - [1, 6, 9, 5], [1, 6, 9, 10, 5], + [1, 6, 9, 11, 10, 5], + [1, 6, 9, 3, 4, 5]] + sage: list(feng_k_shortest_simple_paths(g, 1, 5, by_weight=True)) + [[1, 6, 9, 5], + [1, 7, 8, 5], [1, 2, 3, 4, 5], - [1, 6, 9, 3, 4, 5], - [1, 6, 9, 11, 10, 5]] + [1, 6, 9, 10, 5], + [1, 6, 9, 11, 10, 5], + [1, 6, 9, 3, 4, 5]] sage: from sage.graphs.path_enumeration import feng_k_shortest_simple_paths sage: g = DiGraph([(1, 2, 5), (6, 3, 0), (2, 6, 6), (1, 4, 15), ....: (4, 5, 1), (4, 3, 0), (7, 1, 2), (8, 7, 1)]) diff --git a/src/sage/graphs/strongly_regular_db.pyx b/src/sage/graphs/strongly_regular_db.pyx index 72db0131c59..2f6f8339aa5 100644 --- a/src/sage/graphs/strongly_regular_db.pyx +++ b/src/sage/graphs/strongly_regular_db.pyx @@ -1068,25 +1068,25 @@ def is_polhill(int v, int k, int l, int mu): # We now define the P_{i,j}. see section 6. P = {} - P[0,1] = list(range((-1) + 1 , 2**(s-2)+1)) - P[1,1] = list(range((-1) + 2**(s-2)+2 , 2**(s-1)+1)) - P[2,1] = list(range((-1) + 2**(s-1)+2 , 2**(s-1)+2**(s-2)+1)) - P[3,1] = list(range((-1) + 2**(s-1)+2**(s-2)+2, 2**(s)+1)) - - P[0,2] = list(range((-1) + 2**(s-2)+2 , 2**(s-1)+2)) - P[1,2] = list(range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+2)) - P[2,2] = list(range((-1) + 2**(s-1)+2**(s-2)+3, 2**(s)+1)) + [0] - P[3,2] = list(range((-1) + 2 , 2**(s-2)+1)) - - P[0,3] = list(range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+3)) - P[1,3] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [0,1] - P[2,3] = list(range((-1) + 3 , 2**(s-2)+2)) - P[3,3] = list(range((-1) + 2**(s-2)+3 , 2**(s-1)+2)) - - P[0,4] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) - P[1,4] = list(range((-1) + 3 , 2**(s-2)+1)) + [2**(s-1)+1,2**(s-1)+2**(s-2)+2] - P[2,4] = list(range((-1) + 2**(s-2)+3 , 2**(s-1)+1)) + [2**(s-1)+2**(s-2)+1,1] - P[3,4] = list(range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+1)) + [2**(s-2)+1,0] + P[0, 1] = list(range((-1) + 1, 2**(s-2)+1)) + P[1, 1] = list(range((-1) + 2**(s-2)+2, 2**(s-1)+1)) + P[2, 1] = list(range((-1) + 2**(s-1)+2, 2**(s-1)+2**(s-2)+1)) + P[3, 1] = list(range((-1) + 2**(s-1)+2**(s-2)+2, 2**(s)+1)) + + P[0, 2] = list(range((-1) + 2**(s-2)+2, 2**(s-1)+2)) + P[1, 2] = list(range((-1) + 2**(s-1)+3, 2**(s-1)+2**(s-2)+2)) + P[2, 2] = list(range((-1) + 2**(s-1)+2**(s-2)+3, 2**(s)+1)) + [0] + P[3, 2] = list(range((-1) + 2, 2**(s-2)+1)) + + P[0, 3] = list(range((-1) + 2**(s-1)+3, 2**(s-1)+2**(s-2)+3)) + P[1, 3] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [0,1] + P[2, 3] = list(range((-1) + 3, 2**(s-2)+2)) + P[3, 3] = list(range((-1) + 2**(s-2)+3, 2**(s-1)+2)) + + P[0, 4] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + P[1, 4] = list(range((-1) + 3, 2**(s-2)+1)) + [2**(s-1)+1,2**(s-1)+2**(s-2)+2] + P[2, 4] = list(range((-1) + 2**(s-2)+3, 2**(s-1)+1)) + [2**(s-1)+2**(s-2)+1,1] + P[3, 4] = list(range((-1) + 2**(s-1)+3, 2**(s-1)+2**(s-2)+1)) + [2**(s-2)+1,0] R = {x: copy(P[x]) for x in P} @@ -1100,10 +1100,10 @@ def is_polhill(int v, int k, int l, int mu): # We now define the R_{i,j}. see *end* of section 6. - R[0,3] = list(range((-1) + 2**(s-1)+3 , 2**(s-1)+2**(s-2)+2)) - R[1,3] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [0,1,2**(s-1)+2**(s-2)+2] - R[0,4] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [2**(s-1)+2**(s-2)+2] - R[1,4] = list(range((-1) + 3 , 2**(s-2)+1)) + [2**(s-1)+1] + R[0, 3] = list(range((-1) + 2**(s-1)+3, 2**(s-1)+2**(s-2)+2)) + R[1, 3] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [0,1,2**(s-1)+2**(s-2)+2] + R[0, 4] = list(range((-1) + 2**(s-1)+2**(s-2)+4, 2**(s)+1)) + [2**(s-1)+2**(s-2)+2] + R[1, 4] = list(range((-1) + 3, 2**(s-2)+1)) + [2**(s-1)+1] for x in R: R[x] = [K[i] for i in R[x]] diff --git a/src/sage/graphs/traversals.pyx b/src/sage/graphs/traversals.pyx index 0ce87c3ad11..11cdb87c8b9 100644 --- a/src/sage/graphs/traversals.pyx +++ b/src/sage/graphs/traversals.pyx @@ -63,16 +63,17 @@ from collections import deque from libc.string cimport memset from libc.stdint cimport uint32_t -from libcpp.queue cimport priority_queue -from libcpp.pair cimport pair from libcpp.vector cimport vector from cysignals.signals cimport sig_on, sig_off from memory_allocator cimport MemoryAllocator +from sage.data_structures.pairing_heap cimport PairingHeap_of_n_integers +from sage.graphs.base.c_graph cimport CGraph, CGraphBackend +from sage.graphs.base.static_sparse_backend cimport StaticSparseCGraph +from sage.graphs.base.static_sparse_backend cimport StaticSparseBackend from sage.graphs.base.static_sparse_graph cimport init_short_digraph from sage.graphs.base.static_sparse_graph cimport free_short_digraph from sage.graphs.base.static_sparse_graph cimport out_degree -from sage.graphs.base.c_graph cimport CGraph, CGraphBackend from sage.graphs.graph_decompositions.slice_decomposition cimport \ extended_lex_BFS @@ -753,8 +754,7 @@ def lex_M(self, triangulation=False, labels=False, initial_vertex=None, algorith - ``labels`` -- boolean (default: ``False``); whether to return the labels assigned to each vertex - - ``initial_vertex`` -- (default: ``None``) the first vertex to - consider + - ``initial_vertex`` -- (default: ``None``); the first vertex to consider - ``algorithm`` -- string (default: ``None``); one of the following algorithms: @@ -820,6 +820,18 @@ def lex_M(self, triangulation=False, labels=False, initial_vertex=None, algorith sage: g.lex_M() [6, 4, 5, 3, 2, 1] + The ordering depends on the initial vertex:: + + sage: G = graphs.HouseGraph() + sage: G.lex_M(algorithm='lex_M_slow', initial_vertex=0) + [4, 3, 2, 1, 0] + sage: G.lex_M(algorithm='lex_M_slow', initial_vertex=2) + [1, 4, 3, 0, 2] + sage: G.lex_M(algorithm='lex_M_fast', initial_vertex=0) + [4, 3, 2, 1, 0] + sage: G.lex_M(algorithm='lex_M_fast', initial_vertex=2) + [1, 4, 3, 0, 2] + TESTS: ``'lex_M_fast'`` cannot return labels:: @@ -1127,6 +1139,18 @@ def lex_M_fast(G, triangulation=False, initial_vertex=None): Traceback (most recent call last): ... ValueError: 'foo' is not a graph vertex + + Immutable graphs:: + + sage: from sage.graphs.traversals import lex_M_fast + sage: G = graphs.RandomGNP(10, .7) + sage: G._backend + + sage: H = Graph(G, immutable=True) + sage: H._backend + + sage: lex_M_fast(G) == lex_M_fast(H) + True """ if initial_vertex is not None and initial_vertex not in G: raise ValueError("'{}' is not a graph vertex".format(initial_vertex)) @@ -1136,16 +1160,19 @@ def lex_M_fast(G, triangulation=False, initial_vertex=None): # ==> Initialization - cdef list int_to_v = list(G) cdef int i, j, k, v, w, z - if initial_vertex is not None: - # We put the initial vertex at first place in the ordering - i = int_to_v.index(initial_vertex) - int_to_v[0], int_to_v[i] = int_to_v[i], int_to_v[0] - + cdef list int_to_v + cdef StaticSparseCGraph cg cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_v) + if isinstance(G, StaticSparseBackend): + cg = G._cg + sd = cg.g + int_to_v = cg._vertex_to_labels + else: + int_to_v = list(G) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_v) + cdef uint32_t* p_tmp cdef uint32_t* p_end @@ -1153,6 +1180,11 @@ def lex_M_fast(G, triangulation=False, initial_vertex=None): cdef list unnumbered_vertices = list(range(n)) + if initial_vertex is not None: + # We put the initial vertex at the first place + i = int_to_v.index(initial_vertex) + unnumbered_vertices[0], unnumbered_vertices[i] = unnumbered_vertices[i], unnumbered_vertices[0] + cdef MemoryAllocator mem = MemoryAllocator() cdef int* label = mem.allocarray(n, sizeof(int)) cdef int* alpha = mem.allocarray(n, sizeof(int)) @@ -1237,7 +1269,8 @@ def lex_M_fast(G, triangulation=False, initial_vertex=None): k += 2 label[w] = k - free_short_digraph(sd) + if not isinstance(G, StaticSparseBackend): + free_short_digraph(sd) cdef list ordering = [int_to_v[alpha[i]] for i in range(n)] @@ -1354,9 +1387,9 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None sage: G.maximum_cardinality_search(initial_vertex=0) [3, 2, 1, 0] sage: G.maximum_cardinality_search(initial_vertex=1) - [0, 3, 2, 1] + [3, 2, 0, 1] sage: G.maximum_cardinality_search(initial_vertex=2) - [0, 1, 3, 2] + [0, 3, 1, 2] sage: G.maximum_cardinality_search(initial_vertex=3) [0, 1, 2, 3] sage: G.maximum_cardinality_search(initial_vertex=3, reverse=True) @@ -1388,6 +1421,17 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None Traceback (most recent call last): ... ValueError: vertex (17) is not a vertex of the graph + + Immutable graphs;: + + sage: G = graphs.RandomGNP(10, .7) + sage: G._backend + + sage: H = Graph(G, immutable=True) + sage: H._backend + + sage: G.maximum_cardinality_search() == H.maximum_cardinality_search() + True """ if tree: from sage.graphs.digraph import DiGraph @@ -1398,17 +1442,27 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None if N == 1: return (list(G), DiGraph(G)) if tree else list(G) - cdef list int_to_vertex = list(G) + cdef list int_to_vertex + cdef StaticSparseCGraph cg + cdef short_digraph sd + if isinstance(G, StaticSparseBackend): + cg = G._cg + sd = cg.g + int_to_vertex = cg._vertex_to_labels + else: + int_to_vertex = list(G) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) if initial_vertex is None: initial_vertex = 0 elif initial_vertex in G: - initial_vertex = int_to_vertex.index(initial_vertex) + if isinstance(G, StaticSparseBackend): + initial_vertex = cg._vertex_to_int[initial_vertex] + else: + initial_vertex = int_to_vertex.index(initial_vertex) else: raise ValueError("vertex ({0}) is not a vertex of the graph".format(initial_vertex)) - cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) cdef uint32_t** p_vertices = sd.neighbors cdef uint32_t* p_tmp cdef uint32_t* p_end @@ -1420,27 +1474,18 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None cdef int i, u, v for i in range(N): - weight[i] = 0 - seen[i] = False pred[i] = i - # We emulate a heap with decrease key operation using a priority queue. - # A vertex can be inserted multiple times (up to its degree), but only the - # first extraction (with maximum weight) matters. The size of the queue will - # never exceed O(m). - cdef priority_queue[pair[int, int]] pq - pq.push((0, initial_vertex)) + # We emulate a max-heap data structure using a min-heap with negative values + cdef PairingHeap_of_n_integers P = PairingHeap_of_n_integers(N) + P.push(initial_vertex, 0) # The ordering alpha is feed in reversed order and revert afterword cdef list alpha = [] - while not pq.empty(): - _, u = pq.top() - pq.pop() - if seen[u]: - # We use a lazy decrease key mode, so u can be several times in pq - continue - + while P: + u = P.top_item() + P.pop() alpha.append(int_to_vertex[u]) seen[u] = True @@ -1450,12 +1495,13 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None v = p_tmp[0] if not seen[v]: weight[v] += 1 - pq.push((weight[v], v)) + P.decrease(v, -weight[v]) if pred[v] == v: pred[v] = u p_tmp += 1 - free_short_digraph(sd) + if not isinstance(G, StaticSparseBackend): + free_short_digraph(sd) if len(alpha) < N: raise ValueError("the input graph is not connected") @@ -1762,16 +1808,18 @@ def maximum_cardinality_search_M(G, initial_vertex=None): Traceback (most recent call last): ... ValueError: vertex (17) is not a vertex of the graph - """ - cdef list int_to_vertex = list(G) - if initial_vertex is None: - initial_vertex = 0 - elif initial_vertex in G: - initial_vertex = int_to_vertex.index(initial_vertex) - else: - raise ValueError("vertex ({0}) is not a vertex of the graph".format(initial_vertex)) + Immutable graphs:: + sage: G = graphs.RandomGNP(10, .7) + sage: G._backend + + sage: H = Graph(G, immutable=True) + sage: H._backend + + sage: G.maximum_cardinality_search_M() == H.maximum_cardinality_search_M() + True + """ cdef int N = G.order() if not N: return ([], [], []) @@ -1781,8 +1829,26 @@ def maximum_cardinality_search_M(G, initial_vertex=None): # Copying the whole graph to obtain the list of neighbors quicker than by # calling out_neighbors. This data structure is well documented in the # module sage.graphs.base.static_sparse_graph + cdef list int_to_vertex + cdef StaticSparseCGraph cg cdef short_digraph sd - init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) + if isinstance(G, StaticSparseBackend): + cg = G._cg + sd = cg.g + int_to_vertex = cg._vertex_to_labels + else: + int_to_vertex = list(G) + init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex) + + if initial_vertex is None: + initial_vertex = 0 + elif initial_vertex in G: + if isinstance(G, StaticSparseBackend): + initial_vertex = cg._vertex_to_int[initial_vertex] + else: + initial_vertex = int_to_vertex.index(initial_vertex) + else: + raise ValueError("vertex ({0}) is not a vertex of the graph".format(initial_vertex)) cdef MemoryAllocator mem = MemoryAllocator() cdef int* alpha = mem.calloc(N, sizeof(int)) @@ -1794,7 +1860,8 @@ def maximum_cardinality_search_M(G, initial_vertex=None): maximum_cardinality_search_M_short_digraph(sd, initial_vertex, alpha, alpha_inv, F, X) sig_off() - free_short_digraph(sd) + if not isinstance(G, StaticSparseBackend): + free_short_digraph(sd) cdef int u, v return ([int_to_vertex[alpha[u]] for u in range(N)], diff --git a/src/sage/groups/abelian_gps/abelian_group.py b/src/sage/groups/abelian_gps/abelian_group.py index ec5bc722d64..67a861555cb 100644 --- a/src/sage/groups/abelian_gps/abelian_group.py +++ b/src/sage/groups/abelian_gps/abelian_group.py @@ -365,6 +365,13 @@ def _normalize(n, gens_orders=None, names='f'): Traceback (most recent call last): ... TypeError: unable to convert 's' to an integer + + Verify that :issue:`38967` is fixed:: + + sage: AbelianGroup([-4]) + Traceback (most recent call last): + ... + ValueError: orders of generators cannot be negative but they are (-4,) """ if gens_orders is None: if isinstance(n, (list, tuple)): @@ -376,6 +383,8 @@ def _normalize(n, gens_orders=None, names='f'): if len(gens_orders) < n: gens_orders = [0] * (n - len(gens_orders)) + list(gens_orders) gens_orders = tuple(ZZ(i) for i in gens_orders) + if any(i < 0 for i in gens_orders): + raise ValueError(f'orders of generators cannot be negative but they are {gens_orders}') if len(gens_orders) > n: raise ValueError('gens_orders (='+str(gens_orders)+') must have length n (='+str(n)+')') if isinstance(names, list): diff --git a/src/sage/groups/affine_gps/group_element.py b/src/sage/groups/affine_gps/group_element.py index b1e3cd1e0cb..190a0180d1b 100644 --- a/src/sage/groups/affine_gps/group_element.py +++ b/src/sage/groups/affine_gps/group_element.py @@ -30,15 +30,17 @@ - Volker Braun """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 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/ +# **************************************************************************** + +from copy import copy from sage.structure.element import Matrix from sage.misc.cachefunc import cached_method @@ -119,15 +121,17 @@ def __init__(self, parent, A, b=0, convert=True, check=True): A = A.matrix() except AttributeError: pass - if isinstance(A, Matrix) and A.nrows() == A.ncols() == parent.degree()+1: + if isinstance(A, Matrix) and A.nrows() == A.ncols() == parent.degree() + 1: g = A d = parent.degree() A = g.submatrix(0, 0, d, d) - b = [ g[i,d] for i in range(d) ] + b = [g[i,d] for i in range(d)] convert = True if convert: A = parent.matrix_space()(A) b = parent.vector_space()(b) + A.set_immutable() + b.set_immutable() if check: # Note: the coercion framework expects that we raise TypeError for invalid input if not isinstance(A, Matrix): @@ -138,6 +142,12 @@ def __init__(self, parent, A, b=0, convert=True, check=True): raise TypeError('b must be an element of ' + str(parent.vector_space())) parent._element_constructor_check(A, b) super().__init__(parent) + if not A.is_immutable(): + A = copy(A) + A.set_immutable() + if not b.is_immutable(): + b = copy(b) + b.set_immutable() self._A = A self._b = b @@ -151,10 +161,12 @@ def A(self): sage: G = AffineGroup(3, QQ) sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12]) - sage: g.A() + sage: A = g.A(); A [1 2 3] [4 5 6] [7 8 0] + sage: A.is_immutable() + True """ return self._A @@ -168,8 +180,10 @@ def b(self): sage: G = AffineGroup(3, QQ) sage: g = G([1,2,3,4,5,6,7,8,0], [10,11,12]) - sage: g.b() + sage: b = g.b(); b (10, 11, 12) + sage: b.is_immutable() + True """ return self._b @@ -345,7 +359,9 @@ def _mul_(self, other): parent = self.parent() A = self._A * other._A b = self._b + self._A * other._b - return parent.element_class(parent, A, b, check=False) + A.set_immutable() + b.set_immutable() + return parent.element_class(parent, A, b, convert=False, check=False) def __call__(self, v): """ @@ -439,13 +455,14 @@ def _act_on_(self, x, self_on_left): x |-> [0 1] x + [0] sage: v = vector(GF(3), [1,-1]); v (1, 2) - sage: g*v + sage: g * v (1, 2) - sage: g*v == g.A() * v + g.b() + sage: g * v == g.A() * v + g.b() True """ if self_on_left: return self(x) + return None def __invert__(self): """ @@ -472,7 +489,9 @@ def __invert__(self): parent = self.parent() A = parent.matrix_space()(~self._A) b = -A * self.b() - return parent.element_class(parent, A, b, check=False) + A.set_immutable() + b.set_immutable() + return parent.element_class(parent, A, b, convert=False, check=False) def _richcmp_(self, other, op): """ @@ -497,6 +516,27 @@ def _richcmp_(self, other, op): return richcmp(self._b, other._b, op) + def __hash__(self): + """ + Return the hash of ``self``. + + OUTPUT: int + + EXAMPLES:: + + sage: F = AffineGroup(3, QQ) + sage: g = F([1,2,3,4,5,6,7,8,0], [10,11,12]) + sage: h = F([1,2,3,4,5,6,7,8,0], [10,11,0]) + sage: hash(g) == hash(h) + False + sage: hash(g) == hash(copy(g)) + True + sage: f = g * h + sage: hash(f) == hash(~f) + False + """ + return hash((self._A, self._b)) + def list(self): """ Return list representation of ``self``. diff --git a/src/sage/groups/braid.py b/src/sage/groups/braid.py index 8945175cf7a..ce0375b121f 100644 --- a/src/sage/groups/braid.py +++ b/src/sage/groups/braid.py @@ -67,36 +67,39 @@ ############################################################################## from itertools import combinations + +from sage.algebras.free_algebra import FreeAlgebra from sage.categories.action import Action from sage.categories.groups import Groups -from sage.combinat.permutation import Permutation -from sage.combinat.permutation import Permutations +from sage.combinat.permutation import Permutation, Permutations from sage.combinat.subset import Subsets from sage.features.sagemath import sage__libs__braiding +from sage.functions.generalized import sign from sage.groups.artin import FiniteTypeArtinGroup, FiniteTypeArtinGroupElement -from sage.groups.finitely_presented import FinitelyPresentedGroup -from sage.groups.finitely_presented import GroupMorphismWithGensImages +from sage.groups.finitely_presented import ( + FinitelyPresentedGroup, + GroupMorphismWithGensImages, +) from sage.groups.free_group import FreeGroup, is_FreeGroup -from sage.functions.generalized import sign -from sage.groups.perm_gps.permgroup_named import SymmetricGroup -from sage.groups.perm_gps.permgroup_named import SymmetricGroupElement +from sage.groups.perm_gps.permgroup_named import SymmetricGroup, SymmetricGroupElement from sage.libs.gap.libgap import libgap from sage.matrix.constructor import identity_matrix, matrix +from sage.misc.cachefunc import cached_method from sage.misc.lazy_attribute import lazy_attribute from sage.misc.lazy_import import lazy_import -from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod from sage.rings.integer import Integer -from sage.rings.integer_ring import IntegerRing +from sage.rings.integer_ring import ZZ from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.sets.set import Set from sage.structure.element import Expression -from sage.structure.richcmp import richcmp, rich_to_bool +from sage.structure.richcmp import rich_to_bool, richcmp lazy_import('sage.libs.braiding', ['leftnormalform', 'rightnormalform', 'centralizer', 'supersummitset', 'greatestcommondivisor', 'leastcommonmultiple', 'conjugatingbraid', 'ultrasummitset', - 'thurston_type', 'rigidity', 'sliding_circuits'], + 'thurston_type', 'rigidity', 'sliding_circuits', 'send_to_sss', + 'send_to_uss', 'send_to_sc', 'trajectory', 'cyclic_slidings' ], feature=sage__libs__braiding()) lazy_import('sage.knots.knot', 'Knot') @@ -267,7 +270,7 @@ def burau_matrix(self, var='t', reduced=False): - :wikipedia:`Burau_representation` - [Squ1984]_ """ - R = LaurentPolynomialRing(IntegerRing(), var) + R = LaurentPolynomialRing(ZZ, var) t = R.gen() n = self.strands() if not reduced: @@ -418,7 +421,7 @@ def alexander_polynomial(self, var='t', normalized=True): """ n = self.strands() p = (self.burau_matrix(reduced=True) - identity_matrix(n - 1)).det() - K, t = LaurentPolynomialRing(IntegerRing(), var).objgen() + K, t = LaurentPolynomialRing(ZZ, var).objgen() if p == 0: return K.zero() qn = sum(t**i for i in range(n)) @@ -524,8 +527,8 @@ def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, aspect_ratio Graphics object consisting of 12 graphics primitives """ from sage.plot.bezier_path import bezier_path - from sage.plot.plot import Graphics, line from sage.plot.colors import rainbow + from sage.plot.plot import Graphics, line if orientation == 'top-bottom': orx = 0 ory = -1 @@ -621,8 +624,8 @@ def plot3d(self, color='rainbow'): sage: b.plot3d(color=["red", "blue", "red", "blue"]) # needs sage.plot sage.symbolic Graphics3d Object """ - from sage.plot.plot3d.shapes2 import bezier3d from sage.plot.colors import rainbow + from sage.plot.plot3d.shapes2 import bezier3d b = [] n = self.strands() if isinstance(color, (list, tuple)): @@ -776,7 +779,7 @@ def TL_matrix(self, drain_size, variab=None, sparse=True): - [Jon2005]_ """ if variab is None: - R = LaurentPolynomialRing(IntegerRing(), 'A') + R = LaurentPolynomialRing(ZZ, 'A') else: R = variab.parent() rep = self.parent().TL_representation(drain_size, variab) @@ -857,7 +860,6 @@ def links_gould_polynomial(self, varnames=None, use_symbolics=False): - [MW2012]_ """ - from sage.rings.integer_ring import ZZ if varnames is not None: poly = self.links_gould_polynomial(use_symbolics=use_symbolics) R = LaurentPolynomialRing(ZZ, varnames) @@ -935,7 +937,7 @@ def tropical_coordinates(self): coord[k+2] = x2 + sign*(min(y2, 0) + min(min(y1, 0) + sign*z, 0)) from sage.rings.semirings.tropical_semiring import TropicalSemiring - T = TropicalSemiring(IntegerRing()) + T = TropicalSemiring(ZZ) return [T(_) for _ in coord] def markov_trace(self, variab=None, normalized=True): @@ -980,9 +982,9 @@ def markov_trace(self, variab=None, normalized=True): Univariate Laurent Polynomial Ring in A over Integer Ring """ if variab is None: - R = LaurentPolynomialRing(IntegerRing(), 'A') + R = LaurentPolynomialRing(ZZ, 'A') A = R.gens()[0] - one = IntegerRing().one() + one = ZZ.one() quantum_integer = lambda d: R({i: one for i in range(-2*d, 2*d+1, 4)}) else: A = variab @@ -1125,7 +1127,6 @@ def jones_polynomial(self, variab=None, skein_normalization=False): else: return self._jones_polynomial(variab) else: - from sage.rings.integer_ring import ZZ if variab is None: variab = 't' if not isinstance(variab, Expression): @@ -1189,8 +1190,8 @@ def _enhanced_states(self): ((6, 0), [(2, [((1, 1), [], [([(0, 0), (1, 2)], 0), ([(0, 2), (1, 0)], 0)])])])] """ - from sage.graphs.graph import Graph from sage.functions.generalized import sgn + from sage.graphs.graph import Graph crossinglist = self.Tietze() ncross = len(crossinglist) writhe = 0 @@ -1326,7 +1327,7 @@ def _annular_khovanov_complex_cached(self, qagrad, ring=None): """ from sage.homology.chain_complex import ChainComplex if ring is None: - ring = IntegerRing() + ring = ZZ states = self._enhanced_states() if qagrad in states: bases = states[qagrad] @@ -1402,13 +1403,13 @@ def annular_khovanov_complex(self, qagrad=None, ring=None): 0: []} """ if ring is None: - ring = IntegerRing() + ring = ZZ if qagrad is None: return {qa: self._annular_khovanov_complex_cached(qa, ring) for qa in self._enhanced_states()} return self._annular_khovanov_complex_cached(qagrad, ring) - def annular_khovanov_homology(self, qagrad=None, ring=IntegerRing()): + def annular_khovanov_homology(self, qagrad=None, ring=ZZ): r""" Return the annular Khovanov homology of a closure of a braid. @@ -1743,7 +1744,7 @@ def conjugating_braid(self, other): cb[0][0] %= 2 return B._element_from_libbraiding(cb) - def is_conjugated(self, other): + def is_conjugated(self, other) -> bool: """ Check if the two braids are conjugated. @@ -1908,7 +1909,7 @@ def thurston_type(self): """ return thurston_type(self) - def is_reducible(self): + def is_reducible(self) -> bool: """ Check whether the braid is reducible. @@ -1924,7 +1925,7 @@ def is_reducible(self): """ return self.thurston_type() == 'reducible' - def is_periodic(self): + def is_periodic(self) -> bool: """ Check whether the braid is periodic. @@ -1940,9 +1941,9 @@ def is_periodic(self): """ return self.thurston_type() == 'periodic' - def is_pseudoanosov(self): + def is_pseudoanosov(self) -> bool: """ - Check if the braid is pseudo-anosov. + Check if the braid is pseudo-Anosov. EXAMPLES:: @@ -2093,24 +2094,24 @@ def deformed_burau_matrix(self, variab='q'): sage: burau.subs({t:q}).change_ring(db_base) == db_simp True """ - R = LaurentPolynomialRing(IntegerRing(), variab) + R = LaurentPolynomialRing(ZZ, variab) + n = self.strands() tz = self.Tietze() - m = len(tz) - from sage.algebras.free_algebra import FreeAlgebra - alg = FreeAlgebra(R, m*3, - [f'{s}p_{i}' for i in range(m) if tz[i] > 0 - for s in 'bca'] - + [f'{s}m_{i}' for i in range(m) if tz[i] < 0 - for s in 'bca']) - gen_indices = ([i for i in range(m) if tz[i] > 0] - + [i for i in range(m) if tz[i] < 0]) - - M = identity_matrix(alg, n) + m3 = len(tz) * 3 + plus = [i for i, tzi in enumerate(tz) if tzi > 0] + minus = [i for i, tzi in enumerate(tz) if tzi < 0] + gens_str = [f'{s}p_{i}' for i in plus for s in 'bca'] + gens_str += [f'{s}m_{i}' for i in minus for s in 'bca'] + alg_ZZ = FreeAlgebra(ZZ, m3, gens_str) + gen_indices = {k: i for i, k in enumerate(plus + minus)} + gens = [alg_ZZ.gens()[k:k + 3] for k in range(0, m3, 3)] + + M = identity_matrix(alg_ZZ, n) for k, i in enumerate(tz): - A = identity_matrix(alg, n) - gen_index = gen_indices.index(k) - b, c, a = alg.gens()[3*gen_index:3*gen_index+3] + A = identity_matrix(alg_ZZ, n) + b, c, a = gens[gen_indices[k]] + # faster using row operations instead ? if i > 0: A[i-1, i-1] = a A[i, i] = 0 @@ -2122,7 +2123,9 @@ def deformed_burau_matrix(self, variab='q'): A[-1-i, -i] = c A[-i, -1-i] = b M = M * A - return M + + alg_R = FreeAlgebra(R, m3, gens_str) + return M.change_ring(alg_R) def _colored_jones_sum(self, N, qword): r""" @@ -2147,23 +2150,19 @@ def _colored_jones_sum(self, N, qword): """ rqword = RightQuantumWord(qword).reduced_word() alg = qword.parent() - R = alg.base_ring() - result = R.one() + result = alg.base_ring().one() current_word = alg.one() - i = 1 - continue_summing = True # This seemingly infinite sum is always finite if the qword comes # from a sum of quantum determinants; because at some point # the break condition will become true. - while continue_summing: + while True: current_word *= rqword - new_rqw = RightQuantumWord(alg(current_word)) + new_rqw = RightQuantumWord(current_word) current_word = new_rqw.reduced_word() new_eps = new_rqw.eps(N) - result += new_eps if not new_eps: - continue_summing = False - i += 1 + break + result += new_eps return result def colored_jones_polynomial(self, N, variab=None, try_inverse=True): @@ -2213,7 +2212,7 @@ def colored_jones_polynomial(self, N, variab=None, try_inverse=True): if variab is None: return cj if isinstance(variab, str): - variab = LaurentPolynomialRing(IntegerRing(), variab).gen() + variab = LaurentPolynomialRing(ZZ, variab).gen() return cj.subs(q=variab) db = self.deformed_burau_matrix('q')[1:, 1:] @@ -2239,6 +2238,90 @@ def colored_jones_polynomial(self, N, variab=None, try_inverse=True): self._cj_with_q[N] = cj.subs({q: 1/q}) if use_inverse else cj return self.colored_jones_polynomial(N, variab, try_inverse) + def super_summit_set_element(self): + r""" + Return an element of the braid's super summit set and the conjugating + braid. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, 1, 2, 3, -1, 2, 1, 3]) + sage: b.super_summit_set_element() + (s0*s2*s0*s1*s2*s1*s0, s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s0^-1*s1*s0*s2*s1*s0) + """ + to_sss = send_to_sss(self) + B = self.parent() + return tuple([B._element_from_libbraiding(b) for b in to_sss]) + + def ultra_summit_set_element(self): + r""" + Return an element of the braid's ultra summit set and the conjugating + braid. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, 1, 2, 3, -1, 2, -1, 3]) + sage: b.ultra_summit_set_element() + (s0*s1*s0*s2*s1, s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s0^-1*s1*s2*s1^2*s0) + """ + to_uss = send_to_uss(self) + B = self.parent() + return tuple([B._element_from_libbraiding(b) for b in to_uss]) + + def sliding_circuits_element(self): + r""" + Return an element of the braid's sliding circuits, and the conjugating + braid. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, 1, 2, 3, -1, 2, -1, 3]) + sage: b.sliding_circuits_element() + (s0*s1*s0*s2*s1, s0^2*s1*s2) + """ + to_sc = send_to_sc(self) + B = self.parent() + return tuple([B._element_from_libbraiding(b) for b in to_sc]) + + def trajectory(self): + r""" + Return the braid's trajectory. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, 1, 2, 3, -1, 2, -1, 3]) + sage: b.trajectory() + [s0^-1*s1^-1*s0^-1*s2^-1*s1^-1*s2*s0*s1*s2*s1*s0^2*s1*s2^2, + s0*s1*s2^3, + s0*s1*s2*s1^2, + s0*s1*s0*s2*s1] + """ + traj = trajectory(self) + B = self.parent() + return [B._element_from_libbraiding(b) for b in traj] + + def cyclic_slidings(self): + r""" + Return the braid's cyclic slidings. + + OUTPUT: The braid's cyclic slidings. Each cyclic sliding is a list of braids. + + EXAMPLES:: + + sage: B = BraidGroup(4) + sage: b = B([1, 2, 1, 2, 3, -1, 2, 1]) + sage: b.cyclic_slidings() + [[s0*s2*s1*s0*s1*s2, s0*s1*s2*s1*s0^2, s1*s0*s2^2*s1*s0], + [s0*s1*s2*s1^2*s0, s0*s1*s2*s1*s0*s2, s1*s0*s2*s0*s1*s2]] + """ + cs = cyclic_slidings(self) + B = self.parent() + return [[B._element_from_libbraiding(b) for b in t] for t in cs] + class RightQuantumWord: """ @@ -2286,12 +2369,15 @@ def __init__(self, words): """ self._algebra = words.parent() self.q = self._algebra.base_ring().gen() + self.iq = ~self.q self.R = self._algebra.base_ring() self._unreduced_words = words self._gens = self._algebra._indices.gens() - self._gens_index = {g: i for i, g in enumerate(self._gens)} self._minus_begin = min((i for i, gen in enumerate(self._gens) if 'm' in str(gen)), - default=len(self._gens)) + default=len(self._gens)) // 3 + split = ((g, str(g), i) for i, g in enumerate(self._gens)) + self._recognize = {g: (s[0], s[1] == 'm', 3 * (i // 3)) + for g, s, i in split} @lazy_attribute def tuples(self): @@ -2327,24 +2413,25 @@ def tuples(self): """ from collections import defaultdict ret = defaultdict(self.R) + convert = self._recognize + q = self.q + iq = self.iq for unreduced_monom, q_power in list(self._unreduced_words): - q = self.q ret_tuple = [0] * len(self._gens) for gen, exp in unreduced_monom: - gen_index = self._gens_index[gen] - is_minus = bool(gen_index >= self._minus_begin) - index = gen_index // 3 + letter, is_minus, index = convert[gen] # This uses the relations in equations (4.1) and (4.2) # of [HL2018]_. - i, j, k = ret_tuple[3*index: 3*index + 3] - if not (gen_index + 1) % 3: # is_a - ret_tuple[3*index: 3*index + 3] = [i, j, k + exp] - if not gen_index % 3: # is_b - ret_tuple[3*index: 3*index + 3] = [i + exp, j, k] - q_power *= q**(2*(k*exp + j*exp)) if is_minus else q**(-2*j*exp) - if not (gen_index + 2) % 3: # is_c - ret_tuple[3*index: 3*index + 3] = [i, j + exp, k] - q_power *= q**(-k*exp) if is_minus else q**(k*exp) + if letter == 'a': # is_a + ret_tuple[index + 2] += exp + elif letter == 'b': # is_b + j, k = ret_tuple[index + 1:index + 3] + ret_tuple[index] += exp + q_power *= q**(2*(k*exp + j*exp)) if is_minus else iq**(2*j*exp) + else: # is_c + k = ret_tuple[index + 2] + ret_tuple[index + 1] += exp + q_power *= iq**(k*exp) if is_minus else q**(k*exp) ret[tuple(ret_tuple)] += q_power return ret @@ -2414,7 +2501,7 @@ def eps(self, N): sage: from sage.groups.braid import RightQuantumWord sage: B = BraidGroup(3) sage: b = B([1,-2,1,2]) - sage: db = b.deformed_burau_matrix()[:, :] + sage: db = b.deformed_burau_matrix() sage: q = db.parent().base_ring().base_ring().gen() sage: (bp_0, cp_0, ap_0, ....: bp_2, cp_2, ap_2, @@ -2443,16 +2530,16 @@ def eps_monom(q_tuple): """ q = self.q ret_q = q**sum((N - 1 - q_tuple[3*i + 2])*q_tuple[3*i + 1] - for i in range(self._minus_begin//3)) + for i in range(self._minus_begin)) ret_q *= q**sum((N - 1)*(-q_tuple[rj]) - for rj in range(self._minus_begin + 1, + for rj in range(self._minus_begin * 3 + 1, len(q_tuple), 3)) ret_q *= prod(prod(1 - q**(N - 1 - q_tuple[3*i + 1] - h) for h in range(q_tuple[3*i + 2])) - for i in range(self._minus_begin//3)) + for i in range(self._minus_begin)) ret_q *= prod(prod(1 - q**(q_tuple[3*j + 1] + k + 1 - N) for k in range(q_tuple[3*j + 2])) - for j in range(self._minus_begin//3, + for j in range(self._minus_begin, len(q_tuple)//3)) return ret_q @@ -2756,17 +2843,15 @@ def _links_gould_representation(self, symbolics=False): d = 4 # dimension of the natural module from sage.matrix.special import diagonal_matrix if symbolics: - from sage.symbolic.ring import SR as BR - from sage.calculus.var import var from sage.misc.functional import sqrt - t0, t1 = var('t0, t1') + from sage.symbolic.ring import SR as BR + t0, t1 = BR.var('t0, t1') s0 = sqrt(t0) s1 = sqrt(t1) Y = sqrt(-(t0 - 1)*(t1 - 1)) sparse = False else: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - from sage.rings.integer_ring import ZZ LR = LaurentPolynomialRing(ZZ, 's0r, s1r') PR = PolynomialRing(LR, 'Yr') s0r, s1r, Yr = PR.gens_dict_recursive().values() @@ -2865,7 +2950,7 @@ def _LKB_matrix_(self, braid, variab): A = A*self._LKB_matrix_((i,), variab) return A n2 = [set(X) for X in combinations(range(n), 2)] - R = LaurentPolynomialRing(IntegerRing(), variab) + R = LaurentPolynomialRing(ZZ, variab) q = R.gens()[0] t = R.gens()[1] if not braid: @@ -3215,7 +3300,7 @@ def TL_representation(self, drain_size, variab=None): if variab is None: if drain_size in self._TL_representation_dict: return self._TL_representation_dict[drain_size] - R = LaurentPolynomialRing(IntegerRing(), 'A') + R = LaurentPolynomialRing(ZZ, 'A') A = R.gens()[0] else: R = variab.parent() diff --git a/src/sage/groups/cubic_braid.py b/src/sage/groups/cubic_braid.py index e407b9d1326..3ca62e9f5e9 100644 --- a/src/sage/groups/cubic_braid.py +++ b/src/sage/groups/cubic_braid.py @@ -371,7 +371,7 @@ def burau_matrix(self, root_bur=None, domain=None, characteristic=None, - ``root_bur`` -- six (resp. twelfth) root of unity in some field (default: root of unity over `\QQ`) - ``domain`` -- (default: cyclotomic field of order 3 and degree 2, resp. - the domain of `root_bur` if given) base ring for the Burau matrix + the domain of ``root_bur`` if given) base ring for the Burau matrix - ``characteristic`` -- integer giving the characteristic of the domain (default: 0 or the characteristic of ``domain`` if given) - ``var`` -- string used for the indeterminate name in case ``root_bur`` @@ -640,7 +640,6 @@ class CubicBraidGroup(UniqueRepresentation, FinitelyPresentedGroup): sage: C3.gens() (t0, t1) sage: U3.is_isomorphic(C3) - #I Forcing finiteness test True sage: U3.as_classical_group() Subgroup generated by [(1,7,6)(3,19,14)(4,15,10)(5,11,18)(12,16,20), @@ -802,7 +801,6 @@ def __init__(self, names, cbg_type=None): self._classical_embedding = None # if self._classical_group different from self._classical_base_group self._centralizing_matrix = None # for Assion groups: element in classical base group commuting with self self._centralizing_element = None # image under nat. map of the former one in the proj. classical group - return def _repr_(self): r""" @@ -914,7 +912,6 @@ def _internal_test_attached_group(self, attached_group, tester): if self.is_finite() and self.strands() <= 7: # not realistic for larger number of strands att_grp_elem_back = self(att_grp_elem) tester.assertEqual(att_grp_elem_back, elem) - return def _test_classical_group(self, **options): r""" @@ -935,7 +932,6 @@ def _test_classical_group(self, **options): classic_grp = self.as_classical_group() if self.is_finite(): self._internal_test_attached_group(classic_grp, tester) - return def _test_permutation_group(self, **options): r""" @@ -956,7 +952,6 @@ def _test_permutation_group(self, **options): tester = self._tester(**options) permgrp = self.as_permutation_group() self._internal_test_attached_group(permgrp, tester) - return def _test_matrix_group(self, **options): r""" @@ -1025,7 +1020,6 @@ def _test_reflection_group(self, **options): tester = self._tester(**options) reflgrp = self.as_reflection_group() self._internal_test_attached_group(reflgrp, tester) - return # ------------------------------------------------------------------------------- # ------------------------------------------------------------------------------- @@ -1136,7 +1130,6 @@ def set_classical_realization(self, base_group, proj_group, centralizing_matrix, self._centralizing_matrix = centralizing_matrix self._centralizing_element = centralizing_element self._classical_embedding = embedding - return # ------------------------------------------------------------------------------- # local methods to set up the classical group (specific part) @@ -1211,7 +1204,6 @@ def transvec2mat(v, bas=bas, bform=bform, fact=1): transvec_matrices = [transvec2mat(v) for v in transvections] set_classical_realization(self, base_group, proj_group, centralizing_matrix, transvec_matrices) - return # ------------------------------------------------------------------------------- # Case for unitary groups @@ -1296,7 +1288,6 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): transvec_matrices = [transvec2mat(v) for v in transvections] set_classical_realization(self, base_group, proj_group, centralizing_matrix, transvec_matrices) - return # ---------------------------------------------------------------- # local functions declaration section finishes here @@ -1347,7 +1338,6 @@ def transvec2mat(v, bas=bas, bform=bform, fact=a): self._classical_embedding = classical_group if self._classical_invariant_form is None: self._classical_invariant_form = classical_group.ambient().invariant_form() - return def _element_constructor_(self, x, **kwds): r""" @@ -1604,7 +1594,6 @@ def as_permutation_group(self, use_classical=True): sage: C3 = CubicBraidGroup(3) sage: PC3 = C3.as_permutation_group() sage: assert C3.is_isomorphic(PC3) # random (with respect to the occurrence of the info message) - #I Forcing finiteness test sage: PC3.degree() 8 sage: c = C3([2,1-2]) diff --git a/src/sage/groups/finitely_presented.py b/src/sage/groups/finitely_presented.py index 9b5f7e422d6..b65566ebeb4 100644 --- a/src/sage/groups/finitely_presented.py +++ b/src/sage/groups/finitely_presented.py @@ -1080,7 +1080,6 @@ def direct_product(self, H, reduced=False, new_names=True): sage: C7 = G / [G.0**7]; C6 = G / [G.0**6] sage: C14 = G / [G.0**14]; C3 = G / [G.0**3] sage: C7.direct_product(C6).is_isomorphic(C14.direct_product(C3)) - #I Forcing finiteness test True sage: F = FreeGroup(2); D = F / [F([1,1,1,1,1]),F([2,2]),F([1,2])**2] sage: D.direct_product(D).as_permutation_group().is_isomorphic( @@ -1174,7 +1173,6 @@ def semidirect_product(self, H, hom, check=True, reduced=False): sage: alpha = (Q.gens(), [a,b]) sage: S2 = C2.semidirect_product(Q, ([C2.0],[alpha])) sage: S1.is_isomorphic(S2) - #I Forcing finiteness test True Dihedral groups can be constructed as semidirect products @@ -1233,8 +1231,6 @@ def semidirect_product(self, H, hom, check=True, reduced=False): sage: Se2 = D.semidirect_product(C ,id2) sage: Dp1 = C.direct_product(D) sage: Dp1.is_isomorphic(Se1), Dp1.is_isomorphic(Se2) - #I Forcing finiteness test - #I Forcing finiteness test (True, True) Most checks for validity of input are left to GAP to handle:: diff --git a/src/sage/groups/finitely_presented_named.py b/src/sage/groups/finitely_presented_named.py index 940d761ef49..20d847be0dd 100644 --- a/src/sage/groups/finitely_presented_named.py +++ b/src/sage/groups/finitely_presented_named.py @@ -451,7 +451,6 @@ def QuaternionPresentation(): sage: Q.order(), Q.is_abelian() (8, False) sage: Q.is_isomorphic(groups.presentation.DiCyclic(2)) - #I Forcing finiteness test True """ F = FreeGroup(['a','b']) @@ -554,12 +553,6 @@ def BinaryDihedralPresentation(n): ....: P = groups.presentation.BinaryDihedral(n) ....: M = groups.matrix.BinaryDihedral(n) ....: assert P.is_isomorphic(M) - #I Forcing finiteness test - #I Forcing finiteness test - #I Forcing finiteness test - #I Forcing finiteness test - #I Forcing finiteness test - #I Forcing finiteness test """ F = FreeGroup('x,y,z') x,y,z = F.gens() diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index 69acc7c654d..5b207f423c6 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -1502,12 +1502,18 @@ def has_order(P, n, operation='+'): sage: has_order(x, -8) False + Check for :issue:`38708`:: + + sage: has_order(Mod(2,3), int(2), operation='*') + True + .. NOTE:: In some cases, order *testing* can be much faster than *computing* the order using :func:`order_from_multiple`. """ - if isinstance(n, sage.rings.integer.Integer): + if not isinstance(n, sage.structure.factorization.Factorization): + n = integer_ring.ZZ(n) if n <= 0: return False n = n.factor() diff --git a/src/sage/groups/group.pxd b/src/sage/groups/group.pxd index 8a38ba4b583..462099d77fd 100644 --- a/src/sage/groups/group.pxd +++ b/src/sage/groups/group.pxd @@ -11,4 +11,3 @@ cdef class FiniteGroup(Group): cdef class AlgebraicGroup(Group): pass - diff --git a/src/sage/groups/libgap_mixin.py b/src/sage/groups/libgap_mixin.py index 3491c9f9db0..b14b050bd3b 100644 --- a/src/sage/groups/libgap_mixin.py +++ b/src/sage/groups/libgap_mixin.py @@ -946,4 +946,16 @@ def is_isomorphic(self, H): sage: F == G, G == H, F == H (False, False, False) """ - return self.gap().IsomorphismGroups(H.gap()) != libgap.fail + # If GAP doesn't know that the groups are finite, it will + # check. This emits an informational warning, and then + # annotates the groups as being finite (assuming they were) so + # that future isomorphism checks are silent. This can lead to + # apparent non-determinism in the output as statements are + # rearranged. There's nothing the user can do about this + # anyway, and it happens in trivial cases like the alternating + # group on one element, so we prefer to hide the warning. + old_warnlevel = libgap.InfoLevel(libgap.InfoWarning) + libgap.SetInfoLevel(libgap.InfoWarning, 0) + result = self.gap().IsomorphismGroups(H.gap()) != libgap.fail + libgap.SetInfoLevel(libgap.InfoWarning, old_warnlevel) + return result diff --git a/src/sage/groups/matrix_gps/meson.build b/src/sage/groups/matrix_gps/meson.build index 30b8e2379c0..77c70adf7fa 100644 --- a/src/sage/groups/matrix_gps/meson.build +++ b/src/sage/groups/matrix_gps/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'binary_dihedral.py', 'catalog.py', diff --git a/src/sage/groups/meson.build b/src/sage/groups/meson.build index a1876172c4d..37ba1028d5e 100644 --- a/src/sage/groups/meson.build +++ b/src/sage/groups/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'artin.py', 'braid.py', @@ -37,13 +38,17 @@ extension_data = { } foreach name, pyx : extension_data + deps = [py_dep, gmp] + if name == 'libgap_wrapper' + deps += [gap] + endif py.extension_module( name, sources: pyx, subdir: 'sage/groups', install: true, include_directories: [inc_cpython], - dependencies: [py_dep, gmp, gap], + dependencies: deps, ) endforeach diff --git a/src/sage/groups/misc_gps/argument_groups.py b/src/sage/groups/misc_gps/argument_groups.py index 43c2ef98770..475f260c518 100644 --- a/src/sage/groups/misc_gps/argument_groups.py +++ b/src/sage/groups/misc_gps/argument_groups.py @@ -1006,7 +1006,7 @@ def __init__(self, category): Rational Field """ from sage.rings.rational_field import QQ - return super().__init__(base=QQ, category=category) + super().__init__(base=QQ, category=category) def _repr_(self): r""" @@ -1461,9 +1461,22 @@ def __pow__(self, exponent): 1 sage: S(-1)^3 # indirect doctest -1 + + Check that the results may live in other parents too:: + + sage: x = SR.var('x') + sage: elem = S(-1)^x; elem # indirect doctest + (-1)^x + sage: elem.parent() + Symbolic Ring + """ + result = self._element_ ** exponent P = self.parent() - return P.element_class(P, self._element_ ** exponent) + try: + return P.element_class(P, result) + except (ValueError, TypeError): + return result def __invert__(self): r""" @@ -1613,7 +1626,7 @@ def __init__(self, category): sage: S.base() # indirect doctest """ - return super().__init__(base=int, category=category) + super().__init__(base=int, category=category) def _repr_(self): r""" diff --git a/src/sage/groups/old.pxd b/src/sage/groups/old.pxd index 3409c5b1764..b141cd6d1a3 100644 --- a/src/sage/groups/old.pxd +++ b/src/sage/groups/old.pxd @@ -11,4 +11,3 @@ cdef class FiniteGroup(Group): cdef class AlgebraicGroup(Group): pass - diff --git a/src/sage/groups/perm_gps/meson.build b/src/sage/groups/perm_gps/meson.build index e986fcd964a..6ad30d99fe2 100644 --- a/src/sage/groups/perm_gps/meson.build +++ b/src/sage/groups/perm_gps/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'constructor.py', 'cubegroup.py', 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 f8d9aaf2c1b..6aa7b262712 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 @@ -529,12 +529,12 @@ cdef aut_gp_and_can_lab *get_aut_gp_and_can_lab(void *S, orbits_of_permutation = work_space.orbits_of_permutation current_indicators = work_space.int_array - first_indicators = work_space.int_array + n - permutation = work_space.int_array + 2*n - id_perm = work_space.int_array + 3*n - cells_to_refine_by = work_space.int_array + 4*n - vertices_determining_current_stack = work_space.int_array + 5*n - label_perm = work_space.int_array + 6*n + first_indicators = work_space.int_array + n + permutation = work_space.int_array + 2 * n + id_perm = work_space.int_array + 3 * n + cells_to_refine_by = work_space.int_array + 4 * n + vertices_determining_current_stack = work_space.int_array + 5 * n + label_perm = work_space.int_array + 6 * n fixed_points_of_generators = work_space.bitset_array minimal_cell_reps_of_generators = work_space.bitset_array + len_of_fp_and_mcr diff --git a/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd b/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd index 8996dcaf509..fde91d1d0f6 100644 --- a/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd +++ b/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pxd @@ -82,4 +82,3 @@ cdef iterator *setup_canonical_generator(int degree, iterator *cangen_prealloc) except NULL cdef iterator *start_canonical_generator(StabilizerChain *, void *, int, iterator *) except NULL - diff --git a/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx b/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx index 2775842c09d..6eeeb69ccbb 100644 --- a/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx +++ b/src/sage/groups/perm_gps/partn_ref/canonical_augmentation.pyx @@ -289,15 +289,15 @@ cdef canonical_generator_data *allocate_cgd(int max_depth, int degree) noexcept: if cgd is NULL: sig_free(cgd) return NULL - cgd.object_stack = sig_malloc(max_depth * sizeof(void *)) - cgd.degree_stack = sig_malloc(max_depth * sizeof(int)) - cgd.iterator_stack = sig_malloc(max_depth * sizeof(iterator)) - cgd.aut_gp_stack = sig_malloc(max_depth * sizeof(aut_gp_and_can_lab *)) - cgd.agcl_work_spaces = sig_malloc(max_depth * sizeof(agcl_work_space *)) - cgd.dc_work_spaces = sig_malloc(max_depth * sizeof(dc_work_space *)) - cgd.ps_stack = sig_malloc(max_depth * sizeof(PartitionStack *)) - cgd.aug_stack = sig_malloc(max_depth * sizeof(void *)) - cgd.parent_stack = sig_malloc(max_depth * sizeof(void *)) + cgd.object_stack = sig_malloc(max_depth * sizeof(void *)) + cgd.degree_stack = sig_malloc(max_depth * sizeof(int)) + cgd.iterator_stack = sig_malloc(max_depth * sizeof(iterator)) + cgd.aut_gp_stack = sig_malloc(max_depth * sizeof(aut_gp_and_can_lab *)) + cgd.agcl_work_spaces = sig_malloc(max_depth * sizeof(agcl_work_space *)) + cgd.dc_work_spaces = sig_malloc(max_depth * sizeof(dc_work_space *)) + cgd.ps_stack = sig_malloc(max_depth * sizeof(PartitionStack *)) + cgd.aug_stack = sig_malloc(max_depth * sizeof(void *)) + cgd.parent_stack = sig_malloc(max_depth * sizeof(void *)) part = PS_new(degree, 1) cdef agcl_work_space *agclws = allocate_agcl_work_space(degree) cdef aut_gp_and_can_lab *output = allocate_agcl_output(degree) diff --git a/src/sage/groups/perm_gps/partn_ref/data_structures.pxd b/src/sage/groups/perm_gps/partn_ref/data_structures.pxd index 1cbb95231d5..af6da5d606f 100644 --- a/src/sage/groups/perm_gps/partn_ref/data_structures.pxd +++ b/src/sage/groups/perm_gps/partn_ref/data_structures.pxd @@ -81,7 +81,10 @@ cdef inline int OP_copy_from_to(OrbitPartition *OP, OrbitPartition *OP2) noexcep - OP2.degree == OP.degree - OP2.num_cells == OP.num_cells """ - memcpy(OP2.parent, OP.parent, 4*OP.degree * sizeof(int) ) + memcpy(OP2.parent, OP.parent, OP.degree * sizeof(int)) + memcpy(OP2.rank, OP.rank, OP.degree * sizeof(int)) + memcpy(OP2.mcr, OP.mcr, OP.degree * sizeof(int)) + memcpy(OP2.size, OP.size, OP.degree * sizeof(int)) cdef inline OrbitPartition *OP_copy(OrbitPartition *OP) noexcept: """ @@ -138,38 +141,7 @@ cdef inline void OP_join(OrbitPartition *OP, int m, int n) noexcept: if m_root != n_root: OP.num_cells -= 1 - -cdef inline void OP_make_set(OrbitPartition *OP) noexcept: - cdef int i, n = OP.degree - cdef int *new_parent, *new_rank, *new_mcr, *new_size - - cdef int *int_array = sig_malloc(4*(n+1) * sizeof(int)) - if int_array is NULL: - raise MemoryError("MemoryError allocating int_array in make_set method") - - OP.degree = n + 1 - OP.num_cells = OP.num_cells + 1 - new_parent = int_array - new_rank = int_array + (n + 1) - new_mcr = int_array + (2*n + 2) - new_size = int_array + (3 * n + 3) - - memcpy(new_parent, OP.parent, n * sizeof(int)) - memcpy(new_rank, OP.rank, n * sizeof(int)) - memcpy(new_mcr, OP.mcr, n * sizeof(int)) - memcpy(new_size, OP.size, n * sizeof(int)) - - new_parent[n] = n - new_rank[n] = 0 - new_mcr[n] = n - new_size[n] = 1 - - sig_free(OP.parent) - - OP.parent = new_parent - OP.rank = new_rank - OP.mcr = new_mcr - OP.size = new_size +cdef void OP_make_set(OrbitPartition *OP) noexcept cdef inline int OP_merge_list_perm(OrbitPartition *OP, int *gamma) noexcept: """ diff --git a/src/sage/groups/perm_gps/partn_ref/data_structures.pyx b/src/sage/groups/perm_gps/partn_ref/data_structures.pyx index a3ef7193d3d..cd9bcee07d3 100644 --- a/src/sage/groups/perm_gps/partn_ref/data_structures.pyx +++ b/src/sage/groups/perm_gps/partn_ref/data_structures.pyx @@ -46,25 +46,34 @@ cdef inline OrbitPartition *OP_new(int n) noexcept: """ cdef OrbitPartition *OP = \ sig_malloc(sizeof(OrbitPartition)) - cdef int *int_array = sig_malloc( 4*n * sizeof(int) ) - if OP is NULL or int_array is NULL: + if OP is NULL: + return NULL + OP.parent = sig_malloc(n * sizeof(int)) + OP.rank = sig_malloc(n * sizeof(int)) + OP.mcr = sig_malloc(n * sizeof(int)) + OP.size = sig_malloc(n * sizeof(int)) + if OP.parent is NULL or OP.rank is NULL or OP.mcr is NULL or OP.size is NULL: + sig_free(OP.parent) + sig_free(OP.rank) + sig_free(OP.mcr) + sig_free(OP.size) sig_free(OP) - sig_free(int_array) return NULL OP.degree = n OP.num_cells = n - OP.parent = int_array - OP.rank = int_array + n - OP.mcr = int_array + 2*n - OP.size = int_array + 3*n OP_clear(OP) return OP + cdef inline void OP_dealloc(OrbitPartition *OP) noexcept: if OP is not NULL: sig_free(OP.parent) + sig_free(OP.rank) + sig_free(OP.mcr) + sig_free(OP.size) sig_free(OP) + cdef OP_string(OrbitPartition *OP): """ Return a string representation of the OrbitPartition. @@ -78,6 +87,33 @@ cdef OP_string(OrbitPartition *OP): return s +cdef inline void OP_make_set(OrbitPartition *OP) noexcept: + """ + Increase the degree of the input partition by one. + + An error is raised in case of memory allocation failure. + """ + cdef int n = OP.degree + + OP.parent = sig_realloc(OP.parent, (n + 1) * sizeof(int)) + OP.rank = sig_realloc(OP.rank, (n + 1) * sizeof(int)) + OP.mcr = sig_realloc(OP.mcr, (n + 1) * sizeof(int)) + OP.size = sig_realloc(OP.size, (n + 1) * sizeof(int)) + if OP.parent is NULL or OP.rank is NULL or OP.mcr is NULL or OP.size is NULL: + sig_free(OP.parent) + sig_free(OP.rank) + sig_free(OP.mcr) + sig_free(OP.size) + raise MemoryError("unable to reallocate memory in OP_make_set method") + OP.degree = n + 1 + OP.num_cells = OP.num_cells + 1 + + OP.parent[n] = n + OP.rank[n] = 0 + OP.mcr[n] = n + OP.size[n] = 1 + + def OP_represent(int n, merges, perm): """ Demonstration and testing. @@ -198,6 +234,7 @@ cdef inline PartitionStack *PS_new(int n, bint unit_partition) noexcept: PS_unit_partition(PS) return PS + cdef void PS_unit_partition(PartitionStack *PS) noexcept: """ Set partition stack to a single partition with a single cell. @@ -210,6 +247,7 @@ cdef void PS_unit_partition(PartitionStack *PS) noexcept: PS.entries[n-1] = n - 1 PS.levels[n-1] = -1 + cdef inline PartitionStack *PS_copy(PartitionStack *PS) noexcept: """ Allocate and return a pointer to a copy of PartitionStack PS. Return a null @@ -229,11 +267,13 @@ cdef inline PartitionStack *PS_copy(PartitionStack *PS) noexcept: PS_copy_from_to(PS, PS2) return PS2 + cdef inline void PS_dealloc(PartitionStack *PS) noexcept: if PS is not NULL: sig_free(PS.entries) sig_free(PS) + cdef PartitionStack *PS_from_list(list L) noexcept: """ Allocate and return a pointer to a PartitionStack representing L. Return a @@ -259,6 +299,7 @@ cdef PartitionStack *PS_from_list(list L) noexcept: PS.degree = n return PS + cdef PS_print(PartitionStack *PS): """ Print a visual representation of PS. @@ -267,6 +308,7 @@ cdef PS_print(PartitionStack *PS): for i in range(PS.depth + 1): PS_print_partition(PS, i) + cdef PS_print_partition(PartitionStack *PS, int k): """ Print the partition at depth k. @@ -281,6 +323,7 @@ cdef PS_print_partition(PartitionStack *PS, int k): s = s[:-1] + ')' print(s) + cdef int PS_first_smallest(PartitionStack *PS, bitset_t b, int *second_pos=NULL) noexcept: """ Find the first occurrence of the smallest cell of size greater than one, @@ -345,7 +388,7 @@ cdef int PS_all_new_cells(PartitionStack *PS, bitset_t** nonsingletons_ptr) noex bitset_init(nonsingletons[count-1], n) bitset_copy(nonsingletons[count-1], scratch) else: - if beg==0: + if beg == 0: nonsingletons = sig_realloc(nonsingletons, sizeof(bitset_t)) if nonsingletons is NULL: raise MemoryError("Memory error in PS_all_new_cells") @@ -357,6 +400,7 @@ cdef int PS_all_new_cells(PartitionStack *PS, bitset_t** nonsingletons_ptr) noex nonsingletons_ptr[0] = nonsingletons return count + cdef int PS_find_element(PartitionStack *PS, bitset_t b, int x) except -1: """ Find the cell containing x, store its entries to b and return the location @@ -380,6 +424,7 @@ cdef int PS_find_element(PartitionStack *PS, bitset_t b, int x) except -1: i += 1 return location + cdef list PS_singletons(PartitionStack * part): """ Return the list of all singletons in the ``PartitionStack``. @@ -549,6 +594,7 @@ cdef enum: default_num_gens = 8 default_num_bits = 64 + cdef StabilizerChain *SC_new(int n, bint init_gens=True) noexcept: """ Allocate and return a pointer to a new StabilizerChain of degree n. Return @@ -566,7 +612,7 @@ cdef StabilizerChain *SC_new(int n, bint init_gens=True) noexcept: return SC # first level allocations - cdef int *int_array = sig_malloc( (3*n*n + 6*n + 1) * sizeof(int) ) + cdef int *int_array = sig_malloc( (3*n*n + 6*n + 1) * sizeof(int) ) cdef int **int_ptrs = sig_calloc( 5*n, sizeof(int *) ) SC.OP_scratch = OP_new(n) # bitset_init without the MemoryError: @@ -591,21 +637,21 @@ cdef StabilizerChain *SC_new(int n, bint init_gens=True) noexcept: SC.gen_is_id.bits[limbs-1] = 0 SC.orbit_sizes = int_array - SC.num_gens = int_array + n - SC.array_size = int_array + 2*n - SC.perm_scratch = int_array + 3*n # perm_scratch is length 3*n+1 for sorting + SC.num_gens = int_array + n + SC.array_size = int_array + 2 * n + SC.perm_scratch = int_array + 3 * n # perm_scratch is length 3*n+1 for sorting int_array += 6*n + 1 SC.generators = int_ptrs - SC.gen_inverses = int_ptrs + n - SC.base_orbits = int_ptrs + 2*n - SC.parents = int_ptrs + 3*n - SC.labels = int_ptrs + 4*n + SC.gen_inverses = int_ptrs + n + SC.base_orbits = int_ptrs + 2 * n + SC.parents = int_ptrs + 3 * n + SC.labels = int_ptrs + 4 * n for i in range(n): SC.base_orbits[i] = int_array - SC.parents[i] = int_array + n - SC.labels[i] = int_array + 2*n - int_array += 3*n + SC.parents[i] = int_array + n + SC.labels[i] = int_array + 2 * n + int_array += 3 * n # second level allocations if init_gens: @@ -619,6 +665,7 @@ cdef StabilizerChain *SC_new(int n, bint init_gens=True) noexcept: return SC + cdef inline int SC_realloc_gens(StabilizerChain *SC, int level, int size) noexcept: """ Reallocate generator array at level `level` to size `size`. @@ -641,21 +688,23 @@ cdef inline int SC_realloc_gens(StabilizerChain *SC, int level, int size) noexce SC.array_size[level] = size return 0 + cdef inline void SC_dealloc(StabilizerChain *SC) noexcept: cdef int i, n if SC is not NULL: - n = SC.degree + n = SC.degree if SC.generators is not NULL: for i in range(n): sig_free(SC.generators[i]) sig_free(SC.gen_inverses[i]) - sig_free(SC.generators) # frees int_ptrs - sig_free(SC.orbit_sizes) # frees int_array + sig_free(SC.generators) # frees int_ptrs + sig_free(SC.orbit_sizes) # frees int_array sig_free(SC.gen_used.bits) sig_free(SC.gen_is_id.bits) OP_dealloc(SC.OP_scratch) sig_free(SC) + cdef StabilizerChain *SC_symmetric_group(int n) noexcept: """ Return a stabilizer chain for the symmetric group on {0, 1, ..., n-1}. @@ -690,13 +739,14 @@ cdef StabilizerChain *SC_symmetric_group(int n) noexcept: SC.parents[i][i+j] = b SC.labels[i][i+j] = j for j in range(n - i - 1): - #j-th generator sends i+j+1 to b + # j-th generator sends i+j+1 to b memcpy(SC.generators[i] + n*j, id_perm, n * sizeof(int) ) SC.generators[i][n*j + i+j+1] = b SC.generators[i][n*j + b] = i+j+1 memcpy(SC.gen_inverses[i] + n*j, SC.generators[i] + n*j, n * sizeof(int) ) return SC + cdef StabilizerChain *SC_alternating_group(int n) noexcept: """ Return a stabilizer chain for the alternating group on {0, 1, ..., n-1}. @@ -733,7 +783,7 @@ cdef StabilizerChain *SC_alternating_group(int n) noexcept: SC.labels[i][i+j] = j SC.labels[i][n-1] = -(n-i-2) for j in range(n - i - 2): - #j-th generator sends i+j+1 to b, i+j+2 to i+j+1, and b to i+j+2 + # j-th generator sends i+j+1 to b, i+j+2 to i+j+1, and b to i+j+2 memcpy(SC.generators[i] + n*j, id_perm, n * sizeof(int) ) SC.generators[i][n*j + i+j+1] = b SC.generators[i][n*j + b ] = i+j+2 @@ -741,6 +791,7 @@ cdef StabilizerChain *SC_alternating_group(int n) noexcept: SC_invert_perm(SC.gen_inverses[i] + n*j, SC.generators[i] + n*j, n) return SC + cdef int SC_realloc_bitsets(StabilizerChain *SC, unsigned long size) noexcept: """ If size is larger than current allocation, double the size of the bitsets @@ -770,11 +821,14 @@ cdef int SC_realloc_bitsets(StabilizerChain *SC, unsigned long size) noexcept: SC.gen_used.size = new_size SC.gen_is_id.size = new_size SC.gen_used.bits[size_old >> index_shift] &= limb_lower_bits_down(size_old) - memset(SC.gen_used.bits + (size_old >> index_shift) + 1, 0, (limbs - (size_old >> index_shift) - 1) * sizeof(unsigned long)) + memset(SC.gen_used.bits + (size_old >> index_shift) + 1, 0, + (limbs - (size_old >> index_shift) - 1) * sizeof(unsigned long)) SC.gen_is_id.bits[size_old >> index_shift] &= limb_lower_bits_down(size_old) - memset(SC.gen_is_id.bits + (size_old >> index_shift) + 1, 0, (limbs - (size_old >> index_shift) - 1) * sizeof(unsigned long)) + memset(SC.gen_is_id.bits + (size_old >> index_shift) + 1, 0, + (limbs - (size_old >> index_shift) - 1) * sizeof(unsigned long)) return 0 + cdef StabilizerChain *SC_copy(StabilizerChain *SC, int level) noexcept: """ Create a copy of the first `level` levels of SC. Must have 0 < level. @@ -800,15 +854,16 @@ cdef StabilizerChain *SC_copy(StabilizerChain *SC, int level) noexcept: SC_dealloc(SCC) return NULL SCC.array_size[i] = default_num_gens - SC_copy_nomalloc(SCC, SC, level) # no chance for memory error here... + SC_copy_nomalloc(SCC, SC, level) # no chance for memory error here... return SCC + cdef int SC_copy_nomalloc(StabilizerChain *SC_dest, StabilizerChain *SC, int level) noexcept: cdef int i, n = SC.degree level = min(level, SC.base_size) SC_dest.base_size = level - memcpy(SC_dest.orbit_sizes, SC.orbit_sizes, 2*n * sizeof(int) ) # copies orbit_sizes, num_gens - memcpy(SC_dest.base_orbits[0], SC.base_orbits[0], 3*n*n * sizeof(int) ) # copies base_orbits, parents, labels + memcpy(SC_dest.orbit_sizes, SC.orbit_sizes, 2*n * sizeof(int) ) # copies orbit_sizes, num_gens + memcpy(SC_dest.base_orbits[0], SC.base_orbits[0], 3*n*n * sizeof(int) ) # copies base_orbits, parents, labels for i in range(level): if SC.num_gens[i] > SC_dest.array_size[i]: if SC_realloc_gens(SC_dest, i, max(SC.num_gens[i], 2*SC_dest.array_size[i])): @@ -817,6 +872,7 @@ cdef int SC_copy_nomalloc(StabilizerChain *SC_dest, StabilizerChain *SC, int lev memcpy(SC_dest.gen_inverses[i], SC.gen_inverses[i], SC.num_gens[i]*n * sizeof(int) ) return 0 + cdef SC_print_level(StabilizerChain *SC, int level): cdef int i, j, n = SC.degree if level < SC.base_size: @@ -856,6 +912,7 @@ cdef StabilizerChain *SC_new_base(StabilizerChain *SC, int *base, int base_len) return NULL return NEW + cdef int SC_new_base_nomalloc(StabilizerChain *SC_dest, StabilizerChain *SC, int *base, int base_len) noexcept: cdef int i SC_dest.base_size = 0 @@ -866,6 +923,7 @@ cdef int SC_new_base_nomalloc(StabilizerChain *SC_dest, StabilizerChain *SC, int return 1 return 0 + cdef int SC_update(StabilizerChain *dest, StabilizerChain *source, int level) noexcept: cdef mpz_t src_order, dst_order cdef int *perm = dest.perm_scratch @@ -900,6 +958,7 @@ cdef int SC_update(StabilizerChain *dest, StabilizerChain *source, int level) no mpz_clear(dst_order) return 0 + cdef StabilizerChain *SC_insert_base_point(StabilizerChain *SC, int level, int p) noexcept: """ Insert the point ``p`` as a base point on level ``level``. Return a new @@ -927,6 +986,7 @@ cdef StabilizerChain *SC_insert_base_point(StabilizerChain *SC, int level, int p return NULL return NEW + cdef int SC_insert_base_point_nomalloc(StabilizerChain *SC_dest, StabilizerChain *SC, int level, int p) noexcept: cdef int i, b SC_copy_nomalloc(SC_dest, SC, level) @@ -939,6 +999,7 @@ cdef int SC_insert_base_point_nomalloc(StabilizerChain *SC_dest, StabilizerChain return 1 return 0 + cdef int SC_re_tree(StabilizerChain *SC, int level, int *perm, int x) noexcept: """ Return values: @@ -980,6 +1041,7 @@ cdef int SC_re_tree(StabilizerChain *SC, int level, int *perm, int x) noexcept: i += 1 return 0 + cdef int SC_sift(StabilizerChain *SC, int level, int x, int *gens, int num_gens, int *new_gens) noexcept: """ Apply Schreier's subgroup lemma[1] as follows. Given a level, a point x, and @@ -1001,8 +1063,8 @@ cdef int SC_sift(StabilizerChain *SC, int level, int x, int *gens, int num_gens, # copy a representative taking base to the point x to each of these cdef int i - cdef int *temp = SC.gen_inverses[level] + n*SC.num_gens[level] # one more scratch space - # (available since num_gens > 0) + cdef int *temp = SC.gen_inverses[level] + n*SC.num_gens[level] # one more scratch space + # (available since num_gens > 0) cdef int *rep_inv = temp SC_identify(rep_inv, n) SC_compose_up_to_base(SC, level, x, rep_inv) @@ -1026,6 +1088,7 @@ cdef int SC_sift(StabilizerChain *SC, int level, int x, int *gens, int num_gens, SC_mult_perms(perm, perm, perm_rep_inv, n) return SC_insert(SC, level+1, new_gens, num_gens) + cdef int SC_insert_and_sift(StabilizerChain *SC, int level, int *pi, int num_perms, bint sift) noexcept: cdef int i, j, b, n = SC.degree cdef int perm_gen_index @@ -1075,7 +1138,7 @@ cdef int SC_insert_and_sift(StabilizerChain *SC, int level, int *pi, int num_per bitset_set(&SC.gen_used, perm_gen_index) if SC_re_tree(SC, level, perm, x): return 1 - start_over = 1 # we must look anew + start_over = 1 # we must look anew break if start_over: break @@ -1087,7 +1150,7 @@ cdef int SC_insert_and_sift(StabilizerChain *SC, int level, int *pi, int num_per # now we have an x which maps to a new point under perm, if SC_re_tree(SC, level, perm, x): return 1 - start_over = 1 # we must look anew + start_over = 1 # we must look anew break if start_over: break @@ -1098,7 +1161,7 @@ cdef int SC_insert_and_sift(StabilizerChain *SC, int level, int *pi, int num_per # now we have an x which maps to a new point under perm, if SC_re_tree(SC, level, perm, x): return 1 - start_over = 1 # we must look anew + start_over = 1 # we must look anew break if not sift: return 0 @@ -1133,6 +1196,7 @@ cdef int SC_insert_and_sift(StabilizerChain *SC, int level, int *pi, int num_per section += 1 return 0 + cdef bint SC_is_giant(int n, int num_perms, int *perms, float p, bitset_t support) noexcept: """ Test whether the group generated by the input permutations is a giant, i.e., @@ -1384,8 +1448,8 @@ def SC_test_list_perms(list L, int n, int limit, bint gap, bint limit_complain, sig_free(perm) SC_dealloc(SC) raise MemoryError - cdef int *perm2 = perm + n - cdef int *perm3 = perm + 2*n + cdef int *perm2 = perm + n + cdef int *perm3 = perm + 2 * n for Lperm in L: for i from 0 <= i < n: perm[i] = Lperm[i] @@ -1658,6 +1722,7 @@ cdef int sort_by_function(PartitionStack *PS, int start, int *degrees) noexcept: j += 1 return max_location + cdef int refine_by_orbits(PartitionStack *PS, StabilizerChain *SC, int *perm_stack, int *cells_to_refine_by, int *ctrb_len) noexcept: """ Given a stabilizer chain SC, refine the partition stack PS so that each cell @@ -1698,6 +1763,7 @@ cdef int refine_by_orbits(PartitionStack *PS, StabilizerChain *SC, int *perm_sta start += i return invariant + cdef int compute_relabeling(StabilizerChain *group, StabilizerChain *scratch_group, int *permutation, int *relabeling) noexcept: """ 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 d4cedec1f3c..0ee7cf4b486 100644 --- a/src/sage/groups/perm_gps/partn_ref/double_coset.pyx +++ b/src/sage/groups/perm_gps/partn_ref/double_coset.pyx @@ -379,10 +379,10 @@ cdef int double_coset(void *S1, void *S2, PartitionStack *partition1, int *order orbits_of_subgroup = work_space.orbits_of_subgroup indicators = work_space.int_array - permutation = work_space.int_array + n - id_perm = work_space.int_array + 2*n - cells_to_refine_by = work_space.int_array + 3*n - vertices_determining_current_stack = work_space.int_array + 4*n + permutation = work_space.int_array + n + id_perm = work_space.int_array + 2 * n + cells_to_refine_by = work_space.int_array + 3 * n + vertices_determining_current_stack = work_space.int_array + 4 * n fixed_points_of_generators = work_space.bitset_array minimal_cell_reps_of_generators = work_space.bitset_array + len_of_fp_and_mcr diff --git a/src/sage/groups/perm_gps/partn_ref/meson.build b/src/sage/groups/perm_gps/partn_ref/meson.build index 092b0d0b2c8..933d72d2729 100644 --- a/src/sage/groups/perm_gps/partn_ref/meson.build +++ b/src/sage/groups/perm_gps/partn_ref/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'automorphism_group_canonical_label.pxd', 'canonical_augmentation.pxd', diff --git a/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pxd b/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pxd index 2cf087e9915..6ef14648081 100644 --- a/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pxd +++ b/src/sage/groups/perm_gps/partn_ref/refinement_matrices.pxd @@ -28,4 +28,3 @@ cdef class MatrixStruct: cdef int refine_matrix(PartitionStack *, void *, int *, int) noexcept cdef int compare_matrices(int *, int *, void *, void *, int) noexcept cdef bint all_matrix_children_are_equivalent(PartitionStack *, void *) noexcept - diff --git a/src/sage/groups/perm_gps/partn_ref2/meson.build b/src/sage/groups/perm_gps/partn_ref2/meson.build index ef97195574e..69b9bee042d 100644 --- a/src/sage/groups/perm_gps/partn_ref2/meson.build +++ b/src/sage/groups/perm_gps/partn_ref2/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'refinement_generic.pxd', subdir: 'sage/groups/perm_gps/partn_ref2', diff --git a/src/sage/groups/semimonomial_transformations/meson.build b/src/sage/groups/semimonomial_transformations/meson.build index 402cb5244e5..f7958976271 100644 --- a/src/sage/groups/semimonomial_transformations/meson.build +++ b/src/sage/groups/semimonomial_transformations/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'semimonomial_transformation.pxd', 'semimonomial_transformation_group.py', diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index 60f2ccc77f2..977968fdcb3 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -1253,7 +1253,7 @@ def _acted_upon_(self, a, self_on_left): ret = CombinatorialFreeModule.Element._acted_upon_(self, a, self_on_left) if ret is not None: # did the scalar action return ret - if self_on_left: # i.e., module element on left + if self_on_left: # i.e., module element on left a = a.antipode() b = a.change_basis('adem') ans = self.parent().zero() @@ -1283,7 +1283,7 @@ def steenrod_module_map(self, deg_domain, deg_codomain, side='left'): the action as a left module action or a right module We will write this with respect to the left action; - for the right action, just switch all of the the tensors. + for the right action, just switch all of the tensors. Writing `m` for ``deg_domain`` and `n` for ``deg_codomain``, this returns `A^{n-m} \otimes H^{m} \to H^{n}`, one single component of the map making `H` into an `A`-module. @@ -1434,6 +1434,7 @@ def sum_indices(k, i_k_plus_one, S_k_plus_one): return [[i_k] + l for i_k in range(S_k, i_k_plus_one) for l in sum_indices(k-1, i_k, S_k)] + def is_GF2(R): r""" Return ``True`` iff ``R`` is isomorphic to the field `\GF{2}`. diff --git a/src/sage/interacts/library.py b/src/sage/interacts/library.py index 7aa5ac779d9..a58a0748477 100644 --- a/src/sage/interacts/library.py +++ b/src/sage/interacts/library.py @@ -2,7 +2,7 @@ Sage Interacts Sage interacts are applications of the `@interact decorator <../../sagenb/notebook/interact.html>`_. -They are conveniently accessible in the Sage Notebook via ``interacts.[TAB].[TAB]()``. +They are conveniently accessible in the Sage notebook via ``interacts.[TAB].[TAB]()``. The first ``[TAB]`` lists categories and the second ``[TAB]`` reveals the interact examples. EXAMPLES: @@ -496,6 +496,7 @@ def quadratic_equation(A, B, C): r"\frac{-%s\pm\sqrt{%s}}{%s} = %s$" html(calc % (B, dis1, A, B, dis2, (2*A), sol)) + @library_interact( a0=lambda: slider(0, 360, 1, 30, label='A'), a1=lambda: slider(0, 360, 1, 180, label='B'), diff --git a/src/sage/interacts/meson.build b/src/sage/interacts/meson.build index 4889c06f9fa..b0542f38853 100644 --- a/src/sage/interacts/meson.build +++ b/src/sage/interacts/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'algebra.py', 'all.py', 'calculus.py', diff --git a/src/sage/interfaces/ecm.py b/src/sage/interfaces/ecm.py index 7d1ac74b7c1..74d51dbb51e 100644 --- a/src/sage/interfaces/ecm.py +++ b/src/sage/interfaces/ecm.py @@ -57,6 +57,7 @@ from sage.env import SAGE_ECMBIN + class ECM(SageObject): def __init__(self, B1=10, B2=None, **kwds): diff --git a/src/sage/interfaces/interface.py b/src/sage/interfaces/interface.py index 6f2fb118968..bd1095e8c70 100644 --- a/src/sage/interfaces/interface.py +++ b/src/sage/interfaces/interface.py @@ -880,7 +880,7 @@ def _reduce(self): Special care has to be taken with strings. Since for example `r("abc")` will be interpreted as the R-command abc (not a string in R), we have to reduce to - `"'abc'"` instead. That is dependant on the Elements `is_string` function to + `"'abc'"` instead. That is dependant on the Elements ``is_string`` function to be implemented correctly. This has gone wrong in the past and remained uncaught by the doctests because the original identifier was reused. This test makes sure that does not happen again:: diff --git a/src/sage/interfaces/mathematica.py b/src/sage/interfaces/mathematica.py index 39c3aff9dc2..488a1fb1af5 100644 --- a/src/sage/interfaces/mathematica.py +++ b/src/sage/interfaces/mathematica.py @@ -454,7 +454,7 @@ def clean_output(s): def _un_camel(name): """ - Convert `CamelCase` to `camel_case`. + Convert ``CamelCase`` to ``camel_case``. EXAMPLES:: diff --git a/src/sage/interfaces/mathics.py b/src/sage/interfaces/mathics.py index a6d39ad3c14..3ca4bee83ef 100644 --- a/src/sage/interfaces/mathics.py +++ b/src/sage/interfaces/mathics.py @@ -397,12 +397,12 @@ def _mathics_sympysage_symbol(self): r""" - Convert a Sympy symbol ``self`` to a correspondig element + Convert a Sympy symbol ``self`` to a corresponding element in Sage's symbolic ring. This function replaces ``_sympysage_symbol`` to take care of the special names used in Mathics. - It is set to the method `_sage_` of the Sympy class + It is set to the method ``_sage_`` of the Sympy class :class:`sympy.core.symbol.Sympol`. EXAMPLES:: diff --git a/src/sage/interfaces/maxima_lib.py b/src/sage/interfaces/maxima_lib.py index 1b1e97f3578..a8ba86ae3d0 100644 --- a/src/sage/interfaces/maxima_lib.py +++ b/src/sage/interfaces/maxima_lib.py @@ -35,7 +35,7 @@ classical Maxima Pexpect interface in case no new implementation has been made. This interface is the one used for calculus by Sage -and is accessible as `maxima_calculus`:: +and is accessible as ``maxima_calculus``:: sage: maxima_calculus Maxima_lib @@ -80,8 +80,8 @@ TESTS: Check our workaround for a race in ecl works, see :issue:`26968`. -We use a temporary `MAXIMA_USERDIR` so it's empty; we place it -in `DOT_SAGE` since we expect it to have more latency than `/tmp`. +We use a temporary ``MAXIMA_USERDIR`` so it's empty; we place it +in ``DOT_SAGE`` since we expect it to have more latency than ``/tmp``. sage: import tempfile, subprocess sage: tmpdir = tempfile.TemporaryDirectory(dir=DOT_SAGE) diff --git a/src/sage/interfaces/meson.build b/src/sage/interfaces/meson.build index 4a12245d532..aee6b8493d0 100644 --- a/src/sage/interfaces/meson.build +++ b/src/sage/interfaces/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'abc.py', 'all.py', 'all__sagemath_polyhedra.py', diff --git a/src/sage/interfaces/octave.py b/src/sage/interfaces/octave.py index 5241989836b..da26ea800b5 100644 --- a/src/sage/interfaces/octave.py +++ b/src/sage/interfaces/octave.py @@ -351,7 +351,6 @@ def quit(self, verbose=False): if self._expect is not None: if verbose: print("Exiting spawned %s process." % self) - return def _start(self): """ diff --git a/src/sage/interfaces/phc.py b/src/sage/interfaces/phc.py index 3aa5964352b..d687d456eaf 100644 --- a/src/sage/interfaces/phc.py +++ b/src/sage/interfaces/phc.py @@ -567,7 +567,7 @@ def _parse_path_file(self, input_filename, verbose=False): t_val = CC(m.group(2), m.group(3)) temp_dict = {} temp_dict["t"] = t_val - for i in range(0, count): + for i in range(count): a_line = fh.readline() m = sols_regex.match(a_line) if m: diff --git a/src/sage/interfaces/r.py b/src/sage/interfaces/r.py index b44fe1381ff..6bf0ddc6ab7 100644 --- a/src/sage/interfaces/r.py +++ b/src/sage/interfaces/r.py @@ -894,7 +894,7 @@ def available_packages(self): # The following was more structural, but breaks on my machine. (stein) # p = p._sage_() # s = p['_Dim'][0] - # l = [[p['DATA'][i],p['DATA'][s+1+i]] for i in range(0,s)] + # l = [[p['DATA'][i],p['DATA'][s+1+i]] for i in range(s)] # return l def _object_class(self): diff --git a/src/sage/interfaces/singular.py b/src/sage/interfaces/singular.py index d02ae43149f..d110c17bf16 100644 --- a/src/sage/interfaces/singular.py +++ b/src/sage/interfaces/singular.py @@ -1401,7 +1401,7 @@ def _repr_(self): # this is our cue that singular uses `rp` instead of `ip` if singular_name_mapping['invlex'] == 'rp' and 'doctest' in str(get_display_manager()): s = re.sub('^(// .*block.* : ordering )rp$', '\\1ip', - s, 0, re.MULTILINE) + s, flags=re.MULTILINE) return s def __copy__(self): @@ -1785,7 +1785,7 @@ def sage_poly(self, R=None, kcache=None): # TODO: Refactor imports to move this to the top from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict from sage.rings.polynomial.multi_polynomial_libsingular import MPolynomialRing_libsingular - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.polydict import ETuple from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular from sage.rings.quotient_ring import QuotientRing_generic @@ -1876,7 +1876,7 @@ def sage_poly(self, R=None, kcache=None): return R(sage_repr) - elif isinstance(R, PolynomialRing_general) and (ring_is_fine or can_convert_to_singular(R)): + elif isinstance(R, PolynomialRing_generic) and (ring_is_fine or can_convert_to_singular(R)): sage_repr = [0] * int(self.deg() + 1) diff --git a/src/sage/knots/knot.py b/src/sage/knots/knot.py index aaa01cdade9..d8c688b3c32 100644 --- a/src/sage/knots/knot.py +++ b/src/sage/knots/knot.py @@ -30,6 +30,8 @@ from sage.categories.monoids import Monoids # We need Link to be first in the MRO in order to use its equality, hash, etc. + + class Knot(Link, Element, metaclass=InheritComparisonClasscallMetaclass): r""" A knot. @@ -290,7 +292,7 @@ def dt_code(self): crossing = i break if not string_found: - for i in range(0, crossing): + for i in range(crossing): if abs(b[i]) == string or abs(b[i]) == string - 1: string_found = True crossing = i diff --git a/src/sage/knots/knotinfo.py b/src/sage/knots/knotinfo.py index 8c246ba8097..c57777bb2c2 100644 --- a/src/sage/knots/knotinfo.py +++ b/src/sage/knots/knotinfo.py @@ -17,7 +17,7 @@ This will install a `Python wrapper `__ for the original databases in Sage. This wrapper perfoms an automatic progress of version numbers. For more details and further install instructions please see -the correspondig web-page. +the corresponding web-page. To perform all the doctests concerning the usage of the database on the installation add the option ``-c``. In this case (for instance ``sage -f -c database_knotinfo``) @@ -218,7 +218,7 @@ - Sebastian Oehms August 2020: initial version - Sebastian Oehms June 2022: add :meth:`conway_polynomial` and :meth:`khovanov_polynomial` (:issue:`33969`) -Thanks to Chuck Livingston and Allison Moore for their support. For further acknowledgments see the correspondig hompages. +Thanks to Chuck Livingston and Allison Moore for their support. For further acknowledgments see the corresponding hompages. """ @@ -229,7 +229,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/ ############################################################################## diff --git a/src/sage/lfunctions/dokchitser.py b/src/sage/lfunctions/dokchitser.py index b6524bce984..9e4154a6c07 100644 --- a/src/sage/lfunctions/dokchitser.py +++ b/src/sage/lfunctions/dokchitser.py @@ -287,7 +287,6 @@ def _instantiate_gp(cls): cls.__globals_re = re.compile( '([^a-zA-Z0-9_]|^)(%s)([^a-zA-Z0-9_]|$)' % '|'.join(cls.__globals)) - return @classmethod def _teardown_gp(cls, instance=None): diff --git a/src/sage/lfunctions/meson.build b/src/sage/lfunctions/meson.build index cf0ffe05e17..24e2f156f5e 100644 --- a/src/sage/lfunctions/meson.build +++ b/src/sage/lfunctions/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'dokchitser.py', 'lcalc.py', diff --git a/src/sage/libs/braiding.pyx b/src/sage/libs/braiding.pyx index fb856c918c9..6bfdea11dc4 100644 --- a/src/sage/libs/braiding.pyx +++ b/src/sage/libs/braiding.pyx @@ -41,6 +41,11 @@ cdef extern from "braiding.h" namespace "Braiding": int thurstontype(int n, list[int] word) int Rigidity_ext(int n, list[int] word) list[list[list[list[int]]]] SlidingCircuits(int n, list[int] word) + list[list[list[int]]] SendToSSS(int n, list[int] word) + list[list[list[int]]] SendToUSS(int n, list[int] word) + list[list[list[int]]] SendToSC(int n, list[int] word) + list[list[list[int]]] Trajectory(int n, list[int] word) + list[list[list[list[int]]]] CyclicSlidings(int n, list[int] word) def conjugatingbraid(braid1, braid2): @@ -383,3 +388,161 @@ def sliding_circuits(braid): cdef list[list[list[list[int]]]] rop = SlidingCircuits(nstrands, l) sig_off() return rop + + +def send_to_sss(braid): + r""" + Return an element of the braid's super summit set and the conjugating braid. + + INPUT: + + - ``braid`` -- a braid + + OUTPUT: + + A list with two braids, the first one is an element of ``braid`` super summit + set, the second one is the corresponding conjugating braid. + + EXAMPLES:: + + sage: from sage.libs.braiding import send_to_sss + sage: B = BraidGroup(4) + sage: d = B([1, 2, 1, 2, 3, -1, 2,- 3]) + sage: send_to_sss(d) + [[[0], [1, 2, 1, 3]], [[-1], [1, 2, 3, 2]]] + + """ + nstrands = braid.parent().strands() + l = braid.Tietze() + sig_on() + cdef list[list[list[int]]] rop = SendToSSS(nstrands, l) + sig_off() + return rop + + +def send_to_uss(braid): + r""" + Return an element of the braid's ultra summit set and the conjugating braid. + + INPUT: + + - ``braid`` -- a braid + + OUTPUT: + + A list with two braids, the first one is an element of ``braid`` ultra summit + set, the second one is the corresponding conjugating braid. + + EXAMPLES:: + + sage: from sage.libs.braiding import send_to_uss + sage: B = BraidGroup(4) + sage: d = B([1, 2, 1, 2, 3, -1, 2,- 1]) + sage: send_to_uss(d) + [[[0], [1, 2, 3, 2]], [[0], [1]]] + + """ + nstrands = braid.parent().strands() + l = braid.Tietze() + sig_on() + cdef list[list[list[int]]] rop = SendToUSS(nstrands, l) + sig_off() + return rop + + +def send_to_sc(braid): + r""" + Return an element of the braid's sliding circuits and the conjugating braid. + + INPUT: + + - ``braid`` -- a braid + + OUTPUT: + + A list with two braids, the first one is an element of ``braid`` sliding + circuits, the second one is the corresponding conjugating braid. + + EXAMPLES:: + + sage: from sage.libs.braiding import send_to_sc + sage: B = BraidGroup(4) + sage: d = B([1, 2, 1, 2, 3, -1, 2, 2]) + sage: send_to_sc(d) + [[[0], [1, 2, 3, 2], [2, 1]], [[0], [1]]] + + + """ + nstrands = braid.parent().strands() + l = braid.Tietze() + sig_on() + cdef list[list[list[int]]] rop = SendToSC(nstrands, l) + sig_off() + return rop + + +def trajectory(braid): + r""" + Return the braid's trajectory. + + INPUT: + + - ``braid`` -- a braid + + OUTPUT: + + A list of braids, formed by the ``braid```trajectory. + + EXAMPLES:: + + sage: from sage.libs.braiding import trajectory + sage: B = BraidGroup(4) + sage: d = B([1, 2, 1, 2, 3, -1, 2, 2]) + sage: trajectory(d) + [[[0], [1, 3], [1, 2, 3, 2]], + [[0], [1, 2, 3, 2, 1], [3]], + [[0], [1, 2, 3, 2], [2, 1]], + [[0], [2, 1, 3], [1, 2, 3]]] + + + """ + nstrands = braid.parent().strands() + l = braid.Tietze() + sig_on() + cdef list[list[list[int]]] rop = Trajectory(nstrands, l) + sig_off() + return rop + + +def cyclic_slidings(braid): + r""" + Return the cyclic slidings of the braid. + + INPUT: + + - ``braid`` -- a braid + + OUTPUT: + + A list of lists of braids, given by the input's cyclic slidings. + + EXAMPLES:: + + sage: from sage.libs.braiding import cyclic_slidings + sage: B = BraidGroup(4) + sage: d = B([1, 2, 1, 2, 3, -1, 2, 2]) + sage: cyclic_slidings(d) + [[[[0], [1, 2, 3, 2], [2, 1]], + [[0], [1, 2, 3, 2, 1], [3]], + [[0], [2, 1, 3], [1, 2, 3]]], + [[[0], [1, 3, 2, 1], [2, 3]], + [[0], [1, 2, 3, 2, 1], [1]], + [[0], [2, 1, 3], [3, 2, 1]]]] + + """ + nstrands = braid.parent().strands() + l = braid.Tietze() + sig_on() + cdef list[list[list[list[int]]]] rop = CyclicSlidings(nstrands, l) + sig_off() + return rop diff --git a/src/sage/libs/coxeter3/coxeter_group.py b/src/sage/libs/coxeter3/coxeter_group.py index 845feb2fd38..858a0f24d6e 100644 --- a/src/sage/libs/coxeter3/coxeter_group.py +++ b/src/sage/libs/coxeter3/coxeter_group.py @@ -279,7 +279,7 @@ def m(self, i, j): """ from sage.misc.superseded import deprecation deprecation(30237, "the .m(i, j) method has been deprecated; use .coxeter_matrix()[i,j] instead.") - return self.coxeter_matrix()[i,j] + return self.coxeter_matrix()[i, j] def kazhdan_lusztig_polynomial(self, u, v, constant_term_one=True): r""" @@ -354,8 +354,9 @@ def kazhdan_lusztig_polynomial(self, u, v, constant_term_one=True): return p ZZq = PolynomialRing(ZZ, 'q', sparse=True) # This is the same as q**len_diff * p(q**(-2)) - len_diff = v.length()-u.length() - d = {-2*deg+len_diff: coeff for deg,coeff in enumerate(p) if coeff != 0} + len_diff = v.length() - u.length() + d = {-2 * deg + len_diff: coeff for deg, coeff in enumerate(p) + if coeff != 0} return ZZq(d) def parabolic_kazhdan_lusztig_polynomial(self, u, v, J, constant_term_one=True): @@ -414,11 +415,11 @@ def parabolic_kazhdan_lusztig_polynomial(self, u, v, J, constant_term_one=True): WOI = self.weak_order_ideal(lambda x: J_set.issuperset(x.descents())) if constant_term_one: P = PolynomialRing(ZZ, 'q') - return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u*z,v) - for z in WOI if (u*z).bruhat_le(v)) + return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u * z, v) + for z in WOI if (u * z).bruhat_le(v)) P = PolynomialRing(ZZ, 'q', sparse=True) - return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u*z,v, constant_term_one=False).shift(z.length()) - for z in WOI if (u*z).bruhat_le(v)) + return P.sum((-1)**(z.length()) * self.kazhdan_lusztig_polynomial(u * z, v, constant_term_one=False).shift(z.length()) + for z in WOI if (u * z).bruhat_le(v)) class Element(ElementWrapper): wrapped_class = CoxGroupElement @@ -701,7 +702,7 @@ def action_on_rational_function(self, f): for exponent in exponents: # Construct something in the root lattice from the exponent vector - exponent = sum(e*b for e, b in zip(exponent, basis_elements)) + exponent = sum(e * b for e, b in zip(exponent, basis_elements)) exponent = self.action(exponent) monomial = 1 diff --git a/src/sage/libs/eclib/constructor.py b/src/sage/libs/eclib/constructor.py index 79d28b90c1c..37df4eb935b 100644 --- a/src/sage/libs/eclib/constructor.py +++ b/src/sage/libs/eclib/constructor.py @@ -1,5 +1,6 @@ "Cremona modular symbols" + def CremonaModularSymbols(level, sign=0, cuspidal=False, verbose=0): """ Return the space of Cremona modular symbols with given level, sign, etc. diff --git a/src/sage/libs/eclib/interface.py b/src/sage/libs/eclib/interface.py index a5e65a37d4d..1cdaebc93e4 100644 --- a/src/sage/libs/eclib/interface.py +++ b/src/sage/libs/eclib/interface.py @@ -31,6 +31,7 @@ from .mwrank import _Curvedata, _two_descent, _mw, parse_point_list + class mwrank_EllipticCurve(SageObject): r""" The :class:`mwrank_EllipticCurve` class represents an elliptic @@ -246,8 +247,11 @@ def __repr__(self): """ a1, a2, a3, a4, a6 = self.__ainvs # we do not assume a1, a2, a3 are reduced to {0,1}, {-1,0,1}, {0,1} - coeff = lambda a: ''.join([" +" if a > 0 else " -", - " " + str(abs(a)) if abs(a) > 1 else ""]) + + def coeff(a): + return ''.join([" +" if a > 0 else " -", + " " + str(abs(a)) if abs(a) > 1 else ""]) + return ''.join(['y^2', ' '.join([coeff(a1), 'xy']) if a1 else '', ' '.join([coeff(a3), 'y']) if a3 else '', @@ -267,21 +271,28 @@ def two_descent(self, verbose=True, selmer_only=False, first_limit=20, - ``selmer_only`` -- boolean (default: ``False``); ``selmer_only`` switch - - ``first_limit`` -- integer (default: 20); bound on `|x|+|z|` in - quartic point search - - - ``second_limit`` -- integer (default: 8); bound on - `\log \max(|x|,|z|)`, i.e. logarithmic - - - ``n_aux`` -- integer (default: -1); (only relevant for general - 2-descent when 2-torsion trivial) number of primes used for - quartic search. ``n_aux=-1`` causes default (8) to be used. - Increase for curves of higher rank. - - - ``second_descent`` -- boolean (default: ``True``); (only relevant - for curves with 2-torsion, where mwrank uses descent via - 2-isogeny) flag determining whether or not to do second - descent. *Default strongly recommended.* + - ``first_limit`` -- integer (default: 20); naive height bound on + first point search on quartic homogeneous spaces (before + testing local solubility; very simple search with no + overheads). + + - ``second_limit`` -- integer (default: 8); logarithmic height bound on + second point search on quartic homogeneous spaces (after + testing local solubility; sieve-assisted search) + + - ``n_aux`` -- integer (default: -1); if positive, the number of + auxiliary primes used in sieve-assisted search for quartics. + If -1 (the default) use a default value (set in the eclib + code in ``src/qrank/mrank1.cc`` in DEFAULT_NAUX: currently 8). + Only relevant for curves with no 2-torsion, where full + 2-descent is carried out. Worth increasing for curves + expected to be of rank > 6 to one or two more than the + expected rank. + + - ``second_descent`` -- boolean (default: ``True``); flag specifying + whether or not a second descent will be carried out. Only relevant + for curves with 2-torsion. Recommended left as the default except for + experts interested in details of Selmer groups. OUTPUT: nothing @@ -606,12 +617,14 @@ def certain(self): """ return bool(self.__two_descent_data().getcertain()) - #def fullmw(self): - # return self.__two_descent_data().getfullmw() + # def fullmw(self): + # return self.__two_descent_data().getfullmw() def CPS_height_bound(self): r""" - Return the Cremona-Prickett-Siksek height bound. This is a + Return the Cremona-Prickett-Siksek height bound. + + This is a floating point number `B` such that if `P` is a point on the curve, then the naive logarithmic height `h(P)` is less than `B+\hat{h}(P)`, where `\hat{h}(P)` is the canonical height of @@ -1282,9 +1295,9 @@ def search(self, height_limit=18, verbose=False): """ height_limit = float(height_limit) int_bits = sys.maxsize.bit_length() - max_height_limit = int_bits * 0.693147 # log(2.0) = 0.693147 approx + max_height_limit = int_bits * 0.693147 # log(2.0) = 0.693147 approx if height_limit >= max_height_limit: - raise ValueError("The height limit must be < {} = {}log(2) on a {}-bit machine.".format(max_height_limit, int_bits, int_bits+1)) + raise ValueError("The height limit must be < {} = {}log(2) on a {}-bit machine.".format(max_height_limit, int_bits, int_bits + 1)) moduli_option = 0 # Use Stoll's sieving program... see strategies in ratpoints-1.4.c diff --git a/src/sage/libs/eclib/mwrank.pyx b/src/sage/libs/eclib/mwrank.pyx index 5bc54a04cdc..4a2ca04e55f 100644 --- a/src/sage/libs/eclib/mwrank.pyx +++ b/src/sage/libs/eclib/mwrank.pyx @@ -992,29 +992,11 @@ cdef class _two_descent: points. Useful as a faster way of getting an upper bound on the rank. - - ``firstlim`` -- integer (default: 20); naive height bound on - first point search on quartic homogeneous spaces (before - testing local solubility; very simple search with no - overheads). - - - ``secondlim`` -- integer (default: 8); naive height bound on - second point search on quartic homogeneous spaces (after - testing local solubility; sieve-assisted search) - - - ``n_aux`` -- integer (default: -1); if positive, the number of - auxiliary primes used in sieve-assisted search for quartics. - If -1 (the default) use a default value (set in the eclib - code in ``src/qrank/mrank1.cc`` in DEFAULT_NAUX: currently 8). - Only relevant for curves with no 2-torsion, where full - 2-descent is carried out. Worth increasing for curves - expected to be of rank > 6 to one or two more than the - expected rank. - - - ``second_descent`` -- integer (default: 1); flag specifying - whether or not a second descent will be carried out (yes if - 1, the default; no if 0). Only relevant for curves with - 2-torsion. Recommended left as the default except for - experts interested in details of Selmer groups. + - ``firstlim``, ``secondlim``, ``n_aux``, ``second_descent`` -- + see ``first_limit``, ``second_limit``, ``n_aux``, ``second_descent`` + respectively in :meth:`~sage.libs.eclib.interface.mwrank_EllipticCurve.two_descent` + (although ``second_descent`` here is ``1`` or ``0`` instead of ``True`` or ``False`` + respectively) OUTPUT: none diff --git a/src/sage/libs/flint/flint_wrap.h b/src/sage/libs/flint/flint_wrap.h index 1302973779e..2cd39eb1441 100644 --- a/src/sage/libs/flint/flint_wrap.h +++ b/src/sage/libs/flint/flint_wrap.h @@ -26,6 +26,10 @@ #pragma push_macro("ulong") #undef ulong +/* Reserved in C99, needed for FLINT without https://github.com/flintlib/flint/pull/2027 */ +#pragma push_macro("I") +#define I Iv + #include /* If flint was already previously included via another header (e.g. @@ -169,6 +173,7 @@ #undef mp_bitcnt_t #pragma pop_macro("ulong") +#pragma pop_macro("I") /* CPU_SIZE_1 and SIZE_RED_FAILURE_THRESH are defined as macros in flint/fmpz_lll.h * and as variables in fplll/defs.h, which breaks build if linbox is compiled with fplll */ diff --git a/src/sage/libs/flint/fq_nmod_mpoly.pxd b/src/sage/libs/flint/fq_nmod_mpoly.pxd index 3e5bb56569b..8daa198212f 100644 --- a/src/sage/libs/flint/fq_nmod_mpoly.pxd +++ b/src/sage/libs/flint/fq_nmod_mpoly.pxd @@ -93,7 +93,7 @@ cdef extern from "flint_wrap.h": void fq_nmod_mpoly_scalar_mul_fq_nmod(fq_nmod_mpoly_t A, const fq_nmod_mpoly_t B, const fq_nmod_t c, const fq_nmod_mpoly_ctx_t ctx) noexcept void fq_nmod_mpoly_make_monic(fq_nmod_mpoly_t A, const fq_nmod_mpoly_t B, const fq_nmod_mpoly_ctx_t ctx) noexcept void fq_nmod_mpoly_derivative(fq_nmod_mpoly_t A, const fq_nmod_mpoly_t B, slong var, const fq_nmod_mpoly_ctx_t ctx) noexcept - void fq_nmod_mpoly_evaluate_all_fq_nmod(fq_nmod_t ev, const fq_nmod_mpoly_t A, fq_nmod_struct * const * vals, const fq_nmod_mpoly_ctx_t ctx) noexcept + void fq_nmod_mpoly_evaluate_all_fq_nmod(fq_nmod_t ev, const fq_nmod_mpoly_t A, fq_nmod_struct * const * vals, const fq_nmod_mpoly_ctx_t ctx) noexcept void fq_nmod_mpoly_evaluate_one_fq_nmod(fq_nmod_mpoly_t A, const fq_nmod_mpoly_t B, slong var, const fq_nmod_t val, const fq_nmod_mpoly_ctx_t ctx) noexcept int fq_nmod_mpoly_compose_fq_nmod_poly(fq_nmod_poly_t A, const fq_nmod_mpoly_t B, fq_nmod_poly_struct * const * C, const fq_nmod_mpoly_ctx_t ctx) noexcept int fq_nmod_mpoly_compose_fq_nmod_mpoly(fq_nmod_mpoly_t A, const fq_nmod_mpoly_t B, fq_nmod_mpoly_struct * const * C, const fq_nmod_mpoly_ctx_t ctxB, const fq_nmod_mpoly_ctx_t ctxAC) noexcept diff --git a/src/sage/libs/gap/gap_globals.py b/src/sage/libs/gap/gap_globals.py index 4c3e6eb3aae..f8061a173a2 100644 --- a/src/sage/libs/gap/gap_globals.py +++ b/src/sage/libs/gap/gap_globals.py @@ -15,34 +15,34 @@ # selected gap globals to use in tab completion -common_gap_globals = set([ - 'Assert', - 'Cyclotomics', - 'GaussianIntegers', - 'GaussianRationals', - 'GlobalMersenneTwister', - 'GlobalRandomSource', - 'InfoAlgebra', - 'InfoAttributes', - 'InfoBckt', - 'InfoCharacterTable', - 'InfoCoh', - 'InfoComplement', - 'InfoCoset', - 'InfoFpGroup', - 'InfoGroebner', - 'InfoGroup', - 'InfoLattice', - 'InfoMatrix', - 'InfoMonomial', - 'InfoNumtheor', - 'InfoOptions', - 'InfoPackageLoading', - 'InfoPcSubgroup', - 'InfoWarning', - 'Integers', - 'NiceBasisFiltersInfo', - 'Primes', - 'Rationals', - 'TableOfMarksComponents' -]) | common_gap_functions +common_gap_globals = { + 'Assert', + 'Cyclotomics', + 'GaussianIntegers', + 'GaussianRationals', + 'GlobalMersenneTwister', + 'GlobalRandomSource', + 'InfoAlgebra', + 'InfoAttributes', + 'InfoBckt', + 'InfoCharacterTable', + 'InfoCoh', + 'InfoComplement', + 'InfoCoset', + 'InfoFpGroup', + 'InfoGroebner', + 'InfoGroup', + 'InfoLattice', + 'InfoMatrix', + 'InfoMonomial', + 'InfoNumtheor', + 'InfoOptions', + 'InfoPackageLoading', + 'InfoPcSubgroup', + 'InfoWarning', + 'Integers', + 'NiceBasisFiltersInfo', + 'Primes', + 'Rationals', + 'TableOfMarksComponents' +} | common_gap_functions diff --git a/src/sage/libs/gap/meson.build b/src/sage/libs/gap/meson.build index 2302a169cb2..def07898f4c 100644 --- a/src/sage/libs/gap/meson.build +++ b/src/sage/libs/gap/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'all_documented_functions.py', 'assigned_names.py', diff --git a/src/sage/libs/gap/test_long.py b/src/sage/libs/gap/test_long.py index c92ff9d5223..262f3b00e28 100644 --- a/src/sage/libs/gap/test_long.py +++ b/src/sage/libs/gap/test_long.py @@ -28,7 +28,7 @@ def test_loop_2(): G = libgap.FreeGroup(2) a, b = G.GeneratorsOfGroup() for i in range(100): - rel = libgap([a**2, b**2, a*b*a*b]) + rel = libgap([a**2, b**2, a * b * a * b]) H = G / rel H1 = H.GeneratorsOfGroup()[0] n = H1.Order() diff --git a/src/sage/libs/giac/__init__.py b/src/sage/libs/giac/__init__.py index ba0be068152..49bbe254947 100644 --- a/src/sage/libs/giac/__init__.py +++ b/src/sage/libs/giac/__init__.py @@ -287,7 +287,7 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, return PolynomialSequence([P(0)], P, immutable=True) # check for name confusions - blackgiacconstants = ['i', 'e'] # NB e^k is expanded to exp(k) + blackgiacconstants = ['i', 'e'] # NB e^k is expanded to exp(k) blacklist = blackgiacconstants + [str(j) for j in libgiac.VARS()] problematicnames = sorted(set(P.gens_dict()).intersection(blacklist)) @@ -336,8 +336,8 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, var_names = var_names[:len(blocks[0])] else: raise NotImplementedError( - "%s is not a supported term order in " - "Giac Groebner bases." % P.term_order()) + "%s is not a supported term order in " + "Giac Groebner bases." % P.term_order()) # compute de groebner basis with giac gb_giac = F.gbasis(list(var_names), giac_order) diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index 91c42f3132c..7c32771bee8 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -102,6 +102,13 @@ TESTS:: sage: libgiac(-11^1000) -2469932918005826334124088385085221477709733385238396234869182951830739390375433175367866116456946191973803561189036523363533798726571008961243792655536655282201820357872673322901148243453211756020067624545609411212063417307681204817377763465511222635167942816318177424600927358163388910854695041070577642045540560963004207926938348086979035423732739933235077042750354729095729602516751896320598857608367865475244863114521391548985943858154775884418927768284663678512441565517194156946312753546771163991252528017732162399536497445066348868438762510366191040118080751580689254476068034620047646422315123643119627205531371694188794408120267120500325775293645416335230014278578281272863450085145349124727476223298887655183167465713337723258182649072572861625150703747030550736347589416285606367521524529665763903537989935510874657420361426804068643262800901916285076966174176854351055183740078763891951775452021781225066361670593917001215032839838911476044840388663443684517735022039957481918726697789827894303408292584258328090724141496484460001 +Ensure that signed infinities get converted correctly:: + + sage: libgiac(+Infinity) + +infinity + sage: libgiac(-Infinity) + -infinity + .. SEEALSO:: ``libgiac``, ``giacsettings``, ``Pygen``,``loadgiacgen`` @@ -159,6 +166,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.rings.integer cimport Integer +from sage.rings.infinity import AnInfinity from sage.rings.rational cimport Rational from sage.structure.element cimport Matrix @@ -374,13 +382,8 @@ def _giac(s): sage: (1+2*sin(3*x)).solve(x).simplify() ...list[-pi/18,7*pi/18] - sage: libgiac.solve('sin(3*x)>2*sin(x)',x) - Traceback (most recent call last): - ... - RuntimeError: Unable to find numeric values solving equation. For - trigonometric equations this may be solved using assumptions, e.g. - assume(x>-pi && xx',x) + list[((x>(-sqrt(2))) and (x<0)),x>(sqrt(2))] You can also add some hypothesis to a giac symbol:: @@ -860,6 +863,8 @@ cdef class Pygen(GiacMethods_base): s = s._giac_init_() except AttributeError: s = SRexpressiontoGiac(s) + elif isinstance(s, AnInfinity): + s = s._giac_init_() if not isinstance(s, str): s = s.__str__() sig_on() diff --git a/src/sage/libs/gmp/mpq.pxd b/src/sage/libs/gmp/mpq.pxd index 068988ffbc4..19d94b32808 100644 --- a/src/sage/libs/gmp/mpq.pxd +++ b/src/sage/libs/gmp/mpq.pxd @@ -55,4 +55,3 @@ cdef extern from "gmp.h": # Input and Output Functions # size_t mpq_out_str (file *stream, int base, mpq_t op) # size_t mpq_inp_str (mpq_t rop, file *stream, int base) - diff --git a/src/sage/libs/linbox/fflas.pxd b/src/sage/libs/linbox/fflas.pxd index 886f5c44cfa..e8e6cd6de40 100644 --- a/src/sage/libs/linbox/fflas.pxd +++ b/src/sage/libs/linbox/fflas.pxd @@ -111,14 +111,14 @@ cdef extern from "fflas-ffpack/fflas-ffpack.h" namespace "FFPACK": size_t s, size_t* P, size_t* Q, bool transform, size_t numthreads) Modular_double.Element* Solve (Modular_double F, size_t M, - Modular_double.Element* A, size_t lda, - Modular_double.Element* x, int incx, - Modular_double.Element* b, int incb) + Modular_double.Element* A, size_t lda, + Modular_double.Element* x, int incx, + Modular_double.Element* b, int incb) Modular_double.Element* pSolve (Modular_double F, size_t M, - Modular_double.Element* A, size_t lda, - Modular_double.Element* x, int incx, - Modular_double.Element* b, int incb, size_t numthreads) + Modular_double.Element* A, size_t lda, + Modular_double.Element* x, int incx, + Modular_double.Element* b, int incb, size_t numthreads) void applyP (Modular_double F, FFLAS_SIDE s, FFLAS_TRANSPOSE tr, @@ -165,14 +165,14 @@ cdef extern from "fflas-ffpack/fflas-ffpack.h" namespace "FFPACK": size_t s, size_t* P, size_t* Q, bool transform, size_t numthreads) Modular_float.Element* Solve (Modular_float F, size_t M, - Modular_float.Element* A, size_t lda, - Modular_float.Element* x, int incx, - Modular_float.Element* b, int incb) + Modular_float.Element* A, size_t lda, + Modular_float.Element* x, int incx, + Modular_float.Element* b, int incb) Modular_float.Element* pSolve (Modular_float F, size_t M, - Modular_float.Element* A, size_t lda, - Modular_float.Element* x, int incx, - Modular_float.Element* b, int incb, size_t numthreads) + Modular_float.Element* A, size_t lda, + Modular_float.Element* x, int incx, + Modular_float.Element* b, int incb, size_t numthreads) void applyP (Modular_float F, FFLAS_SIDE s, FFLAS_TRANSPOSE tr, diff --git a/src/sage/libs/m4ri.pxd b/src/sage/libs/m4ri.pxd index 7fbdd35b856..1306b72a74c 100644 --- a/src/sage/libs/m4ri.pxd +++ b/src/sage/libs/m4ri.pxd @@ -179,6 +179,9 @@ cdef extern from "m4ri/m4ri.h": # reduced row echelon form using PLUQ factorization cdef mzd_t *mzd_kernel_left_pluq(mzd_t *A, int cutoff) + # system solving + cdef int mzd_solve_left(mzd_t *A, mzd_t *B, int cutoff, int inconsistency_check) + ######################## # Bit operations ######################## @@ -192,4 +195,3 @@ cdef extern from "m4ri/m4ri.h": ################################## cdef void mzd_clear_bits(mzd_t *m, int x, int y, int n) - diff --git a/src/sage/libs/meson.build b/src/sage/libs/meson.build index 61b36da51f5..53470399d46 100644 --- a/src/sage/libs/meson.build +++ b/src/sage/libs/meson.build @@ -1,11 +1,16 @@ sirocco = cc.find_library('sirocco', required: false, disabler: true) # cannot be found via pkg-config ecl = cc.find_library('ecl') -braiding = cc.find_library('braiding') -gc = cc.find_library('gc') +braiding = dependency('libbraiding', required: false) +if not braiding.found() + # Fallback since pkg-config support was only added in v1.3.1 + braiding = cc.find_library('braiding') +endif +gc = dependency(['bdw-gc-threaded', 'bdw-gc'], version: '>=7.6.4') homfly = cc.find_library('homfly', has_headers: ['homfly.h']) py.install_sources( + '__init__.py', 'all.py', 'all__sagemath_coxeter3.py', 'all__sagemath_meataxe.py', @@ -36,7 +41,7 @@ foreach name, pyx : extension_data if name == 'sirocco' deps += [sirocco] elif name == 'meataxe' - deps += [mtx, meataxe] + deps += [mtx] endif py.extension_module( diff --git a/src/sage/libs/mpfi/__init__.pxd b/src/sage/libs/mpfi/__init__.pxd index b55a5129d18..6b81af16593 100644 --- a/src/sage/libs/mpfi/__init__.pxd +++ b/src/sage/libs/mpfi/__init__.pxd @@ -26,7 +26,7 @@ cdef extern from "mpfi.h": int mpfi_set_z(mpfi_ptr, mpz_t) int mpfi_set_q(mpfi_ptr, mpq_t) int mpfi_set_fr(mpfi_ptr, mpfr_srcptr) - int mpfi_set_str(mpfi_ptr, char *, int) + int mpfi_set_str(mpfi_ptr, const char *, int) # combined initialization and assignment functions int mpfi_init_set(mpfi_ptr, mpfi_srcptr) @@ -36,7 +36,7 @@ cdef extern from "mpfi.h": int mpfi_init_set_z(mpfi_ptr, mpz_srcptr) int mpfi_init_set_q(mpfi_ptr, mpq_srcptr) int mpfi_init_set_fr(mpfi_ptr, mpfr_srcptr) - int mpfi_init_set_str(mpfi_ptr, char *, int) + int mpfi_init_set_str(mpfi_ptr, const char *, int) # swapping two intervals void mpfi_swap(mpfi_ptr, mpfi_ptr) diff --git a/src/sage/libs/mpfr/__init__.pxd b/src/sage/libs/mpfr/__init__.pxd index facac9aa6c7..8bb85ff3c1a 100644 --- a/src/sage/libs/mpfr/__init__.pxd +++ b/src/sage/libs/mpfr/__init__.pxd @@ -27,7 +27,7 @@ cdef extern from "mpfr.h": # int mpfr_set_f(mpfr_t rop, mpf_t op, mpfr_rnd_t rnd) int mpfr_set_ui_2exp(mpfr_t rop, unsigned long int op, mp_exp_t e, mpfr_rnd_t rnd) int mpfr_set_si_2exp(mpfr_t rop, long int op, mp_exp_t e, mpfr_rnd_t rnd) - int mpfr_set_str(mpfr_t rop, char *s, int base, mpfr_rnd_t rnd) + int mpfr_set_str(mpfr_t rop, const char *s, int base, mpfr_rnd_t rnd) int mpfr_strtofr(mpfr_t rop, char *nptr, char **endptr, int base, mpfr_rnd_t rnd) void mpfr_set_inf(mpfr_t x, int sign) void mpfr_set_nan(mpfr_t x) @@ -43,7 +43,7 @@ cdef extern from "mpfr.h": int mpfr_init_set_z(mpfr_t rop, mpz_t op, mpfr_rnd_t rnd) int mpfr_init_set_q(mpfr_t rop, mpq_t op, mpfr_rnd_t rnd) # int mpfr_init_set_f(mpfr_t rop, mpf_t op, mpfr_rnd_t rnd) - int mpfr_init_set_str(mpfr_t x, char *s, int base, mpfr_rnd_t rnd) + int mpfr_init_set_str(mpfr_t x, const char *s, int base, mpfr_rnd_t rnd) # Conversion Functions double mpfr_get_d(mpfr_t op, mpfr_rnd_t rnd) diff --git a/src/sage/libs/mpmath/ext_impl.pyx b/src/sage/libs/mpmath/ext_impl.pyx index fdbbfa80a3a..8996d6296cf 100644 --- a/src/sage/libs/mpmath/ext_impl.pyx +++ b/src/sage/libs/mpmath/ext_impl.pyx @@ -2116,7 +2116,7 @@ cdef MPF_hypsum(MPF *a, MPF *b, int p, int q, param_types, str ztype, coeffs, z, raise ZeroDivisionError # Multiply real factors - for k in range(0, cancellable_real): + for k in range(cancellable_real): sig_check() mpz_mul(PRE, PRE, AREAL[k]) mpz_fdiv_q(PRE, PRE, BREAL[k]) @@ -2129,7 +2129,7 @@ cdef MPF_hypsum(MPF *a, MPF *b, int p, int q, param_types, str ztype, coeffs, z, mpz_mul_2exp(PRE, PRE, wp) mpz_fdiv_q(PRE, PRE, BREAL[k]) if have_complex: - for k in range(0, cancellable_real): + for k in range(cancellable_real): sig_check() mpz_mul(PIM, PIM, AREAL[k]) mpz_fdiv_q(PIM, PIM, BREAL[k]) diff --git a/src/sage/libs/mpmath/ext_main.pyx b/src/sage/libs/mpmath/ext_main.pyx index 96111f7b942..03840b3d8df 100644 --- a/src/sage/libs/mpmath/ext_main.pyx +++ b/src/sage/libs/mpmath/ext_main.pyx @@ -580,8 +580,7 @@ cdef class Context: s = (x).re.special t = (x).im.special return s == S_NAN or t == S_NAN - if type(x) is int or type(x) is long or isinstance(x, Integer) \ - or isinstance(x, rationallib.mpq): + if isinstance(x, (int, Integer, rationallib.mpq)): return False typ = MPF_set_any(&tmp_opx_re, &tmp_opx_im, x, global_opts, 0) if typ == 1: @@ -622,8 +621,7 @@ cdef class Context: s = (x).re.special t = (x).im.special return s == S_INF or s == S_NINF or t == S_INF or t == S_NINF - if type(x) is int or type(x) is long or isinstance(x, Integer) \ - or isinstance(x, rationallib.mpq): + if isinstance(x, (int, Integer, rationallib.mpq)): return False typ = MPF_set_any(&tmp_opx_re, &tmp_opx_im, x, global_opts, 0) if typ == 1: @@ -671,8 +669,7 @@ cdef class Context: if re == libmp.fzero: return im_normal if im == libmp.fzero: return re_normal return re_normal and im_normal - if type(x) is int or type(x) is long or isinstance(x, Integer) \ - or isinstance(x, rationallib.mpq): + if isinstance(x, (int, Integer, rationallib.mpq)): return bool(x) x = ctx.convert(x) if hasattr(x, '_mpf_') or hasattr(x, '_mpc_'): @@ -708,7 +705,7 @@ cdef class Context: cdef MPF v cdef MPF w cdef int typ - if type(x) is int or type(x) is long or isinstance(x, Integer): + if isinstance(x, (int, Integer)): return True if isinstance(x, mpf): v = (x).value diff --git a/src/sage/libs/ntl/ZZ_pX.pxd b/src/sage/libs/ntl/ZZ_pX.pxd index 8c9f609f1cd..4c6895581dd 100644 --- a/src/sage/libs/ntl/ZZ_pX.pxd +++ b/src/sage/libs/ntl/ZZ_pX.pxd @@ -119,4 +119,3 @@ cdef extern from "ntlwrap_impl.h": void ZZ_pX_right_pshift(ZZ_pX_c x, ZZ_pX_c a, ZZ_c pn, ZZ_pContext_c c) void ZZ_pX_InvMod_newton_unram(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_Modulus_c F, ZZ_pContext_c cpn, ZZ_pContext_c cp) void ZZ_pX_InvMod_newton_ram(ZZ_pX_c x, ZZ_pX_c a, ZZ_pX_Modulus_c F, ZZ_pContext_c cpn) - diff --git a/src/sage/libs/ntl/ntl_GF2E.pxd b/src/sage/libs/ntl/ntl_GF2E.pxd index c36292c8748..f12777b16c9 100644 --- a/src/sage/libs/ntl/ntl_GF2E.pxd +++ b/src/sage/libs/ntl/ntl_GF2E.pxd @@ -5,4 +5,3 @@ cdef class ntl_GF2E(): cdef GF2E_c x cdef ntl_GF2EContext_class c cdef ntl_GF2E _new(self) - diff --git a/src/sage/libs/ntl/ntl_mat_GF2.pyx b/src/sage/libs/ntl/ntl_mat_GF2.pyx index 479f4505b71..dd910a567c0 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2.pyx @@ -315,10 +315,10 @@ cdef class ntl_mat_GF2(): if isinstance(ij, tuple) and len(ij) == 2: i, j = ij - elif self.x.NumCols()==1 and (isinstance(ij, Integer) or isinstance(ij, int)): + elif self.x.NumCols() == 1 and isinstance(ij, (Integer, int)): i = ij j = 0 - elif self.x.NumRows()==1 and (isinstance(ij, Integer) or isinstance(ij, int)): + elif self.x.NumRows() == 1 and isinstance(ij, (Integer, int)): i = 0 j = ij else: @@ -342,10 +342,10 @@ cdef class ntl_mat_GF2(): cdef int i, j if isinstance(ij, tuple) and len(ij) == 2: i, j = ij - elif self.x.NumCols() == 1 and (isinstance(ij, Integer) or isinstance(ij, int)): + elif self.x.NumCols() == 1 and isinstance(ij, (Integer, int)): i = ij j = 0 - elif self.x.NumRows() == 1 and (isinstance(ij, Integer) or isinstance(ij, int)): + elif self.x.NumRows() == 1 and isinstance(ij, (Integer, int)): i = 0 j = ij else: diff --git a/src/sage/libs/ntl/ntl_mat_GF2E.pyx b/src/sage/libs/ntl/ntl_mat_GF2E.pyx index eb044cbfc37..7841952cacc 100644 --- a/src/sage/libs/ntl/ntl_mat_GF2E.pyx +++ b/src/sage/libs/ntl/ntl_mat_GF2E.pyx @@ -377,10 +377,10 @@ cdef class ntl_mat_GF2E(): if isinstance(ij, tuple) and len(ij) == 2: i, j = ij - elif self.x.NumCols()==1 and (isinstance(ij, Integer) or isinstance(ij, int)): + elif self.x.NumCols() == 1 and isinstance(ij, (Integer, int)): i = ij j = 0 - elif self.x.NumRows()==1 and (isinstance(ij, Integer) or isinstance(ij, int)): + elif self.x.NumRows() == 1 and isinstance(ij, (Integer, int)): i = 0 j = ij else: @@ -411,10 +411,10 @@ cdef class ntl_mat_GF2E(): cdef int i, j if isinstance(ij, tuple) and len(ij) == 2: i, j = ij - elif self.x.NumCols() == 1 and (isinstance(ij, Integer) or isinstance(ij, int)): + elif self.x.NumCols() == 1 and isinstance(ij, (Integer, int)): i = ij j = 0 - elif self.x.NumRows() == 1 and (isinstance(ij, Integer) or isinstance(ij, int)): + elif self.x.NumRows() == 1 and isinstance(ij, (Integer, int)): i = 0 j = ij else: diff --git a/src/sage/libs/pari/__init__.py b/src/sage/libs/pari/__init__.py index ccb18792918..b5bc281db4d 100644 --- a/src/sage/libs/pari/__init__.py +++ b/src/sage/libs/pari/__init__.py @@ -173,6 +173,7 @@ 3.60546360143265208591582056420772677481026899659802474544 # 32-bit """ + def _get_pari_instance(): """ TESTS:: @@ -181,8 +182,8 @@ def _get_pari_instance(): Interface to the PARI C library """ from cypari2 import Pari - stack_initial = 1024*1024 - stack_max = 1024*stack_initial + stack_initial = 1024 * 1024 + stack_max = 1024 * stack_initial P = Pari(stack_initial, stack_max) # pari_init_opts() overrides MPIR's memory allocation functions, diff --git a/src/sage/libs/singular/decl.pxd b/src/sage/libs/singular/decl.pxd index d8c6d9a1201..3980a856368 100644 --- a/src/sage/libs/singular/decl.pxd +++ b/src/sage/libs/singular/decl.pxd @@ -131,25 +131,25 @@ cdef extern from "singular/Singular/libsingular.h": number* cfSub(number *, number *, const n_Procs_s* r) number* cfMult(number *, number *, const n_Procs_s* r) # algebraic number multiplication - number* (*cfInit)(int i, const n_Procs_s* r ) # algebraic number from int - number* (*cfInitMPZ)(mpz_t i, const n_Procs_s* r) - number* (*cfParameter)(int i, const n_Procs_s* r) - int (*cfParDeg)(number* n, const n_Procs_s* r) - int (*cfSize)(number* n, const n_Procs_s* r) - int (*cfInt)(number* n, const n_Procs_s* r) - int (*cdDivComp)(number* a,number* b, const n_Procs_s* r) - number* (*cfGetUnit)(number* a, const n_Procs_s* r) - number* (*cfExtGcd)(number* a, number* b, number* *s, number* *t , const n_Procs_s* r) + number* (*cfInit)(int i, const n_Procs_s* r ) # algebraic number from int + number* (*cfInitMPZ)(mpz_t i, const n_Procs_s* r) + number* (*cfParameter)(int i, const n_Procs_s* r) + int (*cfParDeg)(number* n, const n_Procs_s* r) + int (*cfSize)(number* n, const n_Procs_s* r) + int (*cfInt)(number* n, const n_Procs_s* r) + int (*cdDivComp)(number* a,number* b, const n_Procs_s* r) + number* (*cfGetUnit)(number* a, const n_Procs_s* r) + number* (*cfExtGcd)(number* a, number* b, number* *s, number* *t , const n_Procs_s* r) void (*cfDelete)(number **, const n_Procs_s*) - number* (*cfInpNeg)(number* a, const n_Procs_s* r) - number* (*cfInvers)(number* a, const n_Procs_s* r) - number* (*cfCopy)(number* a, const n_Procs_s* r) # deep copy of algebraic number - number* (*cfRePart)(number* a, const n_Procs_s* cf) - number* (*cfImPart)(number* a, const n_Procs_s* cf) - void (*cfWrite)(number* a, const n_Procs_s* r) - void (*cfNormalize)(number* a, const n_Procs_s* r) + number* (*cfInpNeg)(number* a, const n_Procs_s* r) + number* (*cfInvers)(number* a, const n_Procs_s* r) + number* (*cfCopy)(number* a, const n_Procs_s* r) # deep copy of algebraic number + number* (*cfRePart)(number* a, const n_Procs_s* cf) + number* (*cfImPart)(number* a, const n_Procs_s* cf) + void (*cfWrite)(number* a, const n_Procs_s* r) + void (*cfNormalize)(number* a, const n_Procs_s* r) bint (*cfDivBy)(number* a, number* b, const n_Procs_s* r) bint (*cfEqual)(number* a,number* b, const n_Procs_s* ) @@ -164,7 +164,7 @@ cdef extern from "singular/Singular/libsingular.h": mpz_ptr modBase unsigned long modExponent - #n_coeffType type + # n_coeffType type int type # polynomials @@ -209,7 +209,7 @@ cdef extern from "singular/Singular/libsingular.h": int pCompIndex # index of components unsigned long bitmask # mask for getting single exponents - n_Procs_s* cf # coefficient field/ring + n_Procs_s* cf # coefficient field/ring int ref # return total degree of p @@ -333,11 +333,11 @@ cdef extern from "singular/Singular/libsingular.h": TObject *T LObject *L LObject *B - poly* kHEdge - poly* kNoether - poly* t_kHEdge - poly* kNoetherTail() - poly* t_kNoether + poly* kHEdge + poly* kNoether + poly* t_kHEdge + poly* kNoetherTail() + poly* t_kNoether bint *NotUsedAxis bint *pairtest void *R @@ -351,10 +351,10 @@ cdef extern from "singular/Singular/libsingular.h": ctypedef struct attr "sattr": void (*Init)() - char * name - void * data - attr * next - int atyp # the type of the attribute, describes the data field + char * name + void * data + attr * next + int atyp # the type of the attribute, describes the data field void (*Print)() attr *(*Copy)() # copy all arguments @@ -374,9 +374,9 @@ cdef extern from "singular/Singular/libsingular.h": ctypedef struct leftv "sleftv": leftv *next - char *id + char *id void* data - #data is some union, so this might be very dangerous, but I am lazy now + # data is some union, so this might be very dangerous, but I am lazy now attr *attribute void (* Copy)(leftv*) void (* Init)() diff --git a/src/sage/libs/singular/function.pyx b/src/sage/libs/singular/function.pyx index 7bf2afafbe8..67cadf5d35c 100644 --- a/src/sage/libs/singular/function.pyx +++ b/src/sage/libs/singular/function.pyx @@ -97,7 +97,7 @@ from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence_g from sage.libs.singular.decl cimport * from sage.libs.singular.option import opt_ctx from sage.libs.singular.polynomial cimport singular_vector_maximal_component -from sage.libs.singular.singular cimport sa2si, si2sa, si2sa_intvec, si2sa_bigintvec +from sage.libs.singular.singular cimport sa2si, si2sa, si2sa_intvec, si2sa_bigintvec, start_catch_error, check_error from sage.libs.singular.singular import error_messages from sage.interfaces.singular import get_docstring @@ -386,11 +386,8 @@ def is_sage_wrapper_for_singular_ring(ring): sage: is_sage_wrapper_for_singular_ring(P) True """ - if isinstance(ring, MPolynomialRing_libsingular): - return True - if isinstance(ring, NCPolynomialRing_plural): - return True - return False + return isinstance(ring, (MPolynomialRing_libsingular, + NCPolynomialRing_plural)) cdef new_sage_polynomial(ring, poly *p): @@ -523,8 +520,7 @@ cdef class Converter(SageObject): elif is_sage_wrapper_for_singular_ring(a): v = self.append_ring(a) - elif isinstance(a, MPolynomialIdeal) or \ - isinstance(a, NCPolynomialIdeal): + elif isinstance(a, (MPolynomialIdeal, NCPolynomialIdeal)): v = self.append_ideal(a) elif isinstance(a, int): @@ -569,8 +565,7 @@ cdef class Converter(SageObject): elif isinstance(a, tuple): is_intvec = True for i in a: - if not (isinstance(i, int) - or isinstance(i, Integer)): + if not isinstance(i, (int, Integer)): is_intvec = False break if is_intvec: @@ -584,7 +579,7 @@ cdef class Converter(SageObject): v = self.append_int(a) else: - raise TypeError("unknown argument type '%s'"%(type(a),)) + raise TypeError("unknown argument type '%s'" % (type(a),)) if attributes and a in attributes: for attrib in attributes[a]: @@ -593,7 +588,7 @@ cdef class Converter(SageObject): atSet(v, omStrDup("isSB"), val, INT_CMD) setFlag(v, FLAG_STD) else: - raise NotImplementedError("Support for attribute '%s' not implemented yet."%attrib) + raise NotImplementedError("Support for attribute '%s' not implemented yet." % attrib) def ring(self): """ @@ -808,15 +803,15 @@ cdef class Converter(SageObject): """ Append the number ``n`` to the list. """ - cdef number *_n = sa2si(n, self._singular_ring) + cdef number *_n = sa2si(n, self._singular_ring) return self._append(_n, NUMBER_CMD) cdef leftv *append_ring(self, r) except NULL: """ Append the ring ``r`` to the list. """ - cdef ring *_r = access_singular_ring(r) - _r.ref+=1 + cdef ring *_r = access_singular_ring(r) + _r.ref += 1 return self._append(_r, RING_CMD) cdef leftv *append_matrix(self, mat) except NULL: @@ -838,7 +833,7 @@ cdef class Converter(SageObject): """ Append the integer ``n`` to the list. """ - cdef long _n = n + cdef long _n = n return self._append(_n, INT_CMD) cdef leftv *append_list(self, l) except NULL: @@ -1304,8 +1299,9 @@ cdef class SingularFunction(SageObject): from sage.rings.rational_field import QQ dummy_ring = PolynomialRing(QQ, "dummy", implementation='singular') # seems a reasonable default ring = dummy_ring - if not (isinstance(ring, MPolynomialRing_libsingular) or isinstance(ring, NCPolynomialRing_plural)): - raise TypeError("cannot call Singular function '%s' with ring parameter of type '%s'" % (self._name,type(ring))) + if not isinstance(ring, (MPolynomialRing_libsingular, + NCPolynomialRing_plural)): + raise TypeError("cannot call Singular function '%s' with ring parameter of type '%s'" % (self._name, type(ring))) return call_function(self, args, ring, interruptible, attributes) def _instancedoc_(self): @@ -1450,10 +1446,8 @@ EXAMPLES:: cdef inline call_function(SingularFunction self, tuple args, object R, bint signal_handler=True, attributes=None): global currRingHdl - global errorreported global currentVoice global myynest - global error_messages cdef ring *si_ring if isinstance(R, MPolynomialRing_libsingular): @@ -1474,29 +1468,28 @@ cdef inline call_function(SingularFunction self, tuple args, object R, bint sign currentVoice = NULL myynest = 0 - errorreported = 0 - - while error_messages: - error_messages.pop() + start_catch_error() with opt_ctx: # we are preserving the global options state here if signal_handler: - sig_on() - _res = self.call_handler.handle_call(argument_list, si_ring) - sig_off() + try: + sig_on() + _res = self.call_handler.handle_call(argument_list, si_ring) + sig_off() + finally: + s = check_error() else: _res = self.call_handler.handle_call(argument_list, si_ring) + s = check_error() - if myynest: - myynest = 0 + myynest = 0 if currentVoice: currentVoice = NULL - if errorreported: - errorreported = 0 + if s: raise RuntimeError("error in Singular function call %r:\n%s" % - (self._name, "\n".join(error_messages))) + (self._name, "\n".join(s))) res = argument_list.to_python(_res) diff --git a/src/sage/libs/singular/polynomial.pyx b/src/sage/libs/singular/polynomial.pyx index db4b2ff35e2..a6023aaa2ae 100644 --- a/src/sage/libs/singular/polynomial.pyx +++ b/src/sage/libs/singular/polynomial.pyx @@ -504,7 +504,7 @@ cdef object singular_polynomial_latex(poly *p, ring *r, object base, object late multi = multi.lstrip().rstrip() # Next determine coefficient of multinomial - c = si2sa(p_GetCoeff(p, r), r, base) + c = si2sa(p_GetCoeff(p, r), r, base) if not multi: multi = latex(c) elif c != 1: @@ -573,7 +573,7 @@ cdef long singular_polynomial_deg(poly *p, poly *x, ring *r) noexcept: if p_GetExp(x, i, r): break while p: - _deg = p_GetExp(p,i,r) + _deg = p_GetExp(p, i, r) if _deg > deg: deg = _deg p = pNext(p) diff --git a/src/sage/libs/singular/ring.pyx b/src/sage/libs/singular/ring.pyx index f770cc483a5..1d8dd844385 100644 --- a/src/sage/libs/singular/ring.pyx +++ b/src/sage/libs/singular/ring.pyx @@ -19,7 +19,7 @@ AUTHORS: from sage.cpython.string cimport str_to_bytes, bytes_to_str from sage.libs.gmp.types cimport __mpz_struct -from sage.libs.gmp.mpz cimport mpz_init_set_ui +from sage.libs.gmp.mpz cimport mpz_init_set from sage.libs.singular.decl cimport ring, currRing from sage.libs.singular.decl cimport rChangeCurrRing, rComplete, rDelete, idInit @@ -31,6 +31,7 @@ from sage.libs.singular.decl cimport n_coeffType from sage.libs.singular.decl cimport rDefault, GFInfo, ZnmInfo, nInitChar, AlgExtInfo, TransExtInfo +from sage.rings.integer cimport Integer from sage.rings.integer_ring cimport IntegerRing_class from sage.rings.integer_ring import ZZ import sage.rings.abc @@ -80,7 +81,7 @@ if bytes_to_str(rSimpleOrdStr(ringorder_ip)) == "rp": ############################################################################# cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: - """ + r""" Create a new Singular ring over the ``base_ring`` in ``n`` variables with the names ``names`` and the term order ``term_order``. @@ -159,17 +160,136 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: sage: R. = F[] sage: from sage.libs.singular.function import singular_function sage: sing_print = singular_function('print') - sage: sing_print(R) - 'polynomial ring, over a field, global ordering\n// coefficients: ZZ/7(a, b)\n// number of vars : 3\n// block 1 : ordering dp\n// : names x y z\n// block 2 : ordering C' + sage: print(sing_print(R)) + polynomial ring, over a field, global ordering + // coefficients: ZZ/7(a, b) + // number of vars : 3 + // block 1 : ordering dp + // : names x y z + // block 2 : ordering C :: sage: F = PolynomialRing(QQ, 's,t').fraction_field() sage: R. = F[] sage: from sage.libs.singular.function import singular_function - sage: sing_print = singular_function('print') - sage: sing_print(R) - 'polynomial ring, over a field, global ordering\n// coefficients: QQ(s, t)\n// number of vars : 3\n// block 1 : ordering dp\n// : names x y z\n// block 2 : ordering C' + sage: print(sing_print(R)) + polynomial ring, over a field, global ordering + // coefficients: QQ(s, t) + // number of vars : 3 + // block 1 : ordering dp + // : names x y z + // block 2 : ordering C + + Small primes:: + + sage: R = PolynomialRing(GF(2), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a field, global ordering + // coefficients: ZZ/2 + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + sage: R = PolynomialRing(GF(3), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a field, global ordering + // coefficients: ZZ/3 + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + sage: R = PolynomialRing(GF(1000000007), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a field, global ordering + // coefficients: ZZ/1000000007 + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + + When ``Zmod`` is used, use a different Singular type + (note that the print is wrong, the field in fact doesn't have zero-divisors):: + + sage: R = PolynomialRing(Zmod(2), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a ring (with zero-divisors), global ordering + // coefficients: ZZ/(2) + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + sage: R = PolynomialRing(Zmod(3), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a ring (with zero-divisors), global ordering + // coefficients: ZZ/(3) + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + + Large prime (note that the print is wrong, the field in fact doesn't have zero-divisors):: + + sage: R = PolynomialRing(GF(2^128+51), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a ring (with zero-divisors), global ordering + // coefficients: ZZ/bigint(340282366920938463463374607431768211507) + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + + Finite field with large degree (note that if stack size is too small and the exponent is too large + a stack overflow may happen inside libsingular):: + + sage: R = PolynomialRing(GF(2^160), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a field, global ordering + // coefficients: ZZ/2[z160]/(z160^160+z160^159+z160^155+z160^154+z160^153+z160^152+z160^151+z160^149+z160^148+z160^147+z160^146+z160^145+z160^144+z160^143+z160^141+z160^139+z160^137+z160^131+z160^129+z160^128+z160^127+z160^126+z160^123+z160^122+z160^121+z160^117+z160^116+z160^115+z160^113+z160^111+z160^110+z160^108+z160^106+z160^102+z160^100+z160^99+z160^97+z160^96+z160^95+z160^94+z160^93+z160^92+z160^91+z160^87+z160^86+z160^82+z160^80+z160^79+z160^78+z160^74+z160^73+z160^72+z160^71+z160^70+z160^67+z160^66+z160^65+z160^62+z160^59+z160^58+z160^57+z160^55+z160^54+z160^53+z160^52+z160^51+z160^49+z160^47+z160^44+z160^40+z160^35+z160^32+z160^30+z160^28+z160^27+z160^26+z160^24+z160^23+z160^21+z160^20+z160^18+z160^16+z160^11+z160^10+z160^8+z160^7+1) + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + + Integer modulo small power of 2:: + + sage: R = PolynomialRing(Zmod(2^32), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a ring (with zero-divisors), global ordering + // coefficients: ZZ/(2^32) + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + + Integer modulo large power of 2:: + + sage: R = PolynomialRing(Zmod(2^1000), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a ring (with zero-divisors), global ordering + // coefficients: ZZ/(bigint(2)^1000) + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + + Integer modulo large power of odd prime:: + + sage: R = PolynomialRing(Zmod(3^300), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a ring (with zero-divisors), global ordering + // coefficients: ZZ/(bigint(3)^300) + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + + Integer modulo non-prime:: + + sage: R = PolynomialRing(Zmod(15^20), ("a", "b"), implementation="singular"); print(sing_print(R)) + polynomial ring, over a ring (with zero-divisors), global ordering + // coefficients: ZZ/bigint(332525673007965087890625) + // number of vars : 2 + // block 1 : ordering dp + // : names a b + // block 2 : ordering C + + Non-prime finite field with large characteristic (not supported, see :issue:`33319`):: + + sage: PolynomialRing(GF((2^31+11)^2), ("a", "b"), implementation="singular") + Traceback (most recent call last): + ... + TypeError: characteristic must be <= 2147483647. """ cdef long cexponent cdef GFInfo* _param @@ -182,7 +302,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: cdef int offset cdef int nvars cdef int characteristic - cdef int modbase + cdef Integer ch, modbase cdef int ringorder_column_pos cdef int ringorder_column_asc @@ -312,7 +432,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: _cfr = rDefault( 0, ngens, _ext_names ) rComplete(_cfr, 1) - trextParam.r = _cfr + trextParam.r = _cfr _cf = nInitChar(n_transExt, &trextParam) @@ -338,7 +458,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: _cfr = rDefault( characteristic, ngens, _ext_names ) rComplete(_cfr, 1) - trextParam.r = _cfr + trextParam.r = _cfr _cf = nInitChar(n_transExt, &trextParam) @@ -363,7 +483,7 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: _cfr.qideal = idInit(1,1) rComplete(_cfr, 1) _cfr.qideal.m[0] = prCopyR(minpoly._poly, k._ring, _cfr) - extParam.r = _cfr + extParam.r = _cfr # _type = nRegister(n_algExt, naInitChar); _cf = nInitChar( n_algExt, &extParam) # @@ -377,44 +497,62 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: _cf = nInitChar( n_Z, NULL) # integer coefficient ring _ring = rDefault (_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) - elif (isinstance(base_ring, FiniteField_generic) and base_ring.is_prime_field()): - if base_ring.characteristic() <= 2147483647: + elif isinstance(base_ring, sage.rings.abc.IntegerModRing): + + ch = base_ring.characteristic() + if ch < 2: + raise NotImplementedError(f"polynomials over {base_ring} are not supported in Singular") + + isprime = ch.is_prime() + + if isprime and ch <= 2147483647 and isinstance(base_ring, FiniteField_generic): + # don't use this branch for e.g. Zmod(5) characteristic = base_ring.characteristic() + + # example for simpler ring creation interface without monomial orderings: + #_ring = rDefault(characteristic, nvars, _names) + + _ring = rDefault(characteristic, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) + else: - raise TypeError("Characteristic p must be <= 2147483647.") + modbase, cexponent = ch.perfect_power() - # example for simpler ring creation interface without monomial orderings: - #_ring = rDefault(characteristic, nvars, _names) + if modbase == 2 and cexponent > 1: + _cf = nInitChar(n_Z2m, cexponent) - _ring = rDefault(characteristic, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) + elif modbase.is_prime() and cexponent > 1: + _info.base = <__mpz_struct *>omAlloc(sizeof(__mpz_struct)) + mpz_init_set(_info.base, modbase.value) + _info.exp = cexponent + _cf = nInitChar(n_Znm, &_info) + + else: + _info.base = <__mpz_struct *>omAlloc(sizeof(__mpz_struct)) + mpz_init_set(_info.base, ch.value) + _info.exp = 1 + _cf = nInitChar(n_Zn, &_info) + _ring = rDefault(_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) elif isinstance(base_ring, FiniteField_generic): - if base_ring.characteristic() <= 2147483647: - characteristic = -base_ring.characteristic() # note the negative characteristic - else: + assert not base_ring.is_prime_field() # would have been handled above + if base_ring.characteristic() > 2147483647: raise TypeError("characteristic must be <= 2147483647.") # TODO: This is lazy, it should only call Singular stuff not PolynomialRing() k = PolynomialRing(base_ring.prime_subfield(), - name=base_ring.variable_name(), order='lex', implementation='singular') + name=base_ring.variable_name(), order='lex', + implementation='singular') minpoly = base_ring.polynomial()(k.gen()) - ch = base_ring.characteristic() - F = ch.factor() - assert(len(F)==1) - - modbase = F[0][0] - cexponent = F[0][1] - _ext_names = omAlloc0(sizeof(char*)) _name = str_to_bytes(k._names[0]) _ext_names[0] = omStrDup(_name) - _cfr = rDefault( modbase, 1, _ext_names ) + _cfr = rDefault(base_ring.characteristic(), 1, _ext_names) _cfr.qideal = idInit(1,1) rComplete(_cfr, 1) _cfr.qideal.m[0] = prCopyR(minpoly._poly, k._ring, _cfr) - extParam.r = _cfr + extParam.r = _cfr _cf = nInitChar( n_algExt, &extParam) if (_cf is NULL): @@ -422,60 +560,6 @@ cdef ring *singular_ring_new(base_ring, n, names, term_order) except NULL: _ring = rDefault (_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) - elif isinstance(base_ring, sage.rings.abc.IntegerModRing): - - ch = base_ring.characteristic() - if ch < 2: - raise NotImplementedError(f"polynomials over {base_ring} are not supported in Singular") - - isprime = ch.is_prime() - - if not isprime and ch.is_power_of(2): - exponent = ch.nbits() -1 - cexponent = exponent - - if exponent <= 30: - ringtype = n_Z2m - else: - ringtype = n_Znm - - if ringtype == n_Znm: - F = ch.factor() - - modbase = F[0][0] - cexponent = F[0][1] - - _info.base = <__mpz_struct*>omAlloc(sizeof(__mpz_struct)) - mpz_init_set_ui(_info.base, modbase) - _info.exp = cexponent - _cf = nInitChar(ringtype, &_info) - else: # ringtype == n_Z2m - _cf = nInitChar(ringtype, cexponent) - - elif not isprime and ch.is_prime_power() and ch < ZZ(2)**160: - F = ch.factor() - assert(len(F)==1) - - modbase = F[0][0] - cexponent = F[0][1] - - _info.base = <__mpz_struct*>omAlloc(sizeof(__mpz_struct)) - mpz_init_set_ui(_info.base, modbase) - _info.exp = cexponent - _cf = nInitChar( n_Znm, &_info ) - - else: - try: - characteristic = ch - except OverflowError: - raise NotImplementedError("Characteristic %d too big." % ch) - - _info.base = <__mpz_struct*>omAlloc(sizeof(__mpz_struct)) - mpz_init_set_ui(_info.base, characteristic) - _info.exp = 1 - _cf = nInitChar( n_Zn, &_info ) - _ring = rDefault(_cf, nvars, _names, nblcks, _order, _block0, _block1, _wvhdl) - else: raise NotImplementedError(f"polynomials over {base_ring} are not supported in Singular") diff --git a/src/sage/libs/singular/singular.pxd b/src/sage/libs/singular/singular.pxd index 9d764b51a6f..a0019fe4ede 100644 --- a/src/sage/libs/singular/singular.pxd +++ b/src/sage/libs/singular/singular.pxd @@ -55,6 +55,13 @@ cdef number *sa2si_NF(object element, ring *_ring) noexcept # dispatches to all the above. cdef number *sa2si(Element elem, ring * _ring) noexcept +# ============== +# Error handling +# ============== + +cdef int start_catch_error() except -1 +cdef object check_error() + # ============== # Initialisation # ============== diff --git a/src/sage/libs/singular/singular.pyx b/src/sage/libs/singular/singular.pyx index 9c7b4078583..d4ed0e3b064 100644 --- a/src/sage/libs/singular/singular.pyx +++ b/src/sage/libs/singular/singular.pyx @@ -25,6 +25,7 @@ cdef extern from "limits.h": long INT_MIN import os +from warnings import warn from libc.stdint cimport int64_t from sage.libs.singular.decl cimport * @@ -302,6 +303,9 @@ cdef object si2sa_GFq_generic(number *n, ring *_ring, object base): cdef object ret cdef ring *cfRing = _ring.cf.extRing + if _ring.cf.type in (n_Zn, n_Znm): + return si2sa_ZZmod(n, _ring, base) + if _ring.cf.cfIsZero(n,_ring.cf): return base.zero() elif _ring.cf.cfIsOne(n,_ring.cf): @@ -886,7 +890,7 @@ cdef number *sa2si_QQ(Rational r, ring *_ring) noexcept: - ``r`` -- a sage rational number - - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the result will live OUTPUT: @@ -916,7 +920,7 @@ cdef number *sa2si_GFqGivaro(int quo, ring *_ring) noexcept: - ``quo`` -- sage integer - - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the result will live OUTPUT: @@ -984,7 +988,7 @@ cdef number *sa2si_GFqNTLGF2E(FFgf2eE elem, ring *_ring) noexcept: - ``elem`` -- a sage element of a ntl_gf2e finite field - - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the result will live OUTPUT: @@ -1049,7 +1053,7 @@ cdef number *sa2si_GFq_generic(object elem, ring *_ring) noexcept: - ``elem`` -- a sage element of a generic finite field - - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the result will live OUTPUT: @@ -1075,6 +1079,9 @@ cdef number *sa2si_GFq_generic(object elem, ring *_ring) noexcept: cdef number *coeff cdef number *apow1 cdef number *apow2 + + if _ring.cf.type in (n_Zn, n_Znm): + return sa2si_ZZmod(elem, _ring) elem = elem.polynomial() if _ring != currRing: rChangeCurrRing(_ring) @@ -1115,7 +1122,7 @@ cdef number *sa2si_transext_QQ(object elem, ring *_ring) noexcept: - ``elem`` -- a sage element of a FractionField of polynomials over the rationals - - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the result will live OUTPUT: @@ -1183,7 +1190,7 @@ cdef number *sa2si_transext_QQ(object elem, ring *_ring) noexcept: ngens = elem.parent().ngens() - nMapFuncPtr = naSetMap(_ring.cf, currRing.cf) # choose correct mapping function + nMapFuncPtr = naSetMap(_ring.cf, currRing.cf) # choose correct mapping function if nMapFuncPtr is NULL: raise RuntimeError("Failed to determine nMapFuncPtr") @@ -1265,7 +1272,7 @@ cdef number *sa2si_transext_FF(object elem, ring *_ring) noexcept: - ``elem`` -- a sage element of a FractionField of polynomials over the rationals - - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the result will live OUTPUT: @@ -1298,7 +1305,7 @@ cdef number *sa2si_transext_FF(object elem, ring *_ring) noexcept: ngens = elem.parent().ngens() - nMapFuncPtr = naSetMap(_ring.cf, currRing.cf) # choose correct mapping function + nMapFuncPtr = naSetMap(_ring.cf, currRing.cf) # choose correct mapping function if nMapFuncPtr is NULL: raise RuntimeError("Failed to determine nMapFuncPtr") @@ -1365,7 +1372,7 @@ cdef number *sa2si_NF(object elem, ring *_ring) noexcept: - ``elem`` -- a sage element of a NumberField - - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the result will live OUTPUT: @@ -1386,6 +1393,13 @@ cdef number *sa2si_NF(object elem, ring *_ring) noexcept: (a + 1) sage: R(F.gen()^5) + 1 (-a^2 + a + 2) + + Ensures :issue:`36101` is fixed:: + + sage: RR. = AA[] + sage: f = -4*r^2+(((1+2*AA(cos(pi/6)))*c0*r+2*c1*r+(1+2*AA(cos(pi/6)))*s0*r+2*s1*r)/2-1/2)^2+((1-(1+2*AA(cos(pi/6)))*c0*r-2*c1*r+(1+2*AA(cos(pi/6)))*s0*r+2*s1*r)/2-1/2)^2 + sage: f.change_ring( QuadraticField(3) ) + ... """ cdef int i cdef number *n1 @@ -1396,13 +1410,6 @@ cdef number *sa2si_NF(object elem, ring *_ring) noexcept: cdef number *apow1 cdef number *apow2 - cdef nMapFunc nMapFuncPtr = NULL - - nMapFuncPtr = naSetMap(_ring.cf, currRing.cf) # choose correct mapping function - - if nMapFuncPtr is NULL: - raise RuntimeError("Failed to determine nMapFuncPtr") - elem = list(elem) if _ring != currRing: @@ -1425,7 +1432,10 @@ cdef number *sa2si_NF(object elem, ring *_ring) noexcept: rComplete(qqr,1) qqr.ShortOut = 0 - nMapFuncPtr = naSetMap(qqr.cf, _ring.cf) # choose correct mapping function + assert _ring.cf.type == n_algExt # if false naSetMap will segmentation fault (should never happen) + cdef nMapFunc nMapFuncPtr = naSetMap(qqr.cf, _ring.cf) # choose correct mapping function + if nMapFuncPtr is NULL: + raise RuntimeError("Failed to determine nMapFuncPtr") cdef poly *_p for i from 0 <= i < len(elem): nlCoeff = nlInit2gmp( mpq_numref((elem[i]).value), mpq_denref((elem[i]).value), qqr.cf ) @@ -1457,7 +1467,7 @@ cdef number *sa2si_ZZ(Integer d, ring *_ring) noexcept: - ``elem`` -- a sage Integer - - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the result will live OUTPUT: @@ -1488,7 +1498,7 @@ cdef inline number *sa2si_ZZmod(IntegerMod_abstract d, ring *_ring) noexcept: - ``elem`` -- a sage IntegerMod - - ``_ ring`` -- a (pointer to) a singular ring, where the resul will live + - ``_ ring`` -- a (pointer to) a singular ring, where the result will live TESTS:: @@ -1512,7 +1522,7 @@ cdef inline number *sa2si_ZZmod(IntegerMod_abstract d, ring *_ring) noexcept: sage: P. = Integers(2^32)[] sage: P(2^32-1) - 4294967295 + -1 sage: P(3) 3 @@ -1534,8 +1544,11 @@ cdef inline number *sa2si_ZZmod(IntegerMod_abstract d, ring *_ring) noexcept: cdef nMapFunc nMapFuncPtr = NULL + if _ring.cf.type == n_unknown: + return n_Init(int(d), _ring.cf) + if _ring.cf.type == n_Z2m: - _d = long(d) + _d = d return nr2mMapZp(_d, currRing.cf, _ring.cf) elif _ring.cf.type == n_Zn or _ring.cf.type == n_Znm: lift = d.lift() @@ -1577,7 +1590,7 @@ cdef object si2sa(number *n, ring *_ring, object base): An element of ``base`` """ - if isinstance(base, FiniteField_prime_modn): + if isinstance(base, FiniteField_prime_modn) and _ring.cf.type == n_Zp: return base(_ring.cf.cfInt(n, _ring.cf)) elif isinstance(base, RationalField): @@ -1605,8 +1618,6 @@ cdef object si2sa(number *n, ring *_ring, object base): return si2sa_transext_FF(n, _ring, base) elif isinstance(base, IntegerModRing_generic): - if _ring.cf.type == n_unknown: - return base(_ring.cf.cfInt(n, _ring.cf)) return si2sa_ZZmod(n, _ring, base) else: @@ -1628,7 +1639,8 @@ cdef number *sa2si(Element elem, ring * _ring) noexcept: a (pointer to) a singular number """ cdef int i = 0 - if isinstance(elem._parent, FiniteField_prime_modn): + + if isinstance(elem._parent, FiniteField_prime_modn) and _ring.cf.type == n_Zp: return n_Init(int(elem),_ring.cf) elif isinstance(elem._parent, RationalField): @@ -1649,8 +1661,6 @@ cdef number *sa2si(Element elem, ring * _ring) noexcept: elif isinstance(elem._parent, NumberField) and elem._parent.is_absolute(): return sa2si_NF(elem, _ring) elif isinstance(elem._parent, IntegerModRing_generic): - if _ring.cf.type == n_unknown: - return n_Init(int(elem),_ring.cf) return sa2si_ZZmod(elem, _ring) elif isinstance(elem._parent, FractionField_generic) and isinstance(elem._parent.base(), (MPolynomialRing_libsingular, PolynomialRing_field)): if isinstance(elem._parent.base().base_ring(), RationalField): @@ -1806,9 +1816,99 @@ saved_PATH = os.environ["PATH"] init_libsingular() os.environ["PATH"] = saved_PATH +cdef bint catching_error = False + cdef void libsingular_error_callback(const_char_ptr s) noexcept: _s = char_to_str(s) - error_messages.append(_s) + if catching_error: + error_messages.append(_s) + else: + warn(f"error in Singular ignored: {_s}") + +cdef int start_catch_error() except -1: + """ + Helper function to convert Singular errors to Python exceptions. + + Must be used as follows:: + + start_catch_error() + ... + s = check_error() # nonempty tuple[str, ...] (error messages) or None + if s: + # at this point global variable ``error_messages`` is cleared + raise RuntimeError(...) + + Return value is ignored, only used for exception handling. + + Note that :func:`check_error` can only be called exactly once. + + Note that this *must not* be used in conjunction with :func:`sig_on` as follows:: + + start_catch_error() + sig_on() + ... + sig_off() + if check_error(): + raise RuntimeError(...) + + because if the code is interrupted, then :func:`check_error` is never called. + + Use the following instead:: + + start_catch_error() + try: + sig_on() + ... # long time + sig_off() + finally: + if check_error(): + raise RuntimeError(...) + + If the code inside (marked `# long time`) can also raise a Python exception, + the above is still wrong --- :func:`sig_off` may not be called. In this case + use a nested ``try`` as suggested in ``cysignals`` documentation:: + + start_catch_error() + try: + sig_on() # This must be OUTSIDE the inner try + try: + ... # long time + finally: + sig_off() + finally: + if check_error(): + raise RuntimeError(...) + """ + global errorreported, catching_error, error_messages + if catching_error: + warn("internal error: previous start_catch_error not ended with check_error") + catching_error = True + + if errorreported: + warn(f"error in Singular ignored: {', '.join(error_messages)}") + errorreported = False + error_messages.clear() + else: + assert not error_messages + return 0 + +cdef object check_error(): + """ + See :func:`start_catch_error`. + """ + global errorreported, catching_error, error_messages + if not catching_error: + warn("internal error: check_error not preceded with start_catch_error") + catching_error = False + + if errorreported: + result = tuple(error_messages) + assert result + errorreported = False + error_messages.clear() + return result + assert not error_messages + return None def get_resource(id): diff --git a/src/sage/libs/singular/standard_options.py b/src/sage/libs/singular/standard_options.py index 476961b2f09..cdd81edf74c 100644 --- a/src/sage/libs/singular/standard_options.py +++ b/src/sage/libs/singular/standard_options.py @@ -6,6 +6,7 @@ - Martin Albrecht """ + class LibSingularGBDefaultContext: def __init__(self): """ @@ -95,7 +96,8 @@ def __exit__(self, typ, value, tb): b - 3*d^6 + 2*d^4 + d^3 + 2*d^2 - 3*d, a - 2*d^6 + d^5 - 2*d^4 + 3*d^3 + 3*d^2 - 2*d - 1] """ - self.libsingular_option_context.__exit__(typ,value,tb) + self.libsingular_option_context.__exit__(typ, value, tb) + def libsingular_gb_standard_options(func): r""" diff --git a/src/sage/libs/symmetrica/symmetrica.pxi b/src/sage/libs/symmetrica/symmetrica.pxi index def9544e2c6..d175de28c38 100644 --- a/src/sage/libs/symmetrica/symmetrica.pxi +++ b/src/sage/libs/symmetrica/symmetrica.pxi @@ -436,7 +436,7 @@ cdef void late_import() noexcept: prod = sage.misc.all.prod import sage.rings.polynomial.polynomial_ring_constructor - PolynomialRing = sage.rings.polynomial.polynomial_ring_constructor.PolynomialRing + PolynomialRing = sage.rings.polynomial.polynomial_ring_constructor.PolynomialRing import sage.rings.all QQ = sage.rings.all.QQ diff --git a/src/sage/manifolds/all.py b/src/sage/manifolds/all.py index e219a98dc32..425199da31a 100644 --- a/src/sage/manifolds/all.py +++ b/src/sage/manifolds/all.py @@ -1,4 +1,5 @@ from sage.misc.lazy_import import lazy_import + lazy_import('sage.manifolds.manifold', 'Manifold') lazy_import('sage.manifolds.differentiable.examples.euclidean', 'EuclideanSpace') lazy_import('sage.manifolds', 'catalog', 'manifolds') diff --git a/src/sage/manifolds/calculus_method.py b/src/sage/manifolds/calculus_method.py index a4888559c0f..abbc5c8bc5f 100644 --- a/src/sage/manifolds/calculus_method.py +++ b/src/sage/manifolds/calculus_method.py @@ -19,13 +19,15 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # ***************************************************************************** +from sage.manifolds.utilities import ( + simplify_chain_generic, + simplify_chain_generic_sympy, + simplify_chain_real, + simplify_chain_real_sympy, +) +from sage.misc.latex import latex from sage.structure.sage_object import SageObject from sage.symbolic.ring import SR -from sage.manifolds.utilities import (simplify_chain_real, - simplify_chain_generic, - simplify_chain_real_sympy, - simplify_chain_generic_sympy,) -from sage.misc.latex import latex try: import sympy @@ -170,6 +172,7 @@ class CalculusMethod(SageObject): associated with each calculus method and :meth:`set_simplify_function` for introducing a new simplification algorithm. """ + _default = 'SR' # default calculus method _methods = ('SR', 'sympy') # implemented methods _tranf = {'SR': _Sympy_to_SR, 'sympy': _SR_to_Sympy} # translators @@ -335,8 +338,7 @@ def set(self, method): NotImplementedError: method lala not implemented """ if method not in self._methods: - raise NotImplementedError("method {} not ".format(method) + - "implemented") + raise NotImplementedError("method {} not ".format(method) + "implemented") self._current = method def current(self): diff --git a/src/sage/manifolds/catalog.py b/src/sage/manifolds/catalog.py index c3c40c42b9a..bbd05367960 100644 --- a/src/sage/manifolds/catalog.py +++ b/src/sage/manifolds/catalog.py @@ -34,6 +34,7 @@ # Lazy import from examples folders: from sage.misc.lazy_import import lazy_import as _lazy_import + _lazy_import('sage.manifolds.differentiable.examples.real_line', 'OpenInterval') _lazy_import('sage.manifolds.differentiable.examples.real_line', 'RealLine') _lazy_import('sage.manifolds.differentiable.examples.euclidean', 'EuclideanSpace') @@ -81,6 +82,7 @@ def Minkowski(positive_spacelike=True, names=None): [ 0 0 0 -1] """ from sage.manifolds.manifold import Manifold + M = Manifold(4, 'M', structure='Lorentzian') if names is None: names = ("t", "x", "y", "z") @@ -89,8 +91,8 @@ def Minkowski(positive_spacelike=True, names=None): g = M.metric('g') sgn = 1 if positive_spacelike else -1 - g[0,0] = -sgn - g[1,1], g[2,2], g[3,3] = sgn, sgn, sgn + g[0, 0] = -sgn + g[1, 1], g[2, 2], g[3, 3] = sgn, sgn, sgn return M @@ -172,51 +174,74 @@ def Kerr(m=1, a=0, coordinates='BL', names=None): sage: K.default_chart().coord_range() t: (-oo, +oo); r: (0, +oo); th: (0, pi); ph: [-pi, pi] (periodic) """ - from sage.misc.functional import sqrt from sage.functions.trig import cos, sin from sage.manifolds.manifold import Manifold + from sage.misc.functional import sqrt + M = Manifold(4, 'M', structure='Lorentzian') if coordinates == "Kerr": if names is None: - names = (r't:(-oo,+oo)', r'r:(0,+oo)', r'th:(0,pi):\theta', - r'ph:(-pi,pi):periodic:\phi') + names = ( + r't:(-oo,+oo)', + r'r:(0,+oo)', + r'th:(0,pi):\theta', + r'ph:(-pi,pi):periodic:\phi', + ) else: - names = (names[0]+r':(-oo,+oo)', names[1]+r':(0,+oo)', - names[2]+r':(0,pi):\theta', - names[3]+r':(-pi,pi):periodic:\phi') + names = ( + names[0] + r':(-oo,+oo)', + names[1] + r':(0,+oo)', + names[2] + r':(0,pi):\theta', + names[3] + r':(-pi,pi):periodic:\phi', + ) C = M.chart(names=names) M._first_ngens = C._first_ngens g = M.metric('g') t, r, th, ph = C[:] - rho = sqrt(r**2+a**2*cos(th)**2) - g[0, 0], g[1, 1], g[2, 2], g[3, 3] = -(1-2*m*r/rho**2), 1+2*m*r/rho**2,\ - rho**2, (r**2+a**2+2*a**2*m*r*sin(th)**2/rho**2)*sin(th)**2 - g[0, 1] = 2*m*r/rho**2 - g[0, 3] = -2*a*m*r/rho**2*sin(th)**2 - g[1, 3] = -a*sin(th)**2*(1+2*m*r/rho**2) + rho = sqrt(r**2 + a**2 * cos(th)**2) + g[0, 0], g[1, 1], g[2, 2], g[3, 3] = ( + -(1 - 2 * m * r / rho**2), + 1 + 2 * m * r / rho**2, + rho**2, + (r**2 + a**2 + 2 * a**2 * m * r * sin(th)**2 / rho**2) * sin(th)**2, + ) + g[0, 1] = 2 * m * r / rho**2 + g[0, 3] = -2 * a * m * r / rho**2 * sin(th)**2 + g[1, 3] = -a * sin(th)**2 * (1 + 2 * m * r / rho**2) return M if coordinates == "BL": if names is None: - names = (r't:(-oo,+oo)', r'r:(0,+oo)', r'th:(0,pi):\theta', - r'ph:(-pi,pi):periodic:\phi') + names = ( + r't:(-oo,+oo)', + r'r:(0,+oo)', + r'th:(0,pi):\theta', + r'ph:(-pi,pi):periodic:\phi', + ) else: - names = (names[0]+r':(-oo,+oo)', names[1]+r':(0,+oo)', - names[2]+r':(0,pi):\theta', - names[3]+r':(-pi,pi):periodic:\phi') + names = ( + names[0] + r':(-oo,+oo)', + names[1] + r':(0,+oo)', + names[2] + r':(0,pi):\theta', + names[3] + r':(-pi,pi):periodic:\phi', + ) C = M.chart(names=names) M._first_ngens = C._first_ngens g = M.metric('g') t, r, th, ph = C[:] - rho = sqrt(r**2+a**2*cos(th)**2) - g[0, 0], g[1, 1], g[2, 2], g[3, 3] = -(1-2*m*r/rho**2), \ - rho**2/(r**2-2*m*r+a**2), rho**2, \ - (r**2+a**2+2*m*r*a**2/rho**2*sin(th)**2)*sin(th)**2 - g[0, 3] = -2*m*r*a*sin(th)**2/rho**2 + rho = sqrt(r**2 + a**2 * cos(th)**2) + g[0, 0], g[1, 1], g[2, 2], g[3, 3] = ( + -(1 - 2 * m * r / rho**2), + rho**2 / (r**2 - 2 * m * r + a**2), + rho**2, + (r**2 + a**2 + 2 * m * r * a**2 / rho**2 * sin(th)**2) * sin(th)**2, + ) + g[0, 3] = -2 * m * r * a * sin(th)**2 / rho**2 return M - raise NotImplementedError("coordinates system not implemented, see help" - " for details") + raise NotImplementedError( + "coordinates system not implemented, see help for details" + ) def Torus(R=2, r=1, names=None): @@ -252,8 +277,9 @@ def Torus(R=2, r=1, names=None): gamma = dtheta⊗dtheta + (cos(theta)^2 + 6*cos(theta) + 9) dphi⊗dphi """ from sage.functions.trig import cos, sin - from sage.manifolds.manifold import Manifold from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace + from sage.manifolds.manifold import Manifold + E = EuclideanSpace(3, symbols='X Y Z') M = Manifold(2, 'T', ambient=E, structure='Riemannian') if names is None: @@ -262,7 +288,7 @@ def Torus(R=2, r=1, names=None): C = M.chart(names=names) M._first_ngens = C._first_ngens th, ph = C[:] - coordfunc = [(R+r*cos(th))*cos(ph), (R+r*cos(th))*sin(ph), r*sin(th)] + coordfunc = [(R + r * cos(th)) * cos(ph), (R + r * cos(th)) * sin(ph), r * sin(th)] imm = M.diff_map(E, coordfunc) M.set_embedding(imm) M.induced_metric() @@ -356,9 +382,12 @@ def RealProjectiveSpace(dim=2): from sage.manifolds.manifold import Manifold - P = Manifold(dim, f"RP{dim}", - structure='topological', - latex_name=r"\mathbb{{RP}}^{{{}}}".format(dim)) + P = Manifold( + dim, + f"RP{dim}", + structure='topological', + latex_name=r"\mathbb{{RP}}^{{{}}}".format(dim), + ) # the trailing whitespace in the string is intentional for defining charts names = [f'x_{i} ' for i in range(dim + 1)] @@ -372,13 +401,12 @@ def RealProjectiveSpace(dim=2): U = P.open_subset(name=f'U{j}', latex_name=f'U_{j}') # The chart where we assert that x_i == 1 - Cj = U.chart(''.join(names[:j] + names[j+1:])) + Cj = U.chart(''.join(names[:j] + names[j + 1 :])) gj = Cj[:] charts[j] = Cj for i in range(j): - Ci = charts[i] gi = Ci[:] @@ -386,15 +414,19 @@ def RealProjectiveSpace(dim=2): xj = gi[j - 1] # use index j - 1 because i < j and xi is omitted in gi # the corresponding coordinates in R^{dim+1} - d_plus_one_coords = [g/xj for g in gi[:i]] + [1/xj] + [g/xj for g in gi[i:]] - cj_new_coords = d_plus_one_coords[:j] + d_plus_one_coords[j+1:] - - Ci_to_Cj = Ci.transition_map(Cj, cj_new_coords, - restrictions1=xj != 0, - restrictions2=xi != 0) - - d_plus_one_coords = [g/xi for g in gj[:j]] + [1/xi] + [g/xi for g in gj[j:]] - ci_new_coords = d_plus_one_coords[:i] + d_plus_one_coords[i+1:] + d_plus_one_coords = ( + [g / xj for g in gi[:i]] + [1 / xj] + [g / xj for g in gi[i:]] + ) + cj_new_coords = d_plus_one_coords[:j] + d_plus_one_coords[j + 1 :] + + Ci_to_Cj = Ci.transition_map( + Cj, cj_new_coords, restrictions1=xj != 0, restrictions2=xi != 0 + ) + + d_plus_one_coords = ( + [g / xi for g in gj[:j]] + [1 / xi] + [g / xi for g in gj[j:]] + ) + ci_new_coords = d_plus_one_coords[:i] + d_plus_one_coords[i + 1 :] Cj_to_Ci = Ci_to_Cj.set_inverse(*ci_new_coords, check=False) diff --git a/src/sage/manifolds/chart.py b/src/sage/manifolds/chart.py index d0d3148be7e..c9bc4c802f1 100644 --- a/src/sage/manifolds/chart.py +++ b/src/sage/manifolds/chart.py @@ -36,16 +36,16 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.ext.fast_callable import fast_callable +from sage.manifolds.calculus_method import CalculusMethod +from sage.manifolds.chart_func import ChartFunctionRing +from sage.misc.decorators import options +from sage.misc.latex import latex +from sage.rings.infinity import Infinity from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation -from sage.symbolic.ring import SR -from sage.rings.infinity import Infinity -from sage.misc.latex import latex -from sage.misc.decorators import options -from sage.manifolds.chart_func import ChartFunctionRing -from sage.manifolds.calculus_method import CalculusMethod from sage.symbolic.expression import Expression -from sage.ext.fast_callable import fast_callable +from sage.symbolic.ring import SR class Chart(UniqueRepresentation, SageObject): @@ -287,9 +287,15 @@ class Chart(UniqueRepresentation, SageObject): """ @staticmethod - def __classcall__(cls, domain, coordinates='', - calc_method=None, names=None, - coord_restrictions=None, **coordinate_options): + def __classcall__( + cls, + domain, + coordinates='', + calc_method=None, + names=None, + coord_restrictions=None, + **coordinate_options, + ): r""" Normalize init args and implement unique representation behavior. @@ -307,8 +313,7 @@ def __classcall__(cls, domain, coordinates='', for x in names: coordinates += x + ' ' coordinates = coordinates[:-1] - coordinates, parsed_options = cls._parse_coordinates(domain, - coordinates) + coordinates, parsed_options = cls._parse_coordinates(domain, coordinates) if not coordinate_options: coordinate_options = parsed_options @@ -318,16 +323,28 @@ def __classcall__(cls, domain, coordinates='', return domain._charts_by_coord[coord_string] except KeyError: # Make coord_restrictions hashable - coord_restrictions = cls._normalize_coord_restrictions(coordinates, - coord_restrictions) - self = super().__classcall__(cls, domain, coordinates, calc_method, - coord_restrictions=coord_restrictions, - **coordinate_options) + coord_restrictions = cls._normalize_coord_restrictions( + coordinates, coord_restrictions + ) + self = super().__classcall__( + cls, + domain, + coordinates, + calc_method, + coord_restrictions=coord_restrictions, + **coordinate_options, + ) domain._charts_by_coord[coord_string] = self return self - def __init__(self, domain, coordinates, calc_method=None, periods=None, - coord_restrictions=None): + def __init__( + self, + domain, + coordinates, + calc_method=None, + periods=None, + coord_restrictions=None, + ): r""" Construct a chart. @@ -354,23 +371,29 @@ def __init__(self, domain, coordinates, calc_method=None, periods=None, [Chart (U, (x, y)), Chart (V, (x, y))] """ from sage.manifolds.manifold import TopologicalManifold + if not isinstance(domain, TopologicalManifold): - raise TypeError("the first argument must be an open subset of " + - "a topological manifold") + raise TypeError( + "the first argument must be an open subset of " + + "a topological manifold" + ) self._manifold = domain.manifold() self._domain = domain self._sindex = self._manifold.start_index() # Handling of calculus methods available on this chart: - self._calc_method = CalculusMethod(current=calc_method, - base_field_type=self.manifold().base_field_type()) + self._calc_method = CalculusMethod( + current=calc_method, base_field_type=self.manifold().base_field_type() + ) self.simplify = self._calc_method.simplify # Treatment of the coordinates: self._periods = periods if len(coordinates) != self._manifold.dim(): - raise ValueError("the list of coordinates must contain " + - "{} elements".format(self._manifold.dim())) + raise ValueError( + "the list of coordinates must contain " + + "{} elements".format(self._manifold.dim()) + ) self._xx = coordinates # # Additional restrictions on the coordinates. @@ -383,8 +406,7 @@ def __init__(self, domain, coordinates, calc_method=None, periods=None, # the chart is added in the top charts iff its coordinates have # not been used on a domain including the chart's domain: for chart in sd._atlas: - if (domain.is_subset(chart._domain) - and self._xx == chart._xx): + if domain.is_subset(chart._domain) and self._xx == chart._xx: break else: sd._top_charts.append(self) @@ -400,9 +422,10 @@ def __init__(self, domain, coordinates, calc_method=None, periods=None, # restriction of: self._supercharts = set([self]) - self._dom_restrict = {} # dict. of the restrictions of self to - # subsets of self._domain, with the - # subsets as keys + # dict. of the restrictions of self to + # subsets of self._domain, with the + # subsets as keys + self._dom_restrict = {} # The null and one functions of the coordinates: # Expression in self of the zero and one scalar fields of open sets # containing the domain of self: @@ -445,13 +468,13 @@ def _parse_coordinates(cls, domain, coordinates): coord_list = coordinates.split() else: coord_list = coordinates - xx_list = [] # will contain the coordinates as Sage symbolic variables + xx_list = [] # will contain the coordinates as Sage symbolic variables period_list = [] for coord_index, coord_field in enumerate(coord_list): coord_properties = coord_field.split(':') - coord_symb = coord_properties[0].strip() # the coordinate symbol - coord_latex = None # possibly redefined below - period = None # possibly redefined below + coord_symb = coord_properties[0].strip() # the coordinate symbol + coord_latex = None # possibly redefined below + period = None # possibly redefined below # scan of the properties other than the symbol: for prop in coord_properties[1:]: prop1 = prop.strip() @@ -489,6 +512,7 @@ def _normalize_coord_restrictions(coordinates, coord_restrictions): sage: Chart._normalize_coord_restrictions(coordinates, [x > y, (x != 0, y != 0), z^2 < x]) frozenset({(x != 0, y != 0), x > y, z^2 < x}) """ + def normalize(r): if isinstance(r, tuple): # or return tuple(normalize(x) for x in r) @@ -500,8 +524,9 @@ def normalize(r): if coord_restrictions is None: return frozenset() - if callable(coord_restrictions) and not isinstance(coord_restrictions, - Expression): + if callable(coord_restrictions) and not isinstance( + coord_restrictions, Expression + ): # lambda-quoted coord_restrictions = coord_restrictions(*coordinates) @@ -542,9 +567,9 @@ def _latex_(self): """ description = r'\left(' + latex(self.domain()).strip() + ',(' n = len(self._xx) - for i in range(n-1): + for i in range(n - 1): description += latex(self._xx[i]).strip() + ', ' - description += latex(self._xx[n-1]).strip() + r')\right)' + description += latex(self._xx[n - 1]).strip() + r')\right)' return description def _first_ngens(self, n): @@ -608,8 +633,8 @@ def __getitem__(self, i): start -= self._sindex if stop is not None: stop -= self._sindex - return self._xx[start:stop:i.step] - return self._xx[i-self._sindex] + return self._xx[start : stop : i.step] + return self._xx[i - self._sindex] def __call__(self, point): r""" @@ -752,8 +777,14 @@ def add_restrictions(self, restrictions): False """ from sage.misc.superseded import deprecation - deprecation(32102, "Chart.add_restrictions is deprecated; provide the restrictions at the time of creating the chart") - self._restrictions.extend(self._normalize_coord_restrictions(self._xx, restrictions)) + + deprecation( + 32102, + "Chart.add_restrictions is deprecated; provide the restrictions at the time of creating the chart", + ) + self._restrictions.extend( + self._normalize_coord_restrictions(self._xx, restrictions) + ) def restrict(self, subset, restrictions=None): r""" @@ -807,20 +838,26 @@ def restrict(self, subset, restrictions=None): return self if subset not in self._dom_restrict: if not subset.is_subset(self.domain()): - raise ValueError("the specified subset is not a subset " + - "of the domain of definition of the chart") + raise ValueError( + "the specified subset is not a subset " + + "of the domain of definition of the chart" + ) coordinates = "" for coord in self._xx: coordinates += repr(coord) + ' ' res_coord_restrictions = set(self._restrictions) - res_coord_restrictions.update(self._normalize_coord_restrictions(self._xx, - restrictions)) - res = type(self)(subset, coordinates, - calc_method=self._calc_method._current, - periods=self._periods, - # The coordinate restrictions are added - # to the result chart - coord_restrictions=res_coord_restrictions) + res_coord_restrictions.update( + self._normalize_coord_restrictions(self._xx, restrictions) + ) + res = type(self)( + subset, + coordinates, + calc_method=self._calc_method._current, + periods=self._periods, + # The coordinate restrictions are added + # to the result chart + coord_restrictions=res_coord_restrictions, + ) # Update of supercharts and subcharts: res._supercharts.update(self._supercharts) for schart in self._supercharts: @@ -926,12 +963,14 @@ def _check_restrictions(self, restrict, substitutions): sage: X._check_restrictions([(x0], {x: 2, y: 1}) False """ - if isinstance(restrict, tuple): # case of 'or' conditions - return any(self._check_restrictions(cond, substitutions) - for cond in restrict) - elif isinstance(restrict, (list, set, frozenset)): # case of 'and' conditions - return all(self._check_restrictions(cond, substitutions) - for cond in restrict) + if isinstance(restrict, tuple): # case of 'or' conditions + return any( + self._check_restrictions(cond, substitutions) for cond in restrict + ) + elif isinstance(restrict, (list, set, frozenset)): # case of 'and' conditions + return all( + self._check_restrictions(cond, substitutions) for cond in restrict + ) # Case of a single condition: return bool(restrict.subs(substitutions)) @@ -947,6 +986,7 @@ def codomain(self): Vector space of dimension 2 over Complex Field with 53 bits of precision """ from sage.modules.free_module import VectorSpace + ambient = VectorSpace(self.manifold().base_field(), self.manifold().dimension()) if self._restrictions: return self._restrict_set(ambient, self._restrictions) @@ -977,24 +1017,35 @@ def _restrict_set(self, universe, coord_restrictions): { (x, y) ∈ Vector space of dimension 2 over Real Field with 53 bits of precision : y < 0 } and { (x, y) ∈ Vector space of dimension 2 over Real Field with 53 bits of precision : x > 0 } """ - if isinstance(coord_restrictions, tuple): # case of 'or' conditions + if isinstance(coord_restrictions, tuple): # case of 'or' conditions A = self._restrict_set(universe, coord_restrictions[0]) if len(coord_restrictions) == 1: return A else: return A.union(self._restrict_set(universe, coord_restrictions[1:])) - elif isinstance(coord_restrictions, (list, set, frozenset)): # case of 'and' conditions + elif isinstance( + coord_restrictions, (list, set, frozenset) + ): # case of 'and' conditions A = self._restrict_set(universe, coord_restrictions[0]) if len(coord_restrictions) == 1: return A else: - return A.intersection(self._restrict_set(universe, coord_restrictions[1:])) + return A.intersection( + self._restrict_set(universe, coord_restrictions[1:]) + ) # Case of a single condition: from sage.sets.condition_set import ConditionSet + return ConditionSet(universe, coord_restrictions, vars=self._xx) - def transition_map(self, other, transformations, intersection_name=None, - restrictions1=None, restrictions2=None): + def transition_map( + self, + other, + transformations, + intersection_name=None, + restrictions1=None, + restrictions2=None, + ): r""" Construct the transition map between the current chart, `(U, \varphi)` say, and another one, `(V, \psi)` say. @@ -1112,7 +1163,7 @@ def transition_map(self, other, transformations, intersection_name=None, else: chart2 = other.restrict(dom, restrictions2) if not isinstance(transformations, (tuple, list)): - transformations = [transformations] + transformations = [transformations] return CoordChange(chart1, chart2, *transformations) def preimage(self, codomain_subset, name=None, latex_name=None): @@ -1216,9 +1267,11 @@ def preimage(self, codomain_subset, name=None, latex_name=None): sage: R((-2,)) in McZ True """ - from .subsets.pullback import ManifoldSubsetPullback - return ManifoldSubsetPullback(self, codomain_subset, - name=name, latex_name=latex_name) + from sage.manifolds.subsets.pullback import ManifoldSubsetPullback + + return ManifoldSubsetPullback( + self, codomain_subset, name=name, latex_name=latex_name + ) pullback = preimage @@ -1236,8 +1289,7 @@ def function_ring(self): return ChartFunctionRing(self) - def function(self, expression, calc_method=None, expansion_symbol=None, - order=None): + def function(self, expression, calc_method=None, expansion_symbol=None, order=None): r""" Define a coordinate function to the base field. @@ -1318,9 +1370,13 @@ def function(self, expression, calc_method=None, expansion_symbol=None, See :class:`~sage.manifolds.chart_func.ChartFunction` for more examples. """ parent = self.function_ring() - return parent.element_class(parent, expression, calc_method=calc_method, - expansion_symbol=expansion_symbol, - order=order) + return parent.element_class( + parent, + expression, + calc_method=calc_method, + expansion_symbol=expansion_symbol, + order=order, + ) def zero_function(self): r""" @@ -1547,11 +1603,13 @@ def multifunction(self, *expressions): """ from sage.manifolds.chart_func import MultiCoordFunction + return MultiCoordFunction(self, expressions) # ***************************************************************************** + class RealChart(Chart): r""" Chart on a topological manifold over `\RR`. @@ -1831,8 +1889,16 @@ class RealChart(Chart): Chart grids can be drawn in 2D or 3D graphics thanks to the method :meth:`plot`. """ - def __init__(self, domain, coordinates, calc_method=None, bounds=None, - periods=None, coord_restrictions=None): + + def __init__( + self, + domain, + coordinates, + calc_method=None, + bounds=None, + periods=None, + coord_restrictions=None, + ): r""" Construct a chart on a real topological manifold. @@ -1849,8 +1915,13 @@ def __init__(self, domain, coordinates, calc_method=None, bounds=None, [x is real, y is real] sage: TestSuite(X).run() """ - super().__init__(domain, coordinates, calc_method=calc_method, - periods=periods, coord_restrictions=coord_restrictions) + super().__init__( + domain, + coordinates, + calc_method=calc_method, + periods=periods, + coord_restrictions=coord_restrictions, + ) self._bounds = bounds self._tighten_bounds() self._fast_valid_coordinates = None @@ -1896,16 +1967,17 @@ def _parse_coordinates(cls, domain, coordinates): 'periods': (None, None)}) """ from sage.symbolic.assumptions import assume + if isinstance(coordinates, str): coord_list = coordinates.split() else: coord_list = coordinates - xx_list = [] # will contain the coordinates as Sage symbolic variables - bounds_list = [] # will contain the coordinate bounds + xx_list = [] # will contain the coordinates as Sage symbolic variables + bounds_list = [] # will contain the coordinate bounds period_list = [] for coord_index, coord_field in enumerate(coord_list): coord_properties = coord_field.split(':') - coord_symb = coord_properties[0].strip() # the coordinate symbol + coord_symb = coord_properties[0].strip() # the coordinate symbol # default values, possibly redefined below: coord_latex = None xmin = -Infinity @@ -1920,16 +1992,30 @@ def _parse_coordinates(cls, domain, coordinates): delim_min = prop1[0] if delim_min in ['[', ']', '(']: # prop1 is the coordinate's range - xmin_str, xmax_str = prop1[1:len(prop1)-1].split(',') - if xmin_str not in ['-inf', '-Inf', '-infinity', - '-Infinity', '-oo']: + xmin_str, xmax_str = prop1[1 : len(prop1) - 1].split(',') + if xmin_str not in [ + '-inf', + '-Inf', + '-infinity', + '-Infinity', + '-oo', + ]: xmin = SR(xmin_str) - xmin_included = ( delim_min == '[' ) - if xmax_str not in ['inf', '+inf', 'Inf', '+Inf', - 'infinity', '+infinity', 'Infinity', - '+Infinity', 'oo', '+oo']: + xmin_included = delim_min == '[' + if xmax_str not in [ + 'inf', + '+inf', + 'Inf', + '+Inf', + 'infinity', + '+infinity', + 'Infinity', + '+Infinity', + 'oo', + '+oo', + ]: xmax = SR(xmax_str) - xmax_included = ( prop1[-1] == ']' ) + xmax_included = prop1[-1] == ']' elif prop1[0:6] == 'period': # prop1 indicates a periodic coordinate is_periodic = True @@ -1941,8 +2027,7 @@ def _parse_coordinates(cls, domain, coordinates): # prop1 is the coordinate's LaTeX symbol coord_latex = prop1 # Construction of the coordinate as a Sage symbolic variable: - coord_var = SR.var(coord_symb, domain='real', - latex_name=coord_latex) + coord_var = SR.var(coord_symb, domain='real', latex_name=coord_latex) assume(coord_var, 'real') if is_periodic: period = xmax - xmin @@ -1962,8 +2047,9 @@ def _parse_coordinates(cls, domain, coordinates): xx_list.append(coord_var) bounds_list.append(((xmin, xmin_included), (xmax, xmax_included))) period_list.append(period) - return tuple(xx_list), dict(bounds=tuple(bounds_list), - periods=tuple(period_list)) + return tuple(xx_list), dict( + bounds=tuple(bounds_list), periods=tuple(period_list) + ) def coord_bounds(self, i=None): r""" @@ -2025,7 +2111,7 @@ def coord_bounds(self, i=None): if i is None: return self._bounds else: - return self._bounds[i-self._sindex] + return self._bounds[i - self._sindex] def codomain(self): r""" @@ -2053,16 +2139,23 @@ def codomain(self): sage: c_spher1.codomain() The Cartesian product of ((0, +oo), (0, pi), [0, 2*pi)) """ - from sage.sets.real_set import RealSet - from sage.modules.free_module import VectorSpace from sage.categories.cartesian_product import cartesian_product - intervals = tuple(RealSet.interval(xmin, xmax, - lower_closed=(min_included == 'periodic' or min_included), - upper_closed=(max_included != 'periodic' and max_included)) - for ((xmin, min_included), (xmax, max_included)) in self._bounds) - if all(interval.is_universe() - for interval in intervals): - ambient = VectorSpace(self.manifold().base_field(), self.manifold().dimension()) + from sage.modules.free_module import VectorSpace + from sage.sets.real_set import RealSet + + intervals = tuple( + RealSet.interval( + xmin, + xmax, + lower_closed=(min_included == 'periodic' or min_included), + upper_closed=(max_included != 'periodic' and max_included), + ) + for ((xmin, min_included), (xmax, max_included)) in self._bounds + ) + if all(interval.is_universe() for interval in intervals): + ambient = VectorSpace( + self.manifold().base_field(), self.manifold().dimension() + ) else: ambient = cartesian_product(intervals) if self._restrictions: @@ -2150,11 +2243,11 @@ def _display_coord_range(self, xx, rtxt, rlatex): if resu_txt != "": resu_txt += "; " resu_latex += r";\quad " - resu_txt, resu_latex = _display_coord_range(self, x, resu_txt, - resu_latex) + resu_txt, resu_latex = _display_coord_range( + self, x, resu_txt, resu_latex + ) else: - resu_txt, resu_latex = _display_coord_range(self, xx, resu_txt, - resu_latex) + resu_txt, resu_latex = _display_coord_range(self, xx, resu_txt, resu_latex) return FormattedExpansion(resu_txt, resu_latex) def add_restrictions(self, restrictions): @@ -2239,13 +2332,16 @@ def _tighten_bounds(self): x: (-oo, 0); y: (1/2, +oo) """ import operator - bounds = list(self._bounds) # convert to a list for modifications + + bounds = list(self._bounds) # convert to a list for modifications new_restrictions = [] for restrict in self._restrictions: - restrict_used = False # determines whether restrict is used - # to set some coordinate bound - if not isinstance(restrict, (tuple, list, set, frozenset)): # case of combined - # conditions excluded + restrict_used = False # determines whether restrict is used to set some coordinate bound + if not isinstance( + restrict, (tuple, list, set, frozenset) + ): + # case of combined + # conditions excluded operands = restrict.operands() left = operands[0] right = operands[1] @@ -2253,15 +2349,14 @@ def _tighten_bounds(self): if left in self._xx: # the l.h.s. of the restriction is a single # coordinate - right_coord = [coord for coord in self._xx - if coord in right_var] + right_coord = [coord for coord in self._xx if coord in right_var] if not right_coord: # there is no other coordinate in the r.h.s. ind = self._xx.index(left) left_bounds = list(bounds[ind]) oper = restrict.operator() - oinf = left_bounds[0][0] # old coord inf - osup = left_bounds[1][0] # old coord sup + oinf = left_bounds[0][0] # old coord inf + osup = left_bounds[1][0] # old coord sup if oper == operator.lt: if osup == Infinity or right <= osup: left_bounds[1] = (right, False) @@ -2367,21 +2462,28 @@ def restrict(self, subset, restrictions=None): return self if subset not in self._dom_restrict: if not subset.is_subset(self.domain()): - raise ValueError("the specified subset is not a subset " + - "of the domain of definition of the chart") + raise ValueError( + "the specified subset is not a subset " + + "of the domain of definition of the chart" + ) coordinates = "" for coord in self._xx: coordinates += repr(coord) + ' ' res_coord_restrictions = set(self._restrictions) - res_coord_restrictions.update(self._normalize_coord_restrictions(self._xx, - restrictions)) - res = type(self)(subset, coordinates, - calc_method=self._calc_method._current, - bounds=self._bounds, periods=self._periods, - # The coordinate restrictions are added - # to the result chart and possibly - # transformed into coordinate bounds: - coord_restrictions=res_coord_restrictions) + res_coord_restrictions.update( + self._normalize_coord_restrictions(self._xx, restrictions) + ) + res = type(self)( + subset, + coordinates, + calc_method=self._calc_method._current, + bounds=self._bounds, + periods=self._periods, + # The coordinate restrictions are added + # to the result chart and possibly + # transformed into coordinate bounds: + coord_restrictions=res_coord_restrictions, + ) # Update of supercharts and subcharts: res._supercharts.update(self._supercharts) for schart in self._supercharts: @@ -2554,7 +2656,7 @@ def valid_coordinates_numerical(self, *coordinates): return self._fast_valid_coordinates(*coordinates) # case fast callable has to be computed - from operator import lt, gt + from operator import gt, lt if not isinstance(self._restrictions, (list, set, frozenset)): if isinstance(self._restrictions, tuple): @@ -2617,11 +2719,26 @@ def evaluate_fast_callable(*coordinates): self._fast_valid_coordinates = evaluate_fast_callable return self._fast_valid_coordinates(*coordinates) - @options(max_range=8, color='red', style='-', thickness=1, plot_points=75, - label_axes=True) - def plot(self, chart=None, ambient_coords=None, mapping=None, - fixed_coords=None, ranges=None, number_values=None, - steps=None, parameters=None, **kwds): + @options( + max_range=8, + color='red', + style='-', + thickness=1, + plot_points=75, + label_axes=True, + ) + def plot( + self, + chart=None, + ambient_coords=None, + mapping=None, + fixed_coords=None, + ranges=None, + number_values=None, + steps=None, + parameters=None, + **kwds, + ): r""" Plot ``self`` as a grid in a Cartesian graph based on the coordinates of some ambient chart. @@ -3003,11 +3120,11 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, sage: X.plot.reset() """ + from sage.manifolds.continuous_map import ContinuousMap + from sage.manifolds.utilities import set_axes_labels from sage.misc.functional import numerical_approx from sage.plot.graphics import Graphics from sage.plot.line import line - from sage.manifolds.continuous_map import ContinuousMap - from sage.manifolds.utilities import set_axes_labels # Extract the kwds options max_range = kwds['max_range'] @@ -3036,8 +3153,7 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): return resu else: rem_coords.remove(coord) - return _plot_xx_list(resu, rem_coords, ranges, steps, - number_values) + return _plot_xx_list(resu, rem_coords, ranges, steps, number_values) if chart is None: chart = self @@ -3059,12 +3175,14 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): if coord not in ambient_coords: fixed_coords[coord] = 0 else: - transf = None # to be the MultiCoordFunction object relating self - # to the ambient chart + transf = None # to be the MultiCoordFunction object relating self + # to the ambient chart if mapping is None: if not self.domain().is_subset(chart.domain()): - raise ValueError("the domain of {} is not ".format(self) + - "included in that of {}".format(chart)) + raise ValueError( + "the domain of {} is not ".format(self) + + "included in that of {}".format(chart) + ) coord_changes = chart.domain()._coord_changes for chart_pair in coord_changes: if chart_pair == (self, chart): @@ -3078,22 +3196,28 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): transf = coord_changes[chart_pair]._transf else: if not isinstance(mapping, ContinuousMap): - raise TypeError("the argument 'mapping' must be a " - "continuous manifold map") + raise TypeError( + "the argument 'mapping' must be a continuous manifold map" + ) if not self.domain().is_subset(mapping.domain()): - raise ValueError("the domain of {} is not ".format(self) + - "included in that of {}".format(mapping)) + raise ValueError( + "the domain of {} is not ".format(self) + + "included in that of {}".format(mapping) + ) if not chart.domain().is_subset(mapping._codomain): - raise ValueError("the domain of {} is not ".format(chart) + - "included in the codomain of {}".format( - mapping)) + raise ValueError( + "the domain of {} is not ".format(chart) + + "included in the codomain of {}".format(mapping) + ) try: transf = mapping.coord_functions(chart1=self, chart2=chart) except ValueError: pass if transf is None: - raise ValueError("no relation has been found between " + - "{} and {}".format(self, chart)) + raise ValueError( + "no relation has been found between " + + "{} and {}".format(self, chart) + ) # # 2/ Treatment of input parameters # ----------------------------- @@ -3118,8 +3242,10 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): ranges0 = {} for coord in coords: if coord in ranges: - ranges0[coord] = (numerical_approx(ranges[coord][0]), - numerical_approx(ranges[coord][1])) + ranges0[coord] = ( + numerical_approx(ranges[coord][0]), + numerical_approx(ranges[coord][1]), + ) else: bounds = self._bounds[self._xx.index(coord)] if bounds[0][0] == -Infinity: @@ -3127,19 +3253,19 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): elif bounds[0][1]: xmin = numerical_approx(bounds[0][0]) else: - xmin = numerical_approx(bounds[0][0] + 1.e-3) + xmin = numerical_approx(bounds[0][0] + 1.0e-3) if bounds[1][0] == Infinity: xmax = numerical_approx(max_range) elif bounds[1][1]: xmax = numerical_approx(bounds[1][0]) else: - xmax = numerical_approx(bounds[1][0] - 1.e-3) + xmax = numerical_approx(bounds[1][0] - 1.0e-3) ranges0[coord] = (xmin, xmax) ranges = ranges0 if number_values is None: - if nca == 2: # 2D plot + if nca == 2: # 2D plot number_values = 9 - else: # 3D plot + else: # 3D plot number_values = 5 if not isinstance(number_values, dict): number_values0 = {} @@ -3150,12 +3276,15 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): steps = {} for coord in coords: if coord not in steps: - steps[coord] = ((ranges[coord][1] - ranges[coord][0]) - / (number_values[coord]-1)) + steps[coord] = (ranges[coord][1] - ranges[coord][0]) / ( + number_values[coord] - 1 + ) else: from sage.functions.other import floor - number_values[coord] = 1 + floor((ranges[coord][1] - ranges[coord][0]) - / steps[coord]) + + number_values[coord] = 1 + floor( + (ranges[coord][1] - ranges[coord][0]) / steps[coord] + ) if not isinstance(color, dict): color0 = {} for coord in coords: @@ -3194,15 +3323,16 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): rem_coords.remove(coord) xx_list = [xx0] if len(rem_coords) >= 1: - xx_list = _plot_xx_list(xx_list, rem_coords, ranges, steps, - number_values) + xx_list = _plot_xx_list( + xx_list, rem_coords, ranges, steps, number_values + ) xmin, xmax = ranges[coord] nbp = plot_points[coord] - dx = (xmax - xmin) / (nbp-1) + dx = (xmax - xmin) / (nbp - 1) ind_coord = self._xx.index(coord) for xx in xx_list: curve = [] - first_invalid = False # initialization + first_invalid = False # initialization xc = xmin xp = list(xx) if parameters is None: @@ -3210,48 +3340,58 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): xp[ind_coord] = xc if self.valid_coordinates(*xp, tolerance=1e-13): yp = transf(*xp, simplify=False) - curve.append( [numerical_approx(yp[j]) - for j in ind_a] ) - first_invalid = True # next invalid point will be - # the first one + curve.append([numerical_approx(yp[j]) for j in ind_a]) + first_invalid = True # next invalid point will be + # the first one else: if first_invalid: # the curve is stopped at previous point and # added to the graph: - resu += line(curve, color=color_c, - linestyle=style_c, - thickness=thickness_c) - curve = [] # a new curve will start at the - # next valid point - first_invalid = False # next invalid point will not - # be the first one + resu += line( + curve, + color=color_c, + linestyle=style_c, + thickness=thickness_c, + ) + curve = [] # a new curve will start at the + # next valid point + first_invalid = False # next invalid point will not + # be the first one xc += dx else: for i in range(nbp): xp[ind_coord] = xc - if self.valid_coordinates(*xp, tolerance=1e-13, - parameters=parameters): + if self.valid_coordinates( + *xp, tolerance=1e-13, parameters=parameters + ): yp = transf(*xp, simplify=False) - curve.append([numerical_approx(yp[j].substitute(parameters)) - for j in ind_a]) - first_invalid = True # next invalid point will be - # the first one + curve.append( + [ + numerical_approx(yp[j].substitute(parameters)) + for j in ind_a + ] + ) + first_invalid = True # next invalid point will be + # the first one else: if first_invalid: # the curve is stopped at previous point and # added to the graph: - resu += line(curve, color=color_c, - linestyle=style_c, - thickness=thickness_c) - curve = [] # a new curve will start at the - # next valid point - first_invalid = False # next invalid point will not - # be the first one + resu += line( + curve, + color=color_c, + linestyle=style_c, + thickness=thickness_c, + ) + curve = [] # a new curve will start at the + # next valid point + first_invalid = False # next invalid point will not + # be the first one xc += dx if curve: - resu += line(curve, color=color_c, - linestyle=style_c, - thickness=thickness_c) + resu += line( + curve, color=color_c, linestyle=style_c, thickness=thickness_c + ) if nca == 2: # 2D graphic resu.set_aspect_ratio(1) if label_axes: @@ -3259,15 +3399,17 @@ def _plot_xx_list(xx_list, rem_coords, ranges, steps, number_values): # to show()), instead of using the method # Graphics.axes_labels() since the latter is not robust w.r.t. # graph addition - resu._extra_kwds['axes_labels'] = [r'$'+latex(ac)+r'$' - for ac in ambient_coords] - else: # 3D graphic + resu._extra_kwds['axes_labels'] = [ + r'$' + latex(ac) + r'$' for ac in ambient_coords + ] + else: # 3D graphic resu.aspect_ratio(1) if label_axes: labels = [str(ac) for ac in ambient_coords] resu = set_axes_labels(resu, *labels) return resu + # ***************************************************************************** @@ -3313,6 +3455,7 @@ class CoordChange(SageObject): u = x + y v = x - y """ + def __init__(self, chart1, chart2, *transformations): r""" Construct a transition map. @@ -3332,8 +3475,9 @@ def __init__(self, chart1, chart2, *transformations): self._n1 = len(chart1._xx) self._n2 = len(chart2._xx) if len(transformations) != self._n2: - raise ValueError("{} coordinate transformations ".format(self._n2) - + "must be provided") + raise ValueError( + "{} coordinate transformations ".format(self._n2) + "must be provided" + ) self._chart1 = chart1 self._chart2 = chart2 # The coordinate transformations are implemented via the class @@ -3364,8 +3508,7 @@ def _repr_(self): sage: X_to_Y # indirect doctest Change of coordinates from Chart (M, (x, y)) to Chart (M, (u, v)) """ - return "Change of coordinates from {} to {}".format(self._chart1, - self._chart2) + return "Change of coordinates from {} to {}".format(self._chart1, self._chart2) def _latex_(self): r""" @@ -3411,9 +3554,11 @@ def __eq__(self, other): return True if not isinstance(other, CoordChange): return False - return ((self._chart1 == other._chart1) - and (self._chart2 == other._chart2) - and (self._transf == other._transf)) + return ( + (self._chart1 == other._chart1) + and (self._chart2 == other._chart2) + and (self._transf == other._transf) + ) def __ne__(self, other): r""" @@ -3502,6 +3647,7 @@ def inverse(self): True """ from sage.symbolic.relation import solve + if self._inverse is not None: return self._inverse # The computation is necessary: @@ -3510,9 +3656,11 @@ def inverse(self): n1 = self._n1 n2 = self._n2 if n1 != n2: - raise ValueError("the change of coordinates is not invertible " + - "(different number of coordinates in the two " + - "charts)") + raise ValueError( + "the change of coordinates is not invertible " + + "(different number of coordinates in the two " + + "charts)" + ) # New symbolic variables (different from x2 to allow for a # correct solution even when chart2 = chart1): base_field = self._chart1.domain().base_field_type() @@ -3525,19 +3673,20 @@ def inverse(self): for i in range(n2): if x2[i].is_positive(): coord_domain[i] = 'positive' - xp2 = [ SR.temp_var(domain=coord_domain[i]) for i in range(n2) ] + xp2 = [SR.temp_var(domain=coord_domain[i]) for i in range(n2)] xx2 = self._transf.expr() equations = [xp2[i] == xx2[i] for i in range(n2)] try: solutions = solve(equations, *x1, solution_dict=True) except RuntimeError: - raise RuntimeError("the system could not be solved; use " + - "set_inverse() to set the inverse manually") + raise RuntimeError( + "the system could not be solved; use " + + "set_inverse() to set the inverse manually" + ) substitutions = dict(zip(xp2, x2)) if len(solutions) == 1: - x2_to_x1 = [solutions[0][x1[i]].subs(substitutions) - for i in range(n1)] - x2_to_x1_simpl = [] # to store simplified transformations + x2_to_x1 = [solutions[0][x1[i]].subs(substitutions) for i in range(n1)] + x2_to_x1_simpl = [] # to store simplified transformations for transf in x2_to_x1: try: transf = self._chart2.simplify(transf) @@ -3549,14 +3698,16 @@ def inverse(self): list_x2_to_x1 = [] for sol in solutions: if x2[0] in sol: - raise ValueError("the system could not be solved; use " + - "set_inverse() to set the inverse " + - "manually") + raise ValueError( + "the system could not be solved; use " + + "set_inverse() to set the inverse " + + "manually" + ) try: x2_to_x1 = [sol[x1[i]].subs(substitutions) for i in range(n1)] - except KeyError: # sol is not a valid solution + except KeyError: # sol is not a valid solution continue - x2_to_x1_simpl = [] # to store simplified transformations + x2_to_x1_simpl = [] # to store simplified transformations for transf in x2_to_x1: try: transf = self._chart2.simplify(transf) @@ -3567,15 +3718,18 @@ def inverse(self): if self._chart1.valid_coordinates(*x2_to_x1): list_x2_to_x1.append(x2_to_x1) if len(list_x2_to_x1) == 0: - raise ValueError("no solution found; use set_inverse() to " + - "set the inverse manually") + raise ValueError( + "no solution found; use set_inverse() to " + + "set the inverse manually" + ) if len(list_x2_to_x1) > 1: print("Multiple solutions found: ") print(list_x2_to_x1) raise ValueError( - "non-unique solution to the inverse coordinate " + - "transformation; use set_inverse() to set the inverse " + - "manually") + "non-unique solution to the inverse coordinate " + + "transformation; use set_inverse() to set the inverse " + + "manually" + ) x2_to_x1 = list_x2_to_x1[0] self._inverse = type(self)(self._chart2, self._chart1, *x2_to_x1) self._inverse._inverse = self @@ -3693,10 +3847,8 @@ def set_inverse(self, *transformations, **kwds): check = kwds.pop('check', True) verbose = kwds.pop('verbose', False) for unknown_key in kwds: - raise TypeError("{} is not a valid keyword " - "argument".format(unknown_key)) - self._inverse = type(self)(self._chart2, self._chart1, - *transformations) + raise TypeError("{} is not a valid keyword argument".format(unknown_key)) + self._inverse = type(self)(self._chart2, self._chart1, *transformations) self._inverse._inverse = self if check: infos = ["Check of the inverse coordinate transformation:"] @@ -3722,8 +3874,9 @@ def set_inverse(self, *transformations, **kwds): any_failure = True infos.append(" {} {}".format(eq, resu)) if any_failure: - infos.append("NB: a failed report can reflect a mere lack of " - "simplification.") + infos.append( + "NB: a failed report can reflect a mere lack of simplification." + ) if verbose or any_failure: for li in infos: print(li) @@ -3759,9 +3912,10 @@ def __mul__(self, other): if not isinstance(other, CoordChange): raise TypeError("{} is not a change of coordinate".format(other)) if other._chart2 != self._chart1: - raise ValueError("composition not possible: " + - "{} is different from {}".format(other._chart2, - other._chart1)) + raise ValueError( + "composition not possible: " + + "{} is different from {}".format(other._chart2, other._chart1) + ) transf = self._transf(*(other._transf.expr())) return type(self)(other._chart1, self._chart2, *transf) @@ -3804,8 +3958,11 @@ def restrict(self, dom1, dom2=None): ch2 = self._chart2.restrict(dom2) if (ch1, ch2) in dom1.coord_changes(): return dom1.coord_changes()[(ch1, ch2)] - return type(self)(self._chart1.restrict(dom1), - self._chart2.restrict(dom2), *(self._transf.expr())) + return type(self)( + self._chart1.restrict(dom1), + self._chart2.restrict(dom2), + *(self._transf.expr()), + ) def display(self): r""" @@ -3838,6 +3995,7 @@ def display(self): """ from sage.misc.latex import latex from sage.tensor.modules.format_utilities import FormattedExpansion + coords2 = self._chart2[:] n2 = len(coords2) expr = self._transf.expr('SR') diff --git a/src/sage/manifolds/chart_func.py b/src/sage/manifolds/chart_func.py index aae7a2b1fff..8e9ac906059 100644 --- a/src/sage/manifolds/chart_func.py +++ b/src/sage/manifolds/chart_func.py @@ -23,6 +23,7 @@ - Florentin Jaffredo (2018) : series expansion with respect to a given parameter """ + # **************************************************************************** # Copyright (C) 2017 Marco Mancini # Copyright (C) 2018 Florentin Jaffredo @@ -32,16 +33,16 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.structure.element import AlgebraElement, ModuleElementWithMutability -from sage.structure.parent import Parent -from sage.structure.sage_object import SageObject -from sage.structure.unique_representation import UniqueRepresentation from sage.categories.commutative_algebras import CommutativeAlgebras from sage.manifolds.utilities import ExpressionNice from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import -from sage.symbolic.ring import SR +from sage.structure.element import AlgebraElement, ModuleElementWithMutability from sage.structure.mutability import Mutability +from sage.structure.parent import Parent +from sage.structure.sage_object import SageObject +from sage.structure.unique_representation import UniqueRepresentation +from sage.symbolic.ring import SR try: import sympy @@ -327,8 +328,14 @@ class ChartFunction(AlgebraElement, ModuleElementWithMutability): .. automethod:: __call__ """ - def __init__(self, parent, expression=None, calc_method=None, - expansion_symbol=None, order=None): + def __init__( + self, + parent, + expression=None, + calc_method=None, + expansion_symbol=None, + order=None, + ): r""" Initialize ``self``. @@ -370,10 +377,11 @@ def __init__(self, parent, expression=None, calc_method=None, if calc_method is None: calc_method = self._calc_method._current self._express[calc_method] = self._calc_method._tranf[calc_method]( - expression) + expression + ) # Derived quantities: self._der = None # list of partial derivatives (to be set by diff() - # and unset by del_derived()) + # and unset by del_derived()) self._expansion_symbol = expansion_symbol self._order = order @@ -399,9 +407,8 @@ def _simplify(self, expr): 2*x """ res = self._calc_method.simplify(expr) - if (self._expansion_symbol is not None and - self._calc_method._current == 'SR'): - res = res.series(self._expansion_symbol, self._order+1).truncate() + if self._expansion_symbol is not None and self._calc_method._current == 'SR': + res = res.series(self._expansion_symbol, self._order + 1).truncate() return res def chart(self): @@ -454,9 +461,9 @@ def scalar_field(self, name=None, latex_name=None): True """ alg = self._chart.domain().scalar_field_algebra() - return alg.element_class(alg, - coord_expression={self._chart: self}, - name=name, latex_name=latex_name) + return alg.element_class( + alg, coord_expression={self._chart: self}, name=name, latex_name=latex_name + ) def expr(self, method=None): r""" @@ -553,8 +560,7 @@ def expr(self, method=None): return self._express[method] except (KeyError, ValueError): pass - raise ValueError("no expression found for converting to {}".format( - method)) + raise ValueError("no expression found for converting to {}".format(method)) def set_expr(self, calc_method, expression): r""" @@ -588,11 +594,14 @@ def set_expr(self, calc_method, expression): ValueError: Expressions are not equal """ if self.is_immutable(): - raise ValueError("the expressions of an immutable element cannot " - "be changed") + raise ValueError( + "the expressions of an immutable element cannot be changed" + ) for vv in self._express.values(): - if not bool(self._calc_method._tranf[calc_method](expression) == - self._calc_method._tranf[calc_method](vv)): + if not bool( + self._calc_method._tranf[calc_method](expression) + == self._calc_method._tranf[calc_method](vv) + ): raise ValueError("Expressions are not equal") self._express[calc_method] = expression @@ -613,8 +622,7 @@ def _repr_(self): x*y + 1 """ curr = self._calc_method._current - if (curr == 'SR' and - self._chart.manifold().options.textbook_output): + if curr == 'SR' and self._chart.manifold().options.textbook_output: return str(ExpressionNice(self.expr(curr))) else: return str(self.expr(curr)) @@ -634,8 +642,7 @@ def _latex_(self): \cos\left(\frac{1}{2} \, x y\right) """ curr = self._calc_method._current - if (curr == 'SR' and - self._chart.manifold().options.textbook_output): + if curr == 'SR' and self._chart.manifold().options.textbook_output: out_expr = ExpressionNice(self._express[curr]) else: out_expr = self._express[curr] @@ -671,17 +678,16 @@ def display(self): sage: X.zero_function().display() (x, y) ↦ 0 """ - from sage.typeset.unicode_characters import unicode_mapsto from sage.tensor.modules.format_utilities import FormattedExpansion + from sage.typeset.unicode_characters import unicode_mapsto + curr = self._calc_method._current expr = self.expr(curr) - if (curr == 'SR' and - self._chart.manifold().options.textbook_output): + if curr == 'SR' and self._chart.manifold().options.textbook_output: expr = ExpressionNice(expr) latex_func = self._calc_method._latex_dict[curr] resu_txt = str(self._chart[:]) + ' ' + unicode_mapsto + ' ' + str(expr) - resu_latex = latex_func(self._chart[:]) + r' \mapsto ' \ - + latex_func(expr) + resu_latex = latex_func(self._chart[:]) + r' \mapsto ' + latex_func(expr) return FormattedExpansion(resu_txt, resu_latex) disp = display @@ -1026,20 +1032,28 @@ def derivative(self, coord): """ from sage.calculus.functional import diff from sage.rings.integer import Integer + if self._der is None: # the list of partial derivatives has to be updated curr = self._calc_method._current if curr == 'SR': - self._der = [type(self)(self.parent(), - self._simplify(diff(self.expr(), xx)), - expansion_symbol=self._expansion_symbol, - order=self._order) - for xx in self._chart[:]] + self._der = [ + type(self)( + self.parent(), + self._simplify(diff(self.expr(), xx)), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) + for xx in self._chart[:] + ] elif curr == 'sympy': - self._der = [type(self)(self.parent(), - self._simplify(sympy.diff(self.expr(), - xx._sympy_()))) - for xx in self._chart[:]] + self._der = [ + type(self)( + self.parent(), + self._simplify(sympy.diff(self.expr(), xx._sympy_())), + ) + for xx in self._chart[:] + ] if isinstance(coord, (int, Integer)): # NB: for efficiency, we access directly to the "private" attributes # of other classes. A more conventional OOP writing would be @@ -1106,8 +1120,9 @@ def __eq__(self, other): method = list(self._express)[0] # pick a random method # other.expr(method) if method == 'sympy': - return bool(sympy.simplify(other.expr(method) - - self.expr(method)) == 0) + return bool( + sympy.simplify(other.expr(method) - self.expr(method)) == 0 + ) return bool(other.expr(method) == self.expr(method)) else: return bool(self.expr(self._calc_method._current) == other) @@ -1161,7 +1176,7 @@ def __neg__(self): """ curr = self._calc_method._current resu = type(self)(self.parent()) - resu._express[curr] = self._simplify(- self.expr()) + resu._express[curr] = self._simplify(-self.expr()) resu._order = self._order resu._expansion_symbol = self._expansion_symbol return resu @@ -1209,16 +1224,21 @@ def __invert__(self): """ curr = self._calc_method._current if curr == 'SR': - return type(self)(self.parent(), - calc_method='SR', - expression=self._simplify(SR.one() / self.expr())) + return type(self)( + self.parent(), + calc_method='SR', + expression=self._simplify(SR.one() / self.expr()), + ) # NB: self._express.__invert__() would return 1/self._express # (cf. the code of __invert__ in src/sage/symbolic/expression.pyx) # Here we prefer SR(1)/self._express - return type(self)(self.parent(), - calc_method=curr, - expression=self._simplify(1 / self.expr()), - expansion_symbol=self._expansion_symbol, order=self._order) + return type(self)( + self.parent(), + calc_method=curr, + expression=self._simplify(1 / self.expr()), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def _add_(self, other): r""" @@ -1286,13 +1306,19 @@ def _add_(self, other): # NB: "if res == 0" would be too expensive (cf. #22859) return self.parent().zero() if other._expansion_symbol is not None: - return type(self)(self.parent(), res, - expansion_symbol=other._expansion_symbol, - order=other._order) + return type(self)( + self.parent(), + res, + expansion_symbol=other._expansion_symbol, + order=other._order, + ) else: - return type(self)(self.parent(), res, - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + res, + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def _sub_(self, other): r""" @@ -1351,13 +1377,19 @@ def _sub_(self, other): # NB: "if res == 0" would be too expensive (cf. #22859) return self.parent().zero() if other._expansion_symbol is not None: - return type(self)(self.parent(), res, - expansion_symbol=other._expansion_symbol, - order=other._order) + return type(self)( + self.parent(), + res, + expansion_symbol=other._expansion_symbol, + order=other._order, + ) else: - return type(self)(self.parent(), res, - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + res, + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def _mul_(self, other): r""" @@ -1412,13 +1444,19 @@ def _mul_(self, other): # NB: "if res == 0" would be too expensive (cf. #22859) return self.parent().zero() if other._expansion_symbol is not None: - return type(self)(self.parent(), res, - expansion_symbol=other._expansion_symbol, - order=other._order) + return type(self)( + self.parent(), + res, + expansion_symbol=other._expansion_symbol, + order=other._order, + ) else: - return type(self)(self.parent(), res, - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + res, + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def _rmul_(self, other): """ @@ -1451,9 +1489,12 @@ def _rmul_(self, other): other = self._calc_method._tranf[curr](other) except (TypeError, ValueError): return - return type(self)(self.parent(), other * self.expr(), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + other * self.expr(), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def _lmul_(self, other): """ @@ -1486,9 +1527,12 @@ def _lmul_(self, other): other = self._calc_method._tranf[curr](other) except (TypeError, ValueError): return - return type(self)(self.parent(), self.expr() * other, - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self.expr() * other, + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def _div_(self, other): r""" @@ -1547,9 +1591,12 @@ def _div_(self, other): if curr == 'SR' and res.is_trivial_zero(): # NB: "if res == 0" would be too expensive (cf. #22859) return self.parent().zero() - return type(self)(self.parent(), res, - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + res, + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def exp(self): r""" @@ -1592,9 +1639,12 @@ def exp(self): val = self.expr().exp() elif curr == 'sympy': val = sympy.exp(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def log(self, base=None): r""" @@ -1645,10 +1695,15 @@ def log(self, base=None): if curr == 'SR': val = self.expr().log(base) elif curr == 'sympy': - val = sympy.log(self.expr()) if base is None else sympy.log(self.expr(), base) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + val = ( + sympy.log(self.expr()) if base is None else sympy.log(self.expr(), base) + ) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def __pow__(self, exponent): r""" @@ -1703,9 +1758,12 @@ def __pow__(self, exponent): val = pow(self.expr(), exponent) elif curr == 'sympy': val = self.expr() ** exponent - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def sqrt(self): r""" @@ -1735,9 +1793,12 @@ def sqrt(self): val = self.expr().sqrt() elif curr == 'sympy': val = sympy.sqrt(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def cos(self): r""" @@ -1775,9 +1836,12 @@ def cos(self): val = self.expr().cos() elif curr == 'sympy': val = sympy.cos(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def sin(self): r""" @@ -1820,9 +1884,12 @@ def sin(self): val = self.expr().sin() elif curr == 'sympy': val = sympy.sin(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def tan(self): r""" @@ -1863,9 +1930,12 @@ def tan(self): val = self.expr().tan() elif curr == 'sympy': val = sympy.tan(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def arccos(self): r""" @@ -1910,9 +1980,12 @@ def arccos(self): val = self.expr().arccos() elif curr == 'sympy': val = sympy.acos(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def arcsin(self): r""" @@ -1954,9 +2027,12 @@ def arcsin(self): val = self.expr().arcsin() elif curr == 'sympy': val = sympy.asin(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def arctan(self): r""" @@ -1998,9 +2074,12 @@ def arctan(self): val = self.expr().arctan() elif curr == 'sympy': val = sympy.atan(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def cosh(self): r""" @@ -2038,9 +2117,12 @@ def cosh(self): val = self.expr().cosh() elif curr == 'sympy': val = sympy.cosh(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def sinh(self): r""" @@ -2078,9 +2160,12 @@ def sinh(self): val = self.expr().sinh() elif curr == 'sympy': val = sympy.sinh(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def tanh(self): r""" @@ -2118,9 +2203,12 @@ def tanh(self): val = self.expr().tanh() elif curr == 'sympy': val = sympy.tanh(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def arccosh(self): r""" @@ -2162,9 +2250,12 @@ def arccosh(self): val = self.expr().arccosh() elif curr == 'sympy': val = sympy.acosh(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def arcsinh(self): r""" @@ -2206,9 +2297,12 @@ def arcsinh(self): val = self.expr().arcsinh() elif curr == 'sympy': val = sympy.asinh(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def arctanh(self): r""" @@ -2250,9 +2344,12 @@ def arctanh(self): val = self.expr().arctanh() elif curr == 'sympy': val = sympy.atanh(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def __abs__(self): r""" @@ -2290,9 +2387,12 @@ def __abs__(self): val = self.expr().abs() elif curr == 'sympy': val = abs(self.expr()) - return type(self)(self.parent(), self._simplify(val), - expansion_symbol=self._expansion_symbol, - order=self._order) + return type(self)( + self.parent(), + self._simplify(val), + expansion_symbol=self._expansion_symbol, + order=self._order, + ) def _del_derived(self): r""" @@ -2652,6 +2752,7 @@ class ChartFunctionRing(Parent, UniqueRepresentation): sage: FR_Y.has_coerce_map_from(FR_X) False """ + Element = ChartFunction def __init__(self, chart): @@ -2895,6 +2996,7 @@ class MultiCoordFunction(SageObject, Mutability): sage: g(1,2) (4,) """ + def __init__(self, chart, expressions): r""" Initialize ``self``. @@ -2910,10 +3012,9 @@ def __init__(self, chart, expressions): sage: TestSuite(f).run() """ self._chart = chart - self._nc = len(self._chart._xx) # number of coordinates - self._nf = len(expressions) # number of functions - self._functions = tuple(chart.function(express) - for express in expressions) + self._nc = len(self._chart._xx) # number of coordinates + self._nf = len(expressions) # number of functions + self._functions = tuple(chart.function(express) for express in expressions) Mutability.__init__(self) def _repr_(self): @@ -2930,8 +3031,7 @@ def _repr_(self): sage: f Coordinate functions (x - y, x*y, cos(x)*e^y) on the Chart (M, (x, y)) """ - return "Coordinate functions {} on the {}".format(self._functions, - self._chart) + return "Coordinate functions {} on the {}".format(self._functions, self._chart) def _latex_(self): r""" @@ -2948,6 +3048,7 @@ def _latex_(self): \left(x - y, x y, \cos\left(x\right) e^{y}\right) """ from sage.misc.latex import latex + return latex(self._functions) def expr(self, method=None): @@ -3048,8 +3149,7 @@ def __eq__(self, other): return False if other._nf != self._nf: return False - return all(other._functions[i] == self._functions[i] - for i in range(self._nf)) + return all(other._functions[i] == self._functions[i] for i in range(self._nf)) def __ne__(self, other): r""" @@ -3191,8 +3291,10 @@ def jacobian(self): [[True, True], [True, True], [True, True]] """ from sage.matrix.constructor import matrix - mat = matrix([[func.diff(coord) for coord in self._chart[:]] - for func in self._functions]) + + mat = matrix( + [[func.diff(coord) for coord in self._chart[:]] for func in self._functions] + ) mat.set_immutable() return mat @@ -3262,16 +3364,24 @@ def jacobian_det(self): True """ from sage.matrix.constructor import matrix + if self._nf != self._nc: raise ValueError("the Jacobian matrix is not a square matrix") mat = self.jacobian() # TODO: do the computation without the 'SR' enforcement - mat_expr = matrix([[mat[i,j].expr(method='SR') for i in range(self._nc)] - for j in range(self._nc)]) + mat_expr = matrix( + [ + [mat[i, j].expr(method='SR') for i in range(self._nc)] + for j in range(self._nc) + ] + ) det = mat_expr.det() # the unsimplified determinant func = self._functions[0] - return type(func)(func.parent(), func._calc_method.simplify(det, method='SR'), - calc_method=self._chart._calc_method._current) + return type(func)( + func.parent(), + func._calc_method.simplify(det, method='SR'), + calc_method=self._chart._calc_method._current, + ) def set_immutable(self): r""" diff --git a/src/sage/manifolds/continuous_map.py b/src/sage/manifolds/continuous_map.py index 2c30b796aab..49a88430a3d 100644 --- a/src/sage/manifolds/continuous_map.py +++ b/src/sage/manifolds/continuous_map.py @@ -343,8 +343,16 @@ class ContinuousMap(Morphism): sage: ~id is id True """ - def __init__(self, parent, coord_functions=None, name=None, latex_name=None, - is_isomorphism=False, is_identity=False): + + def __init__( + self, + parent, + coord_functions=None, + name=None, + latex_name=None, + is_isomorphism=False, + is_identity=False, + ): r""" Initialize ``self``. @@ -376,10 +384,11 @@ def __init__(self, parent, coord_functions=None, name=None, latex_name=None, codomain = parent.codomain() self._domain = domain self._codomain = codomain - self._coord_expression = {} # dict. of coordinate expressions of the - # map: - # - key: pair of charts - # - value: instance of MultiCoordFunction + # dict. of coordinate expressions of the + # map: + # - key: pair of charts + # - value: instance of MultiCoordFunction + self._coord_expression = {} self._is_isomorphism = False # default value; may be redefined below self._is_identity = False # default value; may be redefined below if is_identity: @@ -387,8 +396,9 @@ def __init__(self, parent, coord_functions=None, name=None, latex_name=None, self._is_identity = True self._is_isomorphism = True if domain != codomain: - raise ValueError("the domain and codomain must coincide" - " for the identity map") + raise ValueError( + "the domain and codomain must coincide for the identity map" + ) if name is None: name = 'Id_' + domain._name if latex_name is None: @@ -398,35 +408,42 @@ def __init__(self, parent, coord_functions=None, name=None, latex_name=None, for chart in domain.atlas(): coord_funct = chart[:] self._coord_expression[(chart, chart)] = chart.multifunction( - *coord_funct) + *coord_funct + ) else: # Construction of a generic continuous map if is_isomorphism: self._is_isomorphism = True if domain.dim() != codomain.dim(): - raise ValueError("for an isomorphism, the source" - " manifold and target manifold must" - " have the same dimension") + raise ValueError( + "for an isomorphism, the source" + " manifold and target manifold must" + " have the same dimension" + ) if coord_functions is not None: n2 = self._codomain.dim() for chart_pair, expression in coord_functions.items(): if chart_pair[0] not in self._domain.atlas(): - raise ValueError("{} is not a chart ".format( - chart_pair[0]) + - "defined on the {}".format(self._domain)) + raise ValueError( + "{} is not a chart ".format(chart_pair[0]) + + "defined on the {}".format(self._domain) + ) if chart_pair[1] not in self._codomain.atlas(): - raise ValueError("{} is not a chart ".format( - chart_pair[1]) + - "defined on the {}".format(self._codomain)) + raise ValueError( + "{} is not a chart ".format(chart_pair[1]) + + "defined on the {}".format(self._codomain) + ) if n2 == 1: # a single expression entry is allowed if not isinstance(expression, (tuple, list)): expression = (expression,) if len(expression) != n2: - raise ValueError("{} coordinate ".format(n2) + - "functions must be provided") - self._coord_expression[chart_pair] = \ - chart_pair[0].multifunction(*expression) + raise ValueError( + "{} coordinate ".format(n2) + "functions must be provided" + ) + self._coord_expression[chart_pair] = chart_pair[0].multifunction( + *expression + ) self._name = name if latex_name is None: self._latex_name = self._name @@ -481,8 +498,7 @@ def _repr_(self): else: description += " from the {} to itself".format(self._domain) else: - description += " from the {} to the {}".format(self._domain, - self._codomain) + description += " from the {} to the {}".format(self._domain, self._codomain) return description def _latex_(self): @@ -675,8 +691,10 @@ def _call_(self, point): if chart1 is not None: break else: - raise ValueError("no pair of charts has been found to " + - "compute the action of the {} on the {}".format(self, point)) + raise ValueError( + "no pair of charts has been found to " + + "compute the action of the {} on the {}".format(self, point) + ) coord_map = self._coord_expression[(chart1, chart2)] y = coord_map(*(point._coordinates[chart1])) if point._name is None or self._name is None: @@ -686,13 +704,20 @@ def _call_(self, point): if point._latex_name is None or self._latex_name is None: res_latex_name = None else: - res_latex_name = (self._latex_name + r'\left(' + - point._latex_name + r'\right)') + res_latex_name = ( + self._latex_name + r'\left(' + point._latex_name + r'\right)' + ) # The image point is created as an element of the domain of chart2: dom2 = chart2.domain() - return dom2.element_class(dom2, coords=y, chart=chart2, - name=res_name, latex_name=res_latex_name, - check_coords=False) + return dom2.element_class( + dom2, + coords=y, + chart=chart2, + name=res_name, + latex_name=res_latex_name, + check_coords=False, + ) + # # Morphism methods # @@ -799,8 +824,9 @@ def _composition_(self, other, homset): for chart3 in self._codomain._top_charts: try: self23 = self.coord_functions(chart2, chart3) - resu_funct[(chart1, chart3)] = self23(*other.expr(chart1, chart2), - simplify=True) + resu_funct[(chart1, chart3)] = self23( + *other.expr(chart1, chart2), simplify=True + ) except ValueError: pass return homset(resu_funct) @@ -843,7 +869,8 @@ def image(self, subset=None, inverse=None): sage: Phi_S.is_subset(M) True """ - from .continuous_map_image import ImageManifoldSubset + from sage.manifolds.continuous_map_image import ImageManifoldSubset + if self._is_identity: if subset is None: return self.domain() @@ -917,8 +944,10 @@ def preimage(self, codomain_subset, name=None, latex_name=None): if self._codomain.is_subset(codomain_subset): return self._domain from sage.manifolds.subsets.pullback import ManifoldSubsetPullback - return ManifoldSubsetPullback(self, codomain_subset, - name=name, latex_name=latex_name) + + return ManifoldSubsetPullback( + self, codomain_subset, name=name, latex_name=latex_name + ) pullback = preimage @@ -1002,8 +1031,8 @@ def _init_derived(self): [ 1 0] [ 0 1/2] """ - self._restrictions = {} # dict. of restrictions to subdomains of - # self._domain + # dict. of restrictions to subdomains of self._domain + self._restrictions = {} self._restrictions_graph = {(self._domain, self._codomain): self} # dict. of known extensions of self on bigger domains, # including self, with pairs of domain codomain as keys. @@ -1166,8 +1195,8 @@ def display(self, chart1=None, chart2=None): \end{array} """ from sage.misc.latex import latex - from sage.typeset.unicode_characters import unicode_to, unicode_mapsto from sage.tensor.modules.format_utilities import FormattedExpansion + from sage.typeset.unicode_characters import unicode_mapsto, unicode_to def _display_expression(self, chart1, chart2, result): r""" @@ -1194,33 +1223,43 @@ def _display_expression(self, chart1, chart2, result): result._latex += ' & ' else: result._txt += 'on ' + chart1._domain._name + ': ' - result._latex += r'\text{on}\ ' + latex(chart1._domain) + \ - r': & ' + result._latex += r'\text{on}\ ' + latex(chart1._domain) + r': & ' result._txt += repr(coords1) + ' ' + unicode_mapsto + ' ' result._latex += latex(coords1) + r'& \longmapsto & ' if chart2 == chart1: result._txt += repr(expression) + '\n' result._latex += latex(coord_func) + r'\\' else: - result._txt += repr(coords2) + ' = ' + \ - repr(expression) + '\n' - result._latex += latex(coords2) + ' = ' + \ - latex(coord_func) + r'\\' + result._txt += repr(coords2) + ' = ' + repr(expression) + '\n' + result._latex += latex(coords2) + ' = ' + latex(coord_func) + r'\\' result = FormattedExpansion() if self._name is None: symbol = '' else: symbol = self._name + ': ' - result._txt = symbol + self._domain._name + ' ' + unicode_to + ' ' \ - + self._codomain._name + '\n' + result._txt = ( + symbol + + self._domain._name + + ' ' + + unicode_to + + ' ' + + self._codomain._name + + '\n' + ) if self._latex_name is None: symbol = '' else: symbol = self._latex_name + ':' - result._latex = r'\begin{array}{llcl} ' + symbol + r'&' + \ - latex(self._domain) + r'& \longrightarrow & ' + \ - latex(self._codomain) + r'\\' + result._latex = ( + r'\begin{array}{llcl} ' + + symbol + + r'&' + + latex(self._domain) + + r'& \longrightarrow & ' + + latex(self._codomain) + + r'\\' + ) if chart1 is None: if chart2 is None: for ch1 in self._domain._top_charts: @@ -1357,31 +1396,35 @@ def coord_functions(self, chart1=None, chart2=None): if (chart1, chart2) not in self._coord_expression: # Check whether (chart1, chart2) are (subchart, superchart) of # a pair of charts where the expression of self is known: - for (ochart1, ochart2) in self._coord_expression: + for ochart1, ochart2 in self._coord_expression: if chart1 in ochart1._subcharts and ochart2 in chart2._subcharts: coord_functions = self._coord_expression[(ochart1, ochart2)].expr() - self._coord_expression[(chart1, chart2)] = \ - chart1.multifunction(*coord_functions) + self._coord_expression[(chart1, chart2)] = chart1.multifunction( + *coord_functions + ) return self._coord_expression[(chart1, chart2)] # Special case of the identity in a single chart: if self._is_identity and chart1 == chart2: coord_functions = chart1[:] - self._coord_expression[(chart1, chart1)] = \ - chart1.multifunction(*coord_functions) + self._coord_expression[(chart1, chart1)] = chart1.multifunction( + *coord_functions + ) return self._coord_expression[(chart1, chart2)] # Some change of coordinates must be performed change_start = [] change_arrival = [] - for (ochart1, ochart2) in self._coord_expression: + for ochart1, ochart2 in self._coord_expression: if chart1 == ochart1: change_arrival.append(ochart2) if chart2 == ochart2: change_start.append(ochart1) # 1/ Trying to make a change of chart only on the codomain: # the codomain's default chart is privileged: - sel_chart2 = None # selected chart2 - if (def_chart2 in change_arrival - and (def_chart2, chart2) in dom2._coord_changes): + sel_chart2 = None # selected chart2 + if ( + def_chart2 in change_arrival + and (def_chart2, chart2) in dom2._coord_changes + ): sel_chart2 = def_chart2 else: for ochart2 in change_arrival: @@ -1391,15 +1434,18 @@ def coord_functions(self, chart1=None, chart2=None): if sel_chart2 is not None: oexpr = self._coord_expression[(chart1, sel_chart2)] chg2 = dom2._coord_changes[(sel_chart2, chart2)] - self._coord_expression[(chart1, chart2)] = \ - chart1.multifunction( *chg2(*oexpr.expr()) ) + self._coord_expression[(chart1, chart2)] = chart1.multifunction( + *chg2(*oexpr.expr()) + ) return self._coord_expression[(chart1, chart2)] # 2/ Trying to make a change of chart only on the start domain: # the domain's default chart is privileged: - sel_chart1 = None # selected chart1 - if (def_chart1 in change_start - and (chart1, def_chart1) in dom1._coord_changes): + sel_chart1 = None # selected chart1 + if ( + def_chart1 in change_start + and (chart1, def_chart1) in dom1._coord_changes + ): sel_chart1 = def_chart1 else: for ochart1 in change_start: @@ -1409,22 +1455,27 @@ def coord_functions(self, chart1=None, chart2=None): if sel_chart1 is not None: oexpr = self._coord_expression[(sel_chart1, chart2)] chg1 = dom1._coord_changes[(chart1, sel_chart1)] - self._coord_expression[(chart1, chart2)] = \ - chart1.multifunction( *oexpr(*chg1._transf.expr()) ) + self._coord_expression[(chart1, chart2)] = chart1.multifunction( + *oexpr(*chg1._transf.expr()) + ) return self._coord_expression[(chart1, chart2)] # 3/ If this point is reached, it is necessary to perform some # coordinate change both on the start domain and the arrival one # the default charts are privileged: - if ((def_chart1, def_chart2) in self._coord_expression - and (chart1, def_chart1) in dom1._coord_changes - and (def_chart2, chart2) in dom2._coord_changes): + if ( + (def_chart1, def_chart2) in self._coord_expression + and (chart1, def_chart1) in dom1._coord_changes + and (def_chart2, chart2) in dom2._coord_changes + ): sel_chart1 = def_chart1 sel_chart2 = def_chart2 else: - for (ochart1, ochart2) in self._coord_expression: - if ((chart1, ochart1) in dom1._coord_changes - and (ochart2, chart2) in dom2._coord_changes): + for ochart1, ochart2 in self._coord_expression: + if (chart1, ochart1) in dom1._coord_changes and ( + ochart2, + chart2, + ) in dom2._coord_changes: sel_chart1 = ochart1 sel_chart2 = ochart2 break @@ -1433,14 +1484,18 @@ def coord_functions(self, chart1=None, chart2=None): chg1 = dom1._coord_changes[(chart1, sel_chart1)] chg2 = dom2._coord_changes[(sel_chart2, chart2)] self._coord_expression[(chart1, chart2)] = chart1.multifunction( - *chg2( *oexpr(*chg1._transf.expr()) ) ) + *chg2(*oexpr(*chg1._transf.expr())) + ) return self._coord_expression[(chart1, chart2)] # 4/ If this point is reached, the demanded value cannot be # computed - raise ValueError("the expression of the map in the pair " + - "({}, {})".format(chart1, chart2) + " cannot " + - "be computed by means of known changes of charts") + raise ValueError( + "the expression of the map in the pair " + + "({}, {})".format(chart1, chart2) + + " cannot " + + "be computed by means of known changes of charts" + ) return self._coord_expression[(chart1, chart2)] @@ -1638,27 +1693,36 @@ def set_expr(self, chart1, chart2, coord_functions): True """ if self._is_identity: - raise NotImplementedError("set_expr() must not be used for the identity map") + raise NotImplementedError( + "set_expr() must not be used for the identity map" + ) if chart1 not in self._domain.atlas(): - raise ValueError("the {}".format(chart1) + - " has not been defined on the {}".format(self._domain)) + raise ValueError( + "the {}".format(chart1) + + " has not been defined on the {}".format(self._domain) + ) if chart2 not in self._codomain.atlas(): - raise ValueError("the {}".format(chart2) + - " has not been defined on the {}".format(self._codomain)) + raise ValueError( + "the {}".format(chart2) + + " has not been defined on the {}".format(self._codomain) + ) self._coord_expression.clear() self._del_derived() n2 = self._codomain.dim() if n2 > 1: if len(coord_functions) != n2: - raise ValueError("{} coordinate functions must ".format(n2) + - "be provided.") - self._coord_expression[(chart1, chart2)] = \ - chart1.multifunction(*coord_functions) + raise ValueError( + "{} coordinate functions must ".format(n2) + "be provided." + ) + self._coord_expression[(chart1, chart2)] = chart1.multifunction( + *coord_functions + ) else: if isinstance(coord_functions, (list, tuple)): coord_functions = coord_functions[0] - self._coord_expression[(chart1, chart2)] = \ - chart1.multifunction(coord_functions) + self._coord_expression[(chart1, chart2)] = chart1.multifunction( + coord_functions + ) set_expression = set_expr @@ -1775,23 +1839,33 @@ def add_expr(self, chart1, chart2, coord_functions): True """ if self._is_identity: - raise NotImplementedError("add_expr() must not be used for the identity map") + raise NotImplementedError( + "add_expr() must not be used for the identity map" + ) if chart1 not in self._domain.atlas(): - raise ValueError("the {}".format(chart1) + - " has not been defined on the {}".format(self._domain)) + raise ValueError( + "the {}".format(chart1) + + " has not been defined on the {}".format(self._domain) + ) if chart2 not in self._codomain.atlas(): - raise ValueError("the {}".format(chart2) + - " has not been defined on the {}".format(self._codomain)) + raise ValueError( + "the {}".format(chart2) + + " has not been defined on the {}".format(self._codomain) + ) self._del_derived() n2 = self._codomain.dim() if n2 > 1: if len(coord_functions) != n2: raise ValueError("{} coordinate functions must be provided".format(n2)) - self._coord_expression[(chart1, chart2)] = chart1.multifunction(*coord_functions) + self._coord_expression[(chart1, chart2)] = chart1.multifunction( + *coord_functions + ) else: if isinstance(coord_functions, (list, tuple)): coord_functions = coord_functions[0] - self._coord_expression[(chart1, chart2)] = chart1.multifunction(coord_functions) + self._coord_expression[(chart1, chart2)] = chart1.multifunction( + coord_functions + ) add_expression = add_expr @@ -1879,12 +1953,16 @@ def restrict(self, subdomain, subcodomain=None): return self if (subdomain, subcodomain) not in self._restrictions: if not subdomain.is_subset(self._domain): - raise ValueError("the specified domain is not a subset" - " of the domain of definition of the" - " continuous map") + raise ValueError( + "the specified domain is not a subset" + " of the domain of definition of the" + " continuous map" + ) if not subcodomain.is_subset(self._codomain): - raise ValueError("the specified codomain is not a subset" - " of the codomain of the continuous map") + raise ValueError( + "the specified codomain is not a subset" + " of the codomain of the continuous map" + ) # Special case of the identity map: if self._is_identity: self._restrictions[(subdomain, subcodomain)] = subdomain.identity_map() @@ -1892,7 +1970,10 @@ def restrict(self, subdomain, subcodomain=None): # First one tries to get the restriction from a tighter domain: for dom, rst in self._restrictions.items(): - if subdomain.is_subset(dom[0]) and (subdomain, subcodomain) in rst._restrictions: + if ( + subdomain.is_subset(dom[0]) + and (subdomain, subcodomain) in rst._restrictions + ): res = rst._restrictions[(subdomain, subcodomain)] self._restrictions[(subdomain, subcodomain)] = res self._restrictions.update(res._restrictions) @@ -1907,18 +1988,18 @@ def restrict(self, subdomain, subcodomain=None): # Maybe it didn't exist but could have: for dom, rst in self._restrictions.items(): if subdomain.is_subset(dom[0]) and subcodomain.is_subset(dom[1]): - res = rst.restrict(subdomain,subcodomain) # all propagation - # is done here + res = rst.restrict(subdomain, subcodomain) # all propagation + # is done here # should be useless: - self._restrictions[(subdomain,subcodomain)] = res + self._restrictions[(subdomain, subcodomain)] = res self._restrictions_graph[(subdomain, subcodomain)] = res - return self._restrictions[(subdomain,subcodomain)] + return self._restrictions[(subdomain, subcodomain)] # Secondly one tries to get the restriction from one previously # defined on a larger domain: for dom, ext in self._extensions_graph.items(): - if (subdomain,subcodomain) in ext._restrictions: - res = ext._restrictions[(subdomain,subcodomain)] + if (subdomain, subcodomain) in ext._restrictions: + res = ext._restrictions[(subdomain, subcodomain)] self._restrictions[(subdomain, subcodomain)] = res self._restrictions.update(res._restrictions) self._restrictions_graph.update(res._restrictions_graph) @@ -1931,8 +2012,7 @@ def restrict(self, subdomain, subcodomain=None): # Generic case: homset = Hom(subdomain, subcodomain) - resu = type(self)(homset, name=self._name, - latex_name=self._latex_name) + resu = type(self)(homset, name=self._name, latex_name=self._latex_name) for charts in self._coord_expression: for ch1 in charts[0]._subcharts: if ch1._domain.is_subset(subdomain): @@ -1945,12 +2025,15 @@ def restrict(self, subdomain, subcodomain=None): for sch2 in ch2._subcharts: if (ch1, sch2) in resu._coord_expression: del resu._coord_expression[(ch1, sch2)] - coord_functions = self._coord_expression[charts].expr() - resu._coord_expression[(ch1, ch2)] = \ - ch1.multifunction(*coord_functions) + coord_functions = self._coord_expression[ + charts + ].expr() + resu._coord_expression[(ch1, ch2)] = ( + ch1.multifunction(*coord_functions) + ) # propagate extensions - for dom, ext in self._extensions_graph.items(): # includes self + for dom, ext in self._extensions_graph.items(): # includes self ext._restrictions[(subdomain, subcodomain)] = resu ext._restrictions_graph[(subdomain, subcodomain)] = resu @@ -2045,22 +2128,22 @@ def __invert__(self): sage: si == s True """ - from sage.symbolic.ring import SR from sage.symbolic.relation import solve + from sage.symbolic.ring import SR + if self._inverse is not None: return self._inverse if not self._is_isomorphism: raise ValueError("the {} is not an isomorphism".format(self)) - coord_functions = {} # coordinate expressions of the result - for (chart1, chart2) in self._coord_expression: + coord_functions = {} # coordinate expressions of the result + for chart1, chart2 in self._coord_expression: coord_map = self._coord_expression[(chart1, chart2)] n1 = len(chart1._xx) n2 = len(chart2._xx) # New symbolic variables (different from chart2._xx to allow for a # correct solution even when chart2 = chart1): x2 = SR.temp_var(n=n2) - equations = [x2[i] == coord_map._functions[i].expr() - for i in range(n2)] + equations = [x2[i] == coord_map._functions[i].expr() for i in range(n2)] solutions = solve(equations, chart1._xx, solution_dict=True) if not solutions: raise ValueError("no solution found") @@ -2068,8 +2151,7 @@ def __invert__(self): raise ValueError("non-unique solution found") substitutions = dict(zip(x2, chart2._xx)) sol = solutions[0] - inv_functions = [sol[chart1._xx[i]].subs(substitutions) - for i in range(n1)] + inv_functions = [sol[chart1._xx[i]].subs(substitutions) for i in range(n1)] for i in range(n1): x = inv_functions[i] try: @@ -2088,9 +2170,13 @@ def __invert__(self): else: latex_name = self._latex_name + r'^{-1}' homset = Hom(self._codomain, self._domain) - self._inverse = type(self)(homset, coord_functions=coord_functions, - name=name, latex_name=latex_name, - is_isomorphism=True) + self._inverse = type(self)( + homset, + coord_functions=coord_functions, + name=name, + latex_name=latex_name, + is_isomorphism=True, + ) return self._inverse inverse = __invert__ diff --git a/src/sage/manifolds/continuous_map_image.py b/src/sage/manifolds/continuous_map_image.py index bbcfa672a5a..78000be81ab 100644 --- a/src/sage/manifolds/continuous_map_image.py +++ b/src/sage/manifolds/continuous_map_image.py @@ -39,7 +39,9 @@ class ImageManifoldSubset(ManifoldSubset): ``map`` """ - def __init__(self, map, inverse=None, name=None, latex_name=None, domain_subset=None): + def __init__( + self, map, inverse=None, name=None, latex_name=None, domain_subset=None + ): r""" Construct a manifold subset that is the image of a continuous map. diff --git a/src/sage/manifolds/differentiable/affine_connection.py b/src/sage/manifolds/differentiable/affine_connection.py index 73b6e5d42cd..a52c82ee1cc 100644 --- a/src/sage/manifolds/differentiable/affine_connection.py +++ b/src/sage/manifolds/differentiable/affine_connection.py @@ -28,12 +28,12 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.rings.integer import Integer -from sage.structure.sage_object import SageObject -from sage.misc.cachefunc import cached_method from sage.manifolds.differentiable.manifold import DifferentiableManifold +from sage.misc.cachefunc import cached_method from sage.parallel.decorate import parallel from sage.parallel.parallelism import Parallelism +from sage.rings.integer import Integer +from sage.structure.sage_object import SageObject class AffineConnection(SageObject): @@ -603,8 +603,8 @@ def _new_coef(self, frame): sage: nab._new_coef(X.frame()) 3-indices components w.r.t. Coordinate frame (M, (∂/∂x,∂/∂y)) """ - from sage.tensor.modules.comp import Components from sage.manifolds.differentiable.scalarfield import DiffScalarField + from sage.tensor.modules.comp import Components return Components(frame._domain.scalar_field_algebra(), frame, 3, start_index=self._domain._sindex, output_formatter=DiffScalarField.coord_function) @@ -1306,8 +1306,8 @@ def display(self, frame=None, chart=None, symbol=None, latex_symbol=None, Gam^ph_ph,r = 1/r Gam^ph_ph,th = cos(th)/sin(th) """ - from sage.misc.latex import latex from sage.manifolds.differentiable.vectorframe import CoordFrame + from sage.misc.latex import latex if frame is None: frame = self._domain.default_frame() if chart is None: @@ -1503,8 +1503,7 @@ def __call__(self, tensor): :class:`~sage.manifolds.differentiable.affine_connection.AffineConnection` for more examples. """ - from sage.manifolds.differentiable.tensorfield_paral import \ - TensorFieldParal + from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.tensor.modules.format_utilities import format_unop_latex dom_resu = self._domain.intersection(tensor._domain) tensor_r = tensor.restrict(dom_resu) diff --git a/src/sage/manifolds/differentiable/automorphismfield.py b/src/sage/manifolds/differentiable/automorphismfield.py index 3556fc56e95..320620a0d8b 100644 --- a/src/sage/manifolds/differentiable/automorphismfield.py +++ b/src/sage/manifolds/differentiable/automorphismfield.py @@ -24,9 +24,9 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism class AutomorphismField(TensorField): @@ -1168,9 +1168,9 @@ def __invert__(self): sage: b is ~a True """ + from sage.manifolds.differentiable.vectorframe import CoordFrame from sage.matrix.constructor import matrix from sage.tensor.modules.comp import Components - from sage.manifolds.differentiable.vectorframe import CoordFrame if self._is_identity: return self if self._inverse is None: @@ -1199,7 +1199,7 @@ def __invert__(self): if isinstance(frame, CoordFrame): chart = frame._chart else: - chart = self._domain._def_chart #!# to be improved + chart = self._domain._def_chart # ! # to be improved try: # TODO: do the computation without the 'SR' enforcement mat_self = matrix( @@ -1370,7 +1370,7 @@ def at(self, point): if dest_map.is_identity(): amb_point = point else: - amb_point = dest_map(point) # "ambient" point + amb_point = dest_map(point) # "ambient" point ts = amb_point._manifold.tangent_space(amb_point) if self._is_identity: return ts.identity_map() diff --git a/src/sage/manifolds/differentiable/automorphismfield_group.py b/src/sage/manifolds/differentiable/automorphismfield_group.py index c6315670c9e..45a2fad087a 100644 --- a/src/sage/manifolds/differentiable/automorphismfield_group.py +++ b/src/sage/manifolds/differentiable/automorphismfield_group.py @@ -38,15 +38,19 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent from sage.categories.groups import Groups +from sage.manifolds.differentiable.automorphismfield import ( + AutomorphismField, + AutomorphismFieldParal, +) +from sage.manifolds.differentiable.vectorfield_module import ( + VectorFieldFreeModule, + VectorFieldModule, +) from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation from sage.tensor.modules.free_module_linear_group import FreeModuleLinearGroup -from sage.manifolds.differentiable.vectorfield_module import (VectorFieldModule, - VectorFieldFreeModule) -from sage.manifolds.differentiable.automorphismfield import (AutomorphismField, - AutomorphismFieldParal) class AutomorphismFieldGroup(UniqueRepresentation, Parent): diff --git a/src/sage/manifolds/differentiable/bundle_connection.py b/src/sage/manifolds/differentiable/bundle_connection.py index 184e9641eeb..35d70c2e847 100644 --- a/src/sage/manifolds/differentiable/bundle_connection.py +++ b/src/sage/manifolds/differentiable/bundle_connection.py @@ -38,11 +38,10 @@ # https://www.gnu.org/licenses/ # ****************************************************************************** -from sage.structure.sage_object import SageObject -from sage.structure.mutability import Mutability +from sage.manifolds.differentiable.vector_bundle import DifferentiableVectorBundle from sage.rings.integer import Integer -from sage.manifolds.differentiable.vector_bundle import \ - DifferentiableVectorBundle +from sage.structure.mutability import Mutability +from sage.structure.sage_object import SageObject class BundleConnection(SageObject, Mutability): diff --git a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py index 51f32ffb4b8..63d0384e149 100644 --- a/src/sage/manifolds/differentiable/characteristic_cohomology_class.py +++ b/src/sage/manifolds/differentiable/characteristic_cohomology_class.py @@ -282,16 +282,16 @@ from sage.algebras.finite_gca import FiniteGCAlgebra from sage.combinat.free_module import IndexedFreeModuleElement -from sage.misc.fast_methods import Singleton -from sage.structure.sage_object import SageObject -from sage.misc.cachefunc import cached_method +from sage.manifolds.differentiable.affine_connection import AffineConnection +from sage.manifolds.differentiable.bundle_connection import BundleConnection +from sage.manifolds.differentiable.levi_civita_connection import LeviCivitaConnection from sage.misc.abstract_method import abstract_method -from .affine_connection import AffineConnection -from .bundle_connection import BundleConnection -from .levi_civita_connection import LeviCivitaConnection -from sage.symbolic.expression import Expression +from sage.misc.cachefunc import cached_method +from sage.misc.fast_methods import Singleton from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.structure.sage_object import SageObject +from sage.symbolic.expression import Expression class CharacteristicCohomologyClassRingElement(IndexedFreeModuleElement): @@ -795,7 +795,7 @@ def _element_constructor_(self, x, **kwargs): Characteristic cohomology class pontr(TM) of the Tangent bundle TM over the 8-dimensional differentiable manifold M """ - if isinstance(x, (str, Expression)) or isinstance(x, Polynomial): + if isinstance(x, (str, Expression, Polynomial)): return self._build_element(x, **kwargs) R = self.base_ring() @@ -894,7 +894,7 @@ def _build_element(self, *args, **kwargs): # predefined classes accessible via class names if isinstance(val, str): - from sage.arith.misc import factorial, bernoulli + from sage.arith.misc import bernoulli, factorial P = PolynomialRing(base_ring, 'x') x = P.gen() @@ -1085,8 +1085,8 @@ def multiplicative_sequence(q, n=None): e[] + e[1] - e[1, 1] + 3*e[2] - e[2, 1] + e[2, 2] + 4*e[3] - 3*e[3, 1] + e[3, 2] + 7*e[4] - 4*e[4, 1] + 11*e[5] """ - from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import Partitions + from sage.combinat.sf.sf import SymmetricFunctions from sage.misc.misc_c import prod if n is None: @@ -1140,8 +1140,8 @@ def additive_sequence(q, k, n=None): sage: sym_1 = additive_sequence(f, 2, 1); sym_1 2*e[] + e[1] """ - from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import Partitions + from sage.combinat.sf.sf import SymmetricFunctions if n is None: n = q.degree() @@ -1427,7 +1427,7 @@ def get_local(self, cmat): sage: algorithm.get_local(cmat) [2-form on the 2-dimensional Lorentzian manifold M] """ - from sage.symbolic.constants import pi, I + from sage.symbolic.constants import I, pi dom = cmat[0][0]._domain rk = len(cmat) diff --git a/src/sage/manifolds/differentiable/chart.py b/src/sage/manifolds/differentiable/chart.py index bcfa37dc237..c944a9d7815 100644 --- a/src/sage/manifolds/differentiable/chart.py +++ b/src/sage/manifolds/differentiable/chart.py @@ -31,9 +31,9 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.misc.cachefunc import cached_method -from sage.manifolds.chart import Chart, RealChart, CoordChange +from sage.manifolds.chart import Chart, CoordChange, RealChart from sage.manifolds.differentiable.vectorframe import CoordFrame +from sage.misc.cachefunc import cached_method class DiffChart(Chart): diff --git a/src/sage/manifolds/differentiable/curve.py b/src/sage/manifolds/differentiable/curve.py index e28e44b8adb..8a1cfc2e77e 100644 --- a/src/sage/manifolds/differentiable/curve.py +++ b/src/sage/manifolds/differentiable/curve.py @@ -32,10 +32,10 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.latex import latex -from sage.misc.decorators import options -from sage.manifolds.point import ManifoldPoint from sage.manifolds.differentiable.diff_map import DiffMap +from sage.manifolds.point import ManifoldPoint +from sage.misc.decorators import options +from sage.misc.latex import latex class DifferentiableCurve(DiffMap): @@ -871,9 +871,9 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, g = c.plot(parameters={a: 2, b: -3}, aspect_ratio=1) sphinx_plot(g) """ - from sage.rings.infinity import Infinity - from sage.misc.functional import numerical_approx from sage.manifolds.chart import RealChart + from sage.misc.functional import numerical_approx + from sage.rings.infinity import Infinity # # Get the @options from kwds @@ -995,9 +995,9 @@ def _graphics(self, plot_curve, ambient_coords, thickness=1, sage: graph._extra_kwds['axes_labels'] == l True """ + from sage.manifolds.utilities import set_axes_labels from sage.plot.graphics import Graphics from sage.plot.line import line - from sage.manifolds.utilities import set_axes_labels # # The plot diff --git a/src/sage/manifolds/differentiable/de_rham_cohomology.py b/src/sage/manifolds/differentiable/de_rham_cohomology.py index 9bc766f5a78..729ed375afa 100644 --- a/src/sage/manifolds/differentiable/de_rham_cohomology.py +++ b/src/sage/manifolds/differentiable/de_rham_cohomology.py @@ -45,13 +45,15 @@ # https://www.gnu.org/licenses/ #****************************************************************************** -from sage.structure.unique_representation import UniqueRepresentation +from sage.categories.algebras import Algebras +from sage.manifolds.differentiable.characteristic_cohomology_class import ( + CharacteristicCohomologyClassRing, + CharacteristicCohomologyClassRingElement, +) from sage.misc.cachefunc import cached_method -from sage.structure.parent import Parent from sage.structure.element import AlgebraElement -from sage.categories.algebras import Algebras -from .characteristic_cohomology_class import (CharacteristicCohomologyClassRing, - CharacteristicCohomologyClassRingElement) +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation class DeRhamCohomologyClass(AlgebraElement): diff --git a/src/sage/manifolds/differentiable/degenerate.py b/src/sage/manifolds/differentiable/degenerate.py index b34fefc3a89..80da669f083 100644 --- a/src/sage/manifolds/differentiable/degenerate.py +++ b/src/sage/manifolds/differentiable/degenerate.py @@ -11,11 +11,12 @@ # ***************************************************************************** from __future__ import annotations + from typing import TYPE_CHECKING -from sage.rings.infinity import infinity -from sage.manifolds.structure import DegenerateStructure from sage.manifolds.differentiable.manifold import DifferentiableManifold +from sage.manifolds.structure import DegenerateStructure +from sage.rings.infinity import infinity if TYPE_CHECKING: from sage.manifolds.differentiable.metric import DegenerateMetric @@ -368,8 +369,8 @@ def open_subset(self, name, latex_name=None, coord_def={}): #******************************************************************************************* -from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.manifolds.differentiable.tensorfield import TensorField +from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal class TangentTensor(TensorFieldParal): diff --git a/src/sage/manifolds/differentiable/degenerate_submanifold.py b/src/sage/manifolds/differentiable/degenerate_submanifold.py index a119fb57802..fcb843a8abe 100644 --- a/src/sage/manifolds/differentiable/degenerate_submanifold.py +++ b/src/sage/manifolds/differentiable/degenerate_submanifold.py @@ -156,17 +156,17 @@ # ***************************************************************************** from __future__ import annotations + from typing import TYPE_CHECKING -from sage.manifolds.differentiable.pseudo_riemannian import \ - PseudoRiemannianManifold -from sage.manifolds.differentiable.degenerate import (DegenerateManifold, - TangentTensor) -from sage.manifolds.differentiable.differentiable_submanifold import \ - DifferentiableSubmanifold +from sage.manifolds.differentiable.degenerate import DegenerateManifold, TangentTensor +from sage.manifolds.differentiable.differentiable_submanifold import ( + DifferentiableSubmanifold, +) +from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule -from sage.rings.infinity import infinity from sage.matrix.constructor import matrix +from sage.rings.infinity import infinity from sage.symbolic.expression import Expression if TYPE_CHECKING: diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index fb58189796e..0457b815d8a 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -44,16 +44,18 @@ # ***************************************************************************** from __future__ import annotations -from typing import Optional, Union, TYPE_CHECKING -from sage.misc.cachefunc import cached_method -from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm + +from typing import TYPE_CHECKING, Optional, Union + from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.misc.cachefunc import cached_method +from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm if TYPE_CHECKING: - from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule from sage.manifolds.differentiable.metric import PseudoRiemannianMetric from sage.manifolds.differentiable.symplectic_form import SymplecticForm + from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule class DiffForm(TensorField): @@ -442,8 +444,8 @@ def exterior_derivative(self) -> DiffForm: True """ from sage.tensor.modules.format_utilities import ( - format_unop_txt, format_unop_latex, + format_unop_txt, ) vmodule = self._vmodule # shortcut @@ -525,8 +527,8 @@ def wedge(self, other: DiffForm) -> DiffForm: """ if other._tensor_rank == 0: return self * other - from sage.typeset.unicode_characters import unicode_wedge from sage.tensor.modules.format_utilities import is_atomic + from sage.typeset.unicode_characters import unicode_wedge if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): raise ValueError("incompatible ambient domains for exterior product") @@ -762,8 +764,8 @@ def hodge_dual( """ from sage.functions.other import factorial from sage.tensor.modules.format_utilities import ( - format_unop_txt, format_unop_latex, + format_unop_txt, ) if nondegenerate_tensor is None: @@ -1438,10 +1440,12 @@ def exterior_derivative(self) -> DiffFormParal: sage: a.lie_der(v) == v.contract(diff(a)) + diff(a(v)) # long time True """ - from sage.tensor.modules.format_utilities import (format_unop_txt, - format_unop_latex) - from sage.tensor.modules.comp import CompFullyAntiSym from sage.manifolds.differentiable.vectorframe import CoordFrame + from sage.tensor.modules.comp import CompFullyAntiSym + from sage.tensor.modules.format_utilities import ( + format_unop_latex, + format_unop_txt, + ) fmodule = self._fmodule # shortcut rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) diff --git a/src/sage/manifolds/differentiable/diff_form_module.py b/src/sage/manifolds/differentiable/diff_form_module.py index ee0dd856697..d79686fb7b6 100644 --- a/src/sage/manifolds/differentiable/diff_form_module.py +++ b/src/sage/manifolds/differentiable/diff_form_module.py @@ -38,14 +38,14 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.misc.cachefunc import cached_method -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent from sage.categories.modules import Modules -from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule from sage.manifolds.differentiable.diff_form import DiffForm, DiffFormParal from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule from sage.tensor.modules.reflexive_module import ReflexiveModule_abstract @@ -863,7 +863,9 @@ def _coerce_map_from_(self, other): and self._domain.is_subset(other._domain) and self._ambient_domain.is_subset(other._ambient_domain)) - from sage.manifolds.differentiable.tensorfield_module import TensorFieldFreeModule + from sage.manifolds.differentiable.tensorfield_module import ( + TensorFieldFreeModule, + ) if isinstance(other, TensorFieldFreeModule): # coercion of a type-(0,1) tensor to a linear form return (self._fmodule is other._fmodule and self._degree == 1 diff --git a/src/sage/manifolds/differentiable/examples/euclidean.py b/src/sage/manifolds/differentiable/examples/euclidean.py index ec0f30be82c..433993d36ad 100644 --- a/src/sage/manifolds/differentiable/examples/euclidean.py +++ b/src/sage/manifolds/differentiable/examples/euclidean.py @@ -408,14 +408,13 @@ # https://www.gnu.org/licenses/ #***************************************************************************** -from sage.functions.trig import cos, sin, atan2 +from sage.categories.manifolds import Manifolds +from sage.categories.metric_spaces import MetricSpaces +from sage.functions.trig import atan2, cos, sin +from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold from sage.misc.functional import sqrt from sage.misc.latex import latex from sage.rings.real_mpfr import RR -from sage.categories.manifolds import Manifolds -from sage.categories.metric_spaces import MetricSpaces -from sage.manifolds.differentiable.pseudo_riemannian import \ - PseudoRiemannianManifold ############################################################################### @@ -696,8 +695,9 @@ def __classcall_private__(cls, n=None, name=None, latex_name=None, symbols = ' '.join(names) # Technical bit for UniqueRepresentation - from sage.misc.prandom import getrandbits from time import time + + from sage.misc.prandom import getrandbits if unique_tag is None: unique_tag = getrandbits(128) * time() @@ -1035,7 +1035,7 @@ def sphere(self, radius=1, center=None, name=None, latex_name=None, n = self._dim if n == 1: raise ValueError('Euclidean space must have dimension of at least 2') - from .sphere import Sphere + from sage.manifolds.differentiable.examples.sphere import Sphere return Sphere(n-1, radius=radius, ambient_space=self, center=center, name=name, latex_name=latex_name, coordinates=coordinates, names=names) diff --git a/src/sage/manifolds/differentiable/examples/real_line.py b/src/sage/manifolds/differentiable/examples/real_line.py index 52b3dfad182..ef71608529e 100644 --- a/src/sage/manifolds/differentiable/examples/real_line.py +++ b/src/sage/manifolds/differentiable/examples/real_line.py @@ -24,14 +24,14 @@ # http://www.gnu.org/licenses/ #***************************************************************************** +from sage.categories.manifolds import Manifolds +from sage.manifolds.differentiable.manifold import DifferentiableManifold +from sage.manifolds.structure import RealDifferentialStructure from sage.misc.latex import latex from sage.rings.infinity import infinity, minus_infinity -from sage.symbolic.ring import SR from sage.rings.real_mpfr import RR +from sage.symbolic.ring import SR from sage.typeset.unicode_characters import unicode_mathbbR -from sage.manifolds.differentiable.manifold import DifferentiableManifold -from sage.manifolds.structure import RealDifferentialStructure -from sage.categories.manifolds import Manifolds class OpenInterval(DifferentiableManifold): diff --git a/src/sage/manifolds/differentiable/examples/sphere.py b/src/sage/manifolds/differentiable/examples/sphere.py index 43956a3ba1a..f1add71e110 100644 --- a/src/sage/manifolds/differentiable/examples/sphere.py +++ b/src/sage/manifolds/differentiable/examples/sphere.py @@ -165,13 +165,14 @@ eps_g = -dchi """ -from sage.manifolds.differentiable.pseudo_riemannian_submanifold import \ - PseudoRiemannianSubmanifold -from sage.categories.metric_spaces import MetricSpaces from sage.categories.manifolds import Manifolds +from sage.categories.metric_spaces import MetricSpaces from sage.categories.topological_spaces import TopologicalSpaces -from sage.rings.real_mpfr import RR from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace +from sage.manifolds.differentiable.pseudo_riemannian_submanifold import ( + PseudoRiemannianSubmanifold, +) +from sage.rings.real_mpfr import RR class Sphere(PseudoRiemannianSubmanifold): @@ -315,8 +316,9 @@ def __classcall_private__(cls, n=None, radius=1, ambient_space=None, n = len(names) # Technical bit for UniqueRepresentation - from sage.misc.prandom import getrandbits from time import time + + from sage.misc.prandom import getrandbits if unique_tag is None: unique_tag = getrandbits(128) * time() @@ -609,8 +611,8 @@ def _init_spherical(self, names=None): A.set_default_frame(spher.frame()) # manage embedding... - from sage.misc.misc_c import prod from sage.functions.trig import cos, sin + from sage.misc.misc_c import prod R = self._radius diff --git a/src/sage/manifolds/differentiable/examples/symplectic_space.py b/src/sage/manifolds/differentiable/examples/symplectic_space.py index 5a78277d567..41d7defe25a 100644 --- a/src/sage/manifolds/differentiable/examples/symplectic_space.py +++ b/src/sage/manifolds/differentiable/examples/symplectic_space.py @@ -20,8 +20,10 @@ from sage.categories.manifolds import Manifolds from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace -from sage.manifolds.differentiable.symplectic_form import (SymplecticForm, - SymplecticFormParal) +from sage.manifolds.differentiable.symplectic_form import ( + SymplecticForm, + SymplecticFormParal, +) from sage.rings.real_mpfr import RR diff --git a/src/sage/manifolds/differentiable/examples/symplectic_space_test.py b/src/sage/manifolds/differentiable/examples/symplectic_space_test.py index 9cfdf6da123..ca3dbcc5f41 100644 --- a/src/sage/manifolds/differentiable/examples/symplectic_space_test.py +++ b/src/sage/manifolds/differentiable/examples/symplectic_space_test.py @@ -1,9 +1,10 @@ +import pytest + import sage.all -from sage.manifolds.differentiable.symplectic_form import SymplecticForm from sage.manifolds.differentiable.examples.symplectic_space import ( StandardSymplecticSpace, ) -import pytest +from sage.manifolds.differentiable.symplectic_form import SymplecticForm class TestR2VectorSpace: diff --git a/src/sage/manifolds/differentiable/integrated_curve.py b/src/sage/manifolds/differentiable/integrated_curve.py index 17784f555e1..8b2d1f0251c 100644 --- a/src/sage/manifolds/differentiable/integrated_curve.py +++ b/src/sage/manifolds/differentiable/integrated_curve.py @@ -106,21 +106,21 @@ # https://www.gnu.org/licenses/ # ********************************************************************** -from sage.symbolic.expression import Expression -from sage.rings.infinity import Infinity -from sage.calculus.desolvers import desolve_system_rk4 -from sage.calculus.desolvers import desolve_odeint +from random import shuffle + +from sage.arith.srange import srange +from sage.calculus.desolvers import desolve_odeint, desolve_system_rk4 +from sage.calculus.interpolation import Spline +from sage.ext.fast_callable import fast_callable from sage.manifolds.chart import Chart from sage.manifolds.differentiable.curve import DifferentiableCurve from sage.manifolds.differentiable.tangent_vector import TangentVector -from sage.calculus.interpolation import Spline from sage.misc.decorators import options from sage.misc.functional import numerical_approx from sage.misc.lazy_import import lazy_import -from sage.arith.srange import srange -from sage.ext.fast_callable import fast_callable +from sage.rings.infinity import Infinity +from sage.symbolic.expression import Expression from sage.symbolic.ring import SR -from random import shuffle lazy_import('scipy.integrate', 'ode') @@ -857,9 +857,9 @@ def solve_analytical(self, verbose=False): Dx3_0*t + x3_0) """ - from sage.calculus.var import function - from sage.calculus.functional import diff from sage.calculus.desolvers import desolve_system + from sage.calculus.functional import diff + from sage.calculus.var import function from sage.symbolic.assumptions import assume, forget from sage.symbolic.ring import var @@ -1096,7 +1096,7 @@ def solve(self, step=None, method='odeint', solution_key=None, # raise error if coordinates in chart cannot be obtained initial_coord_basis = chart.frame().at(initial_pt) - initial_tgt_vec_comps = list(v0[initial_coord_basis,:]) #idem + initial_tgt_vec_comps = list(v0[initial_coord_basis,:]) # idem dim = self.codomain().dim() @@ -2372,15 +2372,15 @@ def plot_integrated(self, chart=None, ambient_coords=None, else: if across_charts: for key in self._interpolations: - if key[-8:-1] != '_chart_': # check if not a subplot + if key[-8:-1] != '_chart_': # check if not a subplot interpolation_key = key break else: raise ValueError("Did you forget to " "integrate or interpolate the result?") else: - interpolation_key = next(iter(self._interpolations)) #will - # raise error if self._interpolations empty + interpolation_key = next(iter(self._interpolations)) + # will raise error if self._interpolations empty if verbose: print("Plotting from the interpolation associated " + @@ -2484,7 +2484,7 @@ def plot_integrated(self, chart=None, ambient_coords=None, raise ValueError("the argument prange must be a " + "tuple/list of 2 elements") else: - p = prange #'p' declared only for the line below to be shorter + p = prange # 'p' declared only for the line below to be shorter if p[0] < param_min or p[0] > param_max or p[1] < param_min or p[1] > param_max: raise ValueError("parameter range should be a " + "subinterval of the curve domain " + @@ -2559,8 +2559,8 @@ def plot_integrated(self, chart=None, ambient_coords=None, t += dt if display_tangent: - from sage.plot.graphics import Graphics from sage.plot.arrow import arrow2d + from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes import arrow3d scale = kwds.pop('scale') @@ -2746,8 +2746,8 @@ def plot_integrated(self, chart=None, ambient_coords=None, t += dt if display_tangent: - from sage.plot.graphics import Graphics from sage.plot.arrow import arrow2d + from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes import arrow3d scale = kwds.pop('scale') @@ -3972,18 +3972,19 @@ def system(self, verbose=False): if verbose: initial_tgt_space = v0.parent() - initial_pt = initial_tgt_space.base_point()#retrieves - # the initial point as the base point of the tangent space - # to which initial tangent vector belongs + initial_pt = initial_tgt_space.base_point() + # retrieves the initial point as the base point of the + # tangent space to which initial tangent vector belongs + initial_pt_coords = list(initial_pt.coordinates(chart)) - # previous line converts to list since would otherwise be a - # tuple ; will raise error if coordinates in chart are not - # known + # previous line converts to list since would otherwise be + # a tuple ; will raise error if coordinates in chart are + # not known initial_coord_basis = chart.frame().at(initial_pt) - initial_tgt_vec_comps = v0[initial_coord_basis,:] # will - # raise error if components in coordinate basis are not - # known + initial_tgt_vec_comps = v0[initial_coord_basis,:] + # will raise error if components in coordinate basis are + # not known description = "Geodesic " if self._name is not None: diff --git a/src/sage/manifolds/differentiable/levi_civita_connection.py b/src/sage/manifolds/differentiable/levi_civita_connection.py index 215756f00d3..7768efbad23 100644 --- a/src/sage/manifolds/differentiable/levi_civita_connection.py +++ b/src/sage/manifolds/differentiable/levi_civita_connection.py @@ -29,10 +29,10 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.parallel.decorate import parallel -from sage.parallel.parallelism import Parallelism from sage.manifolds.differentiable.affine_connection import AffineConnection from sage.manifolds.differentiable.vectorframe import CoordFrame +from sage.parallel.decorate import parallel +from sage.parallel.parallelism import Parallelism class LeviCivitaConnection(AffineConnection): @@ -364,9 +364,9 @@ def _new_coef(self, frame): sage: nab._new_coef(e) 3-indices components w.r.t. Vector frame (M, (e_0,e_1)) """ - from sage.tensor.modules.comp import Components, CompWithSym from sage.manifolds.differentiable.scalarfield import DiffScalarField from sage.manifolds.differentiable.vectorframe import CoordFrame + from sage.tensor.modules.comp import Components, CompWithSym if isinstance(frame, CoordFrame): # the Christoffel symbols are symmetric: return CompWithSym(frame._domain.scalar_field_algebra(), frame, 3, diff --git a/src/sage/manifolds/differentiable/manifold.py b/src/sage/manifolds/differentiable/manifold.py index 285a160e7ff..1ad2543827a 100644 --- a/src/sage/manifolds/differentiable/manifold.py +++ b/src/sage/manifolds/differentiable/manifold.py @@ -451,8 +451,8 @@ from sage.rings.real_mpfr import RR if TYPE_CHECKING: - from sage.manifolds.differentiable.diff_map import DiffMap from sage.manifolds.differentiable.diff_form import DiffForm + from sage.manifolds.differentiable.diff_map import DiffMap from sage.manifolds.differentiable.metric import PseudoRiemannianMetric from sage.manifolds.differentiable.vectorfield_module import ( VectorFieldFreeModule, @@ -1097,8 +1097,9 @@ class as the manifold. Differentiable real vector bundle E -> M of rank 2 over the base space 2-dimensional differentiable manifold M """ - from sage.manifolds.differentiable.vector_bundle \ - import DifferentiableVectorBundle + from sage.manifolds.differentiable.vector_bundle import ( + DifferentiableVectorBundle, + ) return DifferentiableVectorBundle(rank, name, self, field=field, latex_name=latex_name) @@ -1366,8 +1367,10 @@ def vector_field_module( sage: M.is_manifestly_parallelizable() True """ - from sage.manifolds.differentiable.vectorfield_module import \ - VectorFieldModule, VectorFieldFreeModule + from sage.manifolds.differentiable.vectorfield_module import ( + VectorFieldFreeModule, + VectorFieldModule, + ) if dest_map is None: dest_map = self.identity_map() codomain = dest_map._codomain @@ -2695,7 +2698,7 @@ def set_orientation(self, orientation): [Coordinate frame (U, (∂/∂x,∂/∂y)), Coordinate frame (V, (∂/∂u,∂/∂v))] """ - from .vectorframe import VectorFrame + from sage.manifolds.differentiable.vectorframe import VectorFrame chart_type = self._structure.chart if isinstance(orientation, chart_type): orientation = [orientation.frame()] @@ -2985,7 +2988,9 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame, [1 2] [0 3] """ - from sage.manifolds.differentiable.automorphismfield import AutomorphismFieldParal + from sage.manifolds.differentiable.automorphismfield import ( + AutomorphismFieldParal, + ) fmodule = frame1._fmodule if frame2._fmodule != fmodule: raise ValueError("the two frames are not defined on the same " + @@ -3394,8 +3399,8 @@ def tangent_space(self, point, base_ring=None): :class:`~sage.manifolds.differentiable.tangent_space.TangentSpace` for more examples. """ - from sage.manifolds.point import ManifoldPoint from sage.manifolds.differentiable.tangent_space import TangentSpace + from sage.manifolds.point import ManifoldPoint if not isinstance(point, ManifoldPoint): raise TypeError("{} is not a manifold point".format(point)) if point not in self: @@ -3725,7 +3730,9 @@ def integrated_autoparallel_curve(self, affine_connection, """ from sage.manifolds.differentiable.examples.real_line import RealLine - from sage.manifolds.differentiable.manifold_homset import IntegratedAutoparallelCurveSet + from sage.manifolds.differentiable.manifold_homset import ( + IntegratedAutoparallelCurveSet, + ) if len(curve_param) != 3: raise ValueError("the argument 'curve_param' must be " + @@ -3893,8 +3900,7 @@ def affine_connection(self, name, latex_name=None): :class:`~sage.manifolds.differentiable.affine_connection.AffineConnection` for more examples. """ - from sage.manifolds.differentiable.affine_connection import \ - AffineConnection + from sage.manifolds.differentiable.affine_connection import AffineConnection return AffineConnection(self, name, latex_name) def metric(self, name: str, signature: Optional[int] = None, diff --git a/src/sage/manifolds/differentiable/manifold_homset.py b/src/sage/manifolds/differentiable/manifold_homset.py index d26e1cfea91..98fdf8998f5 100644 --- a/src/sage/manifolds/differentiable/manifold_homset.py +++ b/src/sage/manifolds/differentiable/manifold_homset.py @@ -42,12 +42,14 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.manifolds.manifold_homset import TopologicalManifoldHomset -from sage.manifolds.differentiable.diff_map import DiffMap from sage.manifolds.differentiable.curve import DifferentiableCurve -from sage.manifolds.differentiable.integrated_curve import IntegratedCurve -from sage.manifolds.differentiable.integrated_curve import IntegratedAutoparallelCurve -from sage.manifolds.differentiable.integrated_curve import IntegratedGeodesic +from sage.manifolds.differentiable.diff_map import DiffMap +from sage.manifolds.differentiable.integrated_curve import ( + IntegratedAutoparallelCurve, + IntegratedCurve, + IntegratedGeodesic, +) +from sage.manifolds.manifold_homset import TopologicalManifoldHomset class DifferentiableManifoldHomset(TopologicalManifoldHomset): @@ -180,8 +182,7 @@ def __init__(self, domain, codomain, name=None, latex_name=None): manifolds over Real Field with 53 bits of precision sage: TestSuite(E).run() """ - from sage.manifolds.differentiable.manifold import \ - DifferentiableManifold + from sage.manifolds.differentiable.manifold import DifferentiableManifold if not isinstance(domain, DifferentiableManifold): raise TypeError("domain = {} is not an ".format(domain) + "instance of DifferentiableManifold") @@ -1305,11 +1306,11 @@ def _an_element_(self): (1.0565635217644918,) """ + from sage.categories.homset import Hom + from sage.functions.log import exp from sage.rings.infinity import Infinity from sage.rings.rational_field import QQ - from sage.categories.homset import Hom from sage.symbolic.ring import var - from sage.functions.log import exp dom = self.domain() t = dom.canonical_coordinate() @@ -1754,8 +1755,8 @@ def _an_element_(self): """ from sage.categories.homset import Hom - from sage.symbolic.ring import var from sage.functions.log import exp + from sage.symbolic.ring import var dom = self.domain() t = dom.canonical_coordinate() diff --git a/src/sage/manifolds/differentiable/metric.py b/src/sage/manifolds/differentiable/metric.py index 4a783db3478..8512ad2b70d 100644 --- a/src/sage/manifolds/differentiable/metric.py +++ b/src/sage/manifolds/differentiable/metric.py @@ -784,8 +784,9 @@ def connection(self, name=None, latex_name=None, init_coef=True): sage: Dig == 0 True """ - from sage.manifolds.differentiable.levi_civita_connection import \ - LeviCivitaConnection + from sage.manifolds.differentiable.levi_civita_connection import ( + LeviCivitaConnection, + ) if self._connection is None: if latex_name is None: if name is None: diff --git a/src/sage/manifolds/differentiable/mixed_form.py b/src/sage/manifolds/differentiable/mixed_form.py index 65e2a25891e..c9b04bd2a12 100644 --- a/src/sage/manifolds/differentiable/mixed_form.py +++ b/src/sage/manifolds/differentiable/mixed_form.py @@ -23,8 +23,8 @@ # ***************************************************************************** from sage.misc.cachefunc import cached_method -from sage.structure.element import AlgebraElement, ModuleElementWithMutability from sage.rings.integer import Integer +from sage.structure.element import AlgebraElement, ModuleElementWithMutability class MixedForm(AlgebraElement, ModuleElementWithMutability): @@ -413,9 +413,8 @@ def display_expansion(self, frame=None, chart=None, from_chart=None): F = x dx + (2*x^2 - 2*y^2) dx∧dy """ from sage.misc.latex import latex + from sage.tensor.modules.format_utilities import FormattedExpansion, is_atomic from sage.typeset.unicode_characters import unicode_wedge - from sage.tensor.modules.format_utilities import (is_atomic, - FormattedExpansion) # In case, no frame is given: if frame is None: frame = self._domain._def_frame @@ -711,7 +710,7 @@ def _richcmp_(self, other, op): sage: F.parent().zero() == 0 True """ - from sage.structure.richcmp import op_NE, op_EQ + from sage.structure.richcmp import op_EQ, op_NE if op == op_NE: return not self == other elif op == op_EQ: @@ -979,9 +978,11 @@ def wedge(self, other): resu._comp = [sum(self[k].wedge(other[j - k]) for k in range(j + 1)) for j in self.irange()] # Compose name: + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) from sage.typeset.unicode_characters import unicode_wedge - from sage.tensor.modules.format_utilities import (format_mul_txt, - format_mul_latex) resu._name = format_mul_txt(self._name, unicode_wedge, other._name) resu._latex_name = format_mul_latex(self._latex_name, r'\wedge ', other._latex_name) @@ -1032,9 +1033,11 @@ def _lmul_(self, other): resu._comp = [other * form for form in self] # Compose name: from sage.misc.latex import latex + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) from sage.typeset.unicode_characters import unicode_wedge - from sage.tensor.modules.format_utilities import (format_mul_txt, - format_mul_latex) resu._name = format_mul_txt(repr(other), unicode_wedge, self._name) resu._latex_name = format_mul_latex(latex(other), r'\wedge ', self._latex_name) @@ -1100,8 +1103,10 @@ def exterior_derivative(self): resu[1:] = [self[j].exterior_derivative() for j in range(self._max_deg)] # Compose name: - from sage.tensor.modules.format_utilities import (format_unop_txt, - format_unop_latex) + from sage.tensor.modules.format_utilities import ( + format_unop_latex, + format_unop_txt, + ) resu._name = format_unop_txt('d', self._name) resu._latex_name = format_unop_latex(r'\mathrm{d}', self._latex_name) return resu diff --git a/src/sage/manifolds/differentiable/mixed_form_algebra.py b/src/sage/manifolds/differentiable/mixed_form_algebra.py index 26339c0d6ad..c6af6f4164d 100644 --- a/src/sage/manifolds/differentiable/mixed_form_algebra.py +++ b/src/sage/manifolds/differentiable/mixed_form_algebra.py @@ -28,14 +28,14 @@ # https://www.gnu.org/licenses/ #****************************************************************************** -from sage.misc.cachefunc import cached_method -from sage.structure.parent import Parent -from sage.categories.graded_algebras import GradedAlgebras from sage.categories.chain_complexes import ChainComplexes +from sage.categories.graded_algebras import GradedAlgebras from sage.categories.morphism import SetMorphism +from sage.manifolds.differentiable.mixed_form import MixedForm +from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.symbolic.ring import SR -from sage.manifolds.differentiable.mixed_form import MixedForm class MixedFormAlgebra(Parent, UniqueRepresentation): @@ -494,7 +494,9 @@ def cohomology(self, *args, **kwargs): De Rham cohomology ring on the 3-dimensional differentiable manifold M """ - from .de_rham_cohomology import DeRhamCohomologyRing + from sage.manifolds.differentiable.de_rham_cohomology import ( + DeRhamCohomologyRing, + ) return DeRhamCohomologyRing(self) homology = cohomology diff --git a/src/sage/manifolds/differentiable/multivector_module.py b/src/sage/manifolds/differentiable/multivector_module.py index fa2d5fce099..35f56f2935e 100644 --- a/src/sage/manifolds/differentiable/multivector_module.py +++ b/src/sage/manifolds/differentiable/multivector_module.py @@ -32,13 +32,15 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.categories.modules import Modules +from sage.manifolds.differentiable.multivectorfield import ( + MultivectorField, + MultivectorFieldParal, +) from sage.misc.cachefunc import cached_method -from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.categories.modules import Modules +from sage.structure.unique_representation import UniqueRepresentation from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule -from sage.manifolds.differentiable.multivectorfield import ( - MultivectorField, MultivectorFieldParal) class MultivectorModule(UniqueRepresentation, Parent): diff --git a/src/sage/manifolds/differentiable/multivectorfield.py b/src/sage/manifolds/differentiable/multivectorfield.py index 1e739dfdd17..2efe5c133f2 100644 --- a/src/sage/manifolds/differentiable/multivectorfield.py +++ b/src/sage/manifolds/differentiable/multivectorfield.py @@ -36,9 +36,9 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor from sage.manifolds.differentiable.tensorfield import TensorField from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal +from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor class MultivectorField(TensorField): @@ -300,8 +300,8 @@ def wedge(self, other): sage: c.display(e_uv) a∧b = (-v^2 + u) ∂/∂u∧∂/∂v """ - from sage.typeset.unicode_characters import unicode_wedge from sage.tensor.modules.format_utilities import is_atomic + from sage.typeset.unicode_characters import unicode_wedge if self._domain.is_subset(other._domain): if not self._ambient_domain.is_subset(other._ambient_domain): raise ValueError("incompatible ambient domains for exterior " + @@ -1401,10 +1401,10 @@ def bracket(self, other): True """ from itertools import combinations + from sage.combinat.permutation import Permutation - from sage.tensor.modules.comp import (Components, CompWithSym, - CompFullyAntiSym) from sage.manifolds.differentiable.scalarfield import DiffScalarField + from sage.tensor.modules.comp import CompFullyAntiSym, Components, CompWithSym pp = self._tensor_rank mp1 = (-1)**(pp+1) if isinstance(other, DiffScalarField): diff --git a/src/sage/manifolds/differentiable/poisson_tensor.py b/src/sage/manifolds/differentiable/poisson_tensor.py index 51da2de5f90..63fcab8d588 100644 --- a/src/sage/manifolds/differentiable/poisson_tensor.py +++ b/src/sage/manifolds/differentiable/poisson_tensor.py @@ -16,16 +16,17 @@ # ***************************************************************************** +from typing import Optional, Union + +from sage.manifolds.differentiable.diff_form import DiffForm +from sage.manifolds.differentiable.manifold import DifferentiableManifold from sage.manifolds.differentiable.multivectorfield import ( MultivectorField, MultivectorFieldParal, ) -from sage.manifolds.differentiable.diff_form import DiffForm -from sage.manifolds.differentiable.vectorfield import VectorField from sage.manifolds.differentiable.scalarfield import DiffScalarField +from sage.manifolds.differentiable.vectorfield import VectorField from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule -from sage.manifolds.differentiable.manifold import DifferentiableManifold -from typing import Optional, Union class PoissonTensorField(MultivectorField): diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian.py b/src/sage/manifolds/differentiable/pseudo_riemannian.py index 505900ad0df..c44d063bdc3 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian.py @@ -267,10 +267,13 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.rings.infinity import infinity -from sage.manifolds.structure import (PseudoRiemannianStructure, - RiemannianStructure, LorentzianStructure) from sage.manifolds.differentiable.manifold import DifferentiableManifold +from sage.manifolds.structure import ( + LorentzianStructure, + PseudoRiemannianStructure, + RiemannianStructure, +) +from sage.rings.infinity import infinity ############################################################################### diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py index e791cef6781..57dc1c99862 100644 --- a/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +++ b/src/sage/manifolds/differentiable/pseudo_riemannian_submanifold.py @@ -190,19 +190,19 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** -from sage.manifolds.differentiable.pseudo_riemannian import \ - PseudoRiemannianManifold -from sage.manifolds.differentiable.degenerate import \ - DegenerateManifold -from sage.manifolds.differentiable.differentiable_submanifold import \ - DifferentiableSubmanifold -from sage.rings.infinity import infinity -from sage.matrix.constructor import matrix +from queue import Queue + from sage.functions.other import factorial -from sage.symbolic.ring import SR +from sage.manifolds.differentiable.degenerate import DegenerateManifold +from sage.manifolds.differentiable.differentiable_submanifold import ( + DifferentiableSubmanifold, +) +from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold +from sage.matrix.constructor import matrix from sage.misc.cachefunc import cached_method +from sage.rings.infinity import infinity from sage.rings.integer import Integer -from queue import Queue +from sage.symbolic.ring import SR class PseudoRiemannianSubmanifold(PseudoRiemannianManifold, diff --git a/src/sage/manifolds/differentiable/scalarfield.py b/src/sage/manifolds/differentiable/scalarfield.py index be1d6d3b97e..72d04db04f0 100644 --- a/src/sage/manifolds/differentiable/scalarfield.py +++ b/src/sage/manifolds/differentiable/scalarfield.py @@ -789,8 +789,10 @@ def differential(self) -> DiffForm: sage: ddg == 0 True """ - from sage.tensor.modules.format_utilities import (format_unop_txt, - format_unop_latex) + from sage.tensor.modules.format_utilities import ( + format_unop_latex, + format_unop_txt, + ) if self._differential is None: # A new computation is necessary: rname = format_unop_txt('d', self._name) @@ -936,8 +938,8 @@ def hodge_dual( True """ from sage.tensor.modules.format_utilities import ( - format_unop_txt, format_unop_latex, + format_unop_txt, ) result = self * nondegenerate_tensor.volume_form() diff --git a/src/sage/manifolds/differentiable/scalarfield_algebra.py b/src/sage/manifolds/differentiable/scalarfield_algebra.py index fc716f5fcc4..6a6091fe659 100644 --- a/src/sage/manifolds/differentiable/scalarfield_algebra.py +++ b/src/sage/manifolds/differentiable/scalarfield_algebra.py @@ -30,10 +30,10 @@ class `C^k` over a topological field `K` (in # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.manifolds.differentiable.scalarfield import DiffScalarField +from sage.manifolds.scalarfield_algebra import ScalarFieldAlgebra from sage.rings.infinity import infinity from sage.symbolic.ring import SymbolicRing -from sage.manifolds.scalarfield_algebra import ScalarFieldAlgebra -from sage.manifolds.differentiable.scalarfield import DiffScalarField class DiffScalarFieldAlgebra(ScalarFieldAlgebra): diff --git a/src/sage/manifolds/differentiable/symplectic_form.py b/src/sage/manifolds/differentiable/symplectic_form.py index 52a076bfbe8..2c393d59cd7 100644 --- a/src/sage/manifolds/differentiable/symplectic_form.py +++ b/src/sage/manifolds/differentiable/symplectic_form.py @@ -22,18 +22,19 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** from __future__ import annotations -from typing import Union, Optional -from sage.symbolic.expression import Expression +from typing import Optional, Union + from sage.manifolds.differentiable.diff_form import DiffForm, DiffFormParal from sage.manifolds.differentiable.diff_map import DiffMap -from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule -from sage.manifolds.differentiable.tensorfield import TensorField -from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.manifolds.differentiable.manifold import DifferentiableManifold +from sage.manifolds.differentiable.poisson_tensor import PoissonTensorField from sage.manifolds.differentiable.scalarfield import DiffScalarField +from sage.manifolds.differentiable.tensorfield import TensorField +from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.manifolds.differentiable.vectorfield import VectorField -from sage.manifolds.differentiable.poisson_tensor import PoissonTensorField +from sage.manifolds.differentiable.vectorfield_module import VectorFieldModule +from sage.symbolic.expression import Expression class SymplecticForm(DiffForm): diff --git a/src/sage/manifolds/differentiable/symplectic_form_test.py b/src/sage/manifolds/differentiable/symplectic_form_test.py index 804c8956b6e..cb5133595fb 100644 --- a/src/sage/manifolds/differentiable/symplectic_form_test.py +++ b/src/sage/manifolds/differentiable/symplectic_form_test.py @@ -1,16 +1,16 @@ # pylint: disable=missing-function-docstring -from _pytest.fixtures import FixtureRequest import pytest +from _pytest.fixtures import FixtureRequest -from sage.manifolds.manifold import Manifold -from sage.manifolds.differentiable.manifold import DifferentiableManifold from sage.manifolds.differentiable.examples.sphere import Sphere -from sage.manifolds.differentiable.symplectic_form import SymplecticForm from sage.manifolds.differentiable.examples.symplectic_space import ( StandardSymplecticSpace, ) -from sage.symbolic.function_factory import function +from sage.manifolds.differentiable.manifold import DifferentiableManifold from sage.manifolds.differentiable.scalarfield import DiffScalarField +from sage.manifolds.differentiable.symplectic_form import SymplecticForm +from sage.manifolds.manifold import Manifold +from sage.symbolic.function_factory import function class TestGenericSymplecticForm: diff --git a/src/sage/manifolds/differentiable/tangent_vector.py b/src/sage/manifolds/differentiable/tangent_vector.py index 1bd1dd5c647..81b89e29646 100644 --- a/src/sage/manifolds/differentiable/tangent_vector.py +++ b/src/sage/manifolds/differentiable/tangent_vector.py @@ -24,10 +24,10 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement -from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm -from .scalarfield import DiffScalarField +from sage.manifolds.differentiable.scalarfield import DiffScalarField from sage.misc.decorators import options +from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm +from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement class TangentVector(FiniteRankFreeModuleElement): @@ -448,13 +448,13 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9) sphinx_plot(graph_v + graph_S2) """ + from sage.manifolds.differentiable.chart import DiffChart + from sage.misc.functional import numerical_approx from sage.plot.arrow import arrow2d - from sage.plot.text import text from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes import arrow3d from sage.plot.plot3d.shapes2 import text3d - from sage.misc.functional import numerical_approx - from sage.manifolds.differentiable.chart import DiffChart + from sage.plot.text import text scale = extra_options.pop("scale") diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py index 562c62cefc8..50ed9fe7a80 100644 --- a/src/sage/manifolds/differentiable/tensorfield.py +++ b/src/sage/manifolds/differentiable/tensorfield.py @@ -2228,7 +2228,7 @@ def __eq__(self, other): sage: t.parent().zero() == 0 True """ - from .mixed_form import MixedForm + from sage.manifolds.differentiable.mixed_form import MixedForm if other is self: return True @@ -2341,8 +2341,10 @@ def __pos__(self): for dom, rst in self._restrictions.items(): resu._restrictions[dom] = + rst # Compose names: - from sage.tensor.modules.format_utilities import (format_unop_txt, - format_unop_latex) + from sage.tensor.modules.format_utilities import ( + format_unop_latex, + format_unop_txt, + ) resu._name = format_unop_txt('+', self._name) resu._latex_name = format_unop_latex(r'+', self._latex_name) return resu @@ -2385,8 +2387,10 @@ def __neg__(self): for dom, rst in self._restrictions.items(): resu._restrictions[dom] = - rst # Compose names: - from sage.tensor.modules.format_utilities import (format_unop_txt, - format_unop_latex) + from sage.tensor.modules.format_utilities import ( + format_unop_latex, + format_unop_txt, + ) resu._name = format_unop_txt('-', self._name) resu._latex = format_unop_latex(r'-', self._latex_name) return resu @@ -2597,8 +2601,10 @@ def _rmul_(self, scalar): for dom, rst in self._restrictions.items(): resu._restrictions[dom] = scalar.restrict(dom) * rst # Compose names: - from sage.tensor.modules.format_utilities import (format_mul_txt, - format_mul_latex) + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) resu_name = format_mul_txt(scalar._name, '*', self._name) resu_latex = format_mul_latex(scalar._latex_name, r' \cdot ', self._latex_name) @@ -3826,8 +3832,8 @@ def up( raise ValueError("position out of range") from sage.manifolds.differentiable.metric import PseudoRiemannianMetric - from sage.manifolds.differentiable.symplectic_form import SymplecticForm from sage.manifolds.differentiable.poisson_tensor import PoissonTensorField + from sage.manifolds.differentiable.symplectic_form import SymplecticForm if isinstance(non_degenerate_form, PseudoRiemannianMetric): return self.contract(pos, non_degenerate_form.inverse(), 1) diff --git a/src/sage/manifolds/differentiable/tensorfield_module.py b/src/sage/manifolds/differentiable/tensorfield_module.py index 22d42050b89..089d4d178d8 100644 --- a/src/sage/manifolds/differentiable/tensorfield_module.py +++ b/src/sage/manifolds/differentiable/tensorfield_module.py @@ -38,20 +38,23 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** +from sage.categories.modules import Modules +from sage.manifolds.differentiable.automorphismfield import ( + AutomorphismField, + AutomorphismFieldParal, +) +from sage.manifolds.differentiable.diff_form import DiffForm, DiffFormParal +from sage.manifolds.differentiable.multivectorfield import ( + MultivectorField, + MultivectorFieldParal, +) +from sage.manifolds.differentiable.tensorfield import TensorField +from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal from sage.misc.cachefunc import cached_method -from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.categories.modules import Modules +from sage.structure.unique_representation import UniqueRepresentation from sage.tensor.modules.reflexive_module import ReflexiveModule_tensor from sage.tensor.modules.tensor_free_module import TensorFreeModule -from sage.manifolds.differentiable.tensorfield import TensorField -from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal -from sage.manifolds.differentiable.diff_form import (DiffForm, - DiffFormParal) -from sage.manifolds.differentiable.multivectorfield import (MultivectorField, - MultivectorFieldParal) -from sage.manifolds.differentiable.automorphismfield import (AutomorphismField, - AutomorphismFieldParal) class TensorFieldModule(UniqueRepresentation, ReflexiveModule_tensor): @@ -442,12 +445,11 @@ def _coerce_map_from_(self, other): sage: T11._coerce_map_from_(M.automorphism_field_group()) True """ - from sage.manifolds.differentiable.diff_form_module import \ - DiffFormModule - from sage.manifolds.differentiable.multivector_module import \ - MultivectorModule - from sage.manifolds.differentiable.automorphismfield_group \ - import AutomorphismFieldGroup + from sage.manifolds.differentiable.automorphismfield_group import ( + AutomorphismFieldGroup, + ) + from sage.manifolds.differentiable.diff_form_module import DiffFormModule + from sage.manifolds.differentiable.multivector_module import MultivectorModule if isinstance(other, (TensorFieldModule, TensorFieldFreeModule)): # coercion by domain restriction return (self._tensor_type == other._tensor_type @@ -901,12 +903,13 @@ def _coerce_map_from_(self, other): sage: T11._coerce_map_from_(M.automorphism_field_group()) True """ - from sage.manifolds.differentiable.diff_form_module import \ - DiffFormFreeModule - from sage.manifolds.differentiable.multivector_module import \ - MultivectorFreeModule - from sage.manifolds.differentiable.automorphismfield_group \ - import AutomorphismFieldParalGroup + from sage.manifolds.differentiable.automorphismfield_group import ( + AutomorphismFieldParalGroup, + ) + from sage.manifolds.differentiable.diff_form_module import DiffFormFreeModule + from sage.manifolds.differentiable.multivector_module import ( + MultivectorFreeModule, + ) if isinstance(other, (TensorFieldModule, TensorFieldFreeModule)): # coercion by domain restriction return (self._tensor_type == other._tensor_type diff --git a/src/sage/manifolds/differentiable/tensorfield_paral.py b/src/sage/manifolds/differentiable/tensorfield_paral.py index cb0e1db14cd..08b151e50c9 100644 --- a/src/sage/manifolds/differentiable/tensorfield_paral.py +++ b/src/sage/manifolds/differentiable/tensorfield_paral.py @@ -1975,8 +1975,8 @@ def display_comp(self, frame=None, chart=None, coordinate_labels=True, t^10_0 = (u^2 - v^2)/(u^2 + 2*u*v + v^2 + 8) t^11_1 = -12/(u^2 + 2*u*v + v^2 + 8) """ - from sage.misc.latex import latex from sage.manifolds.differentiable.vectorframe import CoordFrame + from sage.misc.latex import latex if frame is None: if chart is not None: frame = chart.frame() @@ -2118,7 +2118,7 @@ def at(self, point): if dest_map.is_identity(): amb_point = point else: - amb_point = dest_map(point) # "ambient" point + amb_point = dest_map(point) # "ambient" point ts = amb_point._manifold.tangent_space(amb_point) resu = ts.tensor(self._tensor_type, name=self._name, latex_name=self._latex_name, sym=self._sym, diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 79e940a19e6..a6307cf274d 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -30,12 +30,12 @@ #****************************************************************************** from sage.categories.vector_bundles import VectorBundles -from sage.rings.cc import CC -from sage.rings.real_mpfr import RR from sage.manifolds.vector_bundle import TopologicalVectorBundle -from sage.rings.infinity import infinity from sage.misc.superseded import deprecated_function_alias +from sage.rings.cc import CC +from sage.rings.infinity import infinity from sage.rings.rational_field import QQ +from sage.rings.real_mpfr import RR class DifferentiableVectorBundle(TopologicalVectorBundle): @@ -158,7 +158,7 @@ def bundle_connection(self, name, latex_name=None): Further examples can be found in :class:`~sage.manifolds.differentiable.bundle_connection.BundleConnection`. """ - from .bundle_connection import BundleConnection + from sage.manifolds.differentiable.bundle_connection import BundleConnection return BundleConnection(self, name, latex_name) def characteristic_cohomology_class_ring(self, base=QQ): @@ -186,7 +186,9 @@ def characteristic_cohomology_class_ring(self, base=QQ): Characteristic cohomology class (1 + p_1)(TM) of the Tangent bundle TM over the 4-dimensional differentiable manifold M """ - from .characteristic_cohomology_class import CharacteristicCohomologyClassRing + from sage.manifolds.differentiable.characteristic_cohomology_class import ( + CharacteristicCohomologyClassRing, + ) return CharacteristicCohomologyClassRing(base, self) diff --git a/src/sage/manifolds/differentiable/vectorfield.py b/src/sage/manifolds/differentiable/vectorfield.py index 44ae84089de..c038e8afab2 100644 --- a/src/sage/manifolds/differentiable/vectorfield.py +++ b/src/sage/manifolds/differentiable/vectorfield.py @@ -59,10 +59,12 @@ # https://www.gnu.org/licenses/ # ***************************************************************************** -from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement from sage.manifolds.differentiable.multivectorfield import ( - MultivectorField, MultivectorFieldParal) + MultivectorField, + MultivectorFieldParal, +) from sage.misc.decorators import options +from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement class VectorField(MultivectorField): @@ -663,14 +665,14 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, sage: v.plot.reset() """ - from sage.rings.infinity import Infinity - from sage.misc.functional import numerical_approx - from sage.misc.latex import latex - from sage.plot.graphics import Graphics from sage.manifolds.chart import RealChart from sage.manifolds.utilities import set_axes_labels + from sage.misc.functional import numerical_approx + from sage.misc.latex import latex from sage.parallel.decorate import parallel from sage.parallel.parallelism import Parallelism + from sage.plot.graphics import Graphics + from sage.rings.infinity import Infinity # # 1/ Treatment of input parameters diff --git a/src/sage/manifolds/differentiable/vectorfield_module.py b/src/sage/manifolds/differentiable/vectorfield_module.py index 67cd1abd614..edea1756278 100644 --- a/src/sage/manifolds/differentiable/vectorfield_module.py +++ b/src/sage/manifolds/differentiable/vectorfield_module.py @@ -57,9 +57,9 @@ if TYPE_CHECKING: from sage.manifolds.differentiable.diff_form import DiffForm - from sage.manifolds.scalarfield import ScalarField from sage.manifolds.differentiable.diff_map import DiffMap from sage.manifolds.differentiable.manifold import DifferentiableManifold + from sage.manifolds.scalarfield import ScalarField class VectorFieldModule(UniqueRepresentation, ReflexiveModule_base): @@ -548,8 +548,9 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): try: return self._tensor_modules[(k,l)] except KeyError: - from sage.manifolds.differentiable.tensorfield_module import \ - TensorFieldModule + from sage.manifolds.differentiable.tensorfield_module import ( + TensorFieldModule, + ) T = TensorFieldModule(self, (k,l)) self._tensor_modules[(k,l)] = T return T @@ -606,8 +607,9 @@ def exterior_power(self, p): if p == 0: L = self._ring else: - from sage.manifolds.differentiable.multivector_module import \ - MultivectorModule + from sage.manifolds.differentiable.multivector_module import ( + MultivectorModule, + ) L = MultivectorModule(self, p) self._exterior_powers[p] = L return L @@ -663,8 +665,9 @@ def dual_exterior_power(self, p): if p == 0: L = self._ring else: - from sage.manifolds.differentiable.diff_form_module import \ - DiffFormModule + from sage.manifolds.differentiable.diff_form_module import ( + DiffFormModule, + ) L = DiffFormModule(self, p) self._dual_exterior_powers[p] = L return L @@ -713,8 +716,9 @@ def general_linear_group(self): for more examples and documentation. """ if self._general_linear_group is None: - from sage.manifolds.differentiable.automorphismfield_group import \ - AutomorphismFieldGroup + from sage.manifolds.differentiable.automorphismfield_group import ( + AutomorphismFieldGroup, + ) self._general_linear_group = AutomorphismFieldGroup(self) return self._general_linear_group @@ -769,10 +773,11 @@ def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, :class:`~sage.manifolds.differentiable.tensorfield.TensorField` for more examples and documentation. """ - from sage.manifolds.differentiable.automorphismfield import \ - AutomorphismField - from sage.manifolds.differentiable.metric import (PseudoRiemannianMetric, - DegenerateMetric) + from sage.manifolds.differentiable.automorphismfield import AutomorphismField + from sage.manifolds.differentiable.metric import ( + DegenerateMetric, + PseudoRiemannianMetric, + ) from sage.tensor.modules.comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( tensor_type[0] + tensor_type[1], sym, antisym) @@ -1839,8 +1844,9 @@ def tensor_module(self, k, l, *, sym=None, antisym=None): elif (k, l) == (0, 1): T = self.dual() else: - from sage.manifolds.differentiable.tensorfield_module import \ - TensorFieldFreeModule + from sage.manifolds.differentiable.tensorfield_module import ( + TensorFieldFreeModule, + ) T = TensorFieldFreeModule(self, (k,l)) self._tensor_modules[(k,l)] = T return T @@ -1900,8 +1906,9 @@ def exterior_power(self, p): elif p == 1: L = self else: - from sage.manifolds.differentiable.multivector_module import \ - MultivectorFreeModule + from sage.manifolds.differentiable.multivector_module import ( + MultivectorFreeModule, + ) L = MultivectorFreeModule(self, p) self._exterior_powers[p] = L return L @@ -1956,12 +1963,14 @@ def dual_exterior_power(self, p): if p == 0: L = self._ring elif p == 1: - from sage.manifolds.differentiable.diff_form_module import \ - VectorFieldDualFreeModule + from sage.manifolds.differentiable.diff_form_module import ( + VectorFieldDualFreeModule, + ) L = VectorFieldDualFreeModule(self) else: - from sage.manifolds.differentiable.diff_form_module import \ - DiffFormFreeModule + from sage.manifolds.differentiable.diff_form_module import ( + DiffFormFreeModule, + ) L = DiffFormFreeModule(self, p) self._dual_exterior_powers[p] = L return L @@ -1996,8 +2005,9 @@ def general_linear_group(self): :class:`~sage.manifolds.differentiable.automorphismfield_group.AutomorphismFieldParalGroup` for more examples and documentation. """ - from sage.manifolds.differentiable.automorphismfield_group import \ - AutomorphismFieldParalGroup + from sage.manifolds.differentiable.automorphismfield_group import ( + AutomorphismFieldParalGroup, + ) return AutomorphismFieldParalGroup(self) def basis(self, symbol=None, latex_symbol=None, from_frame=None, @@ -2138,9 +2148,13 @@ def _tensor(self, tensor_type, name=None, latex_name=None, sym=None, for more examples and documentation. """ from sage.manifolds.differentiable.automorphismfield import ( - AutomorphismField, AutomorphismFieldParal) - from sage.manifolds.differentiable.metric import (PseudoRiemannianMetric, - DegenerateMetric) + AutomorphismField, + AutomorphismFieldParal, + ) + from sage.manifolds.differentiable.metric import ( + DegenerateMetric, + PseudoRiemannianMetric, + ) from sage.tensor.modules.comp import CompWithSym sym, antisym = CompWithSym._canonicalize_sym_antisym( tensor_type[0] + tensor_type[1], sym, antisym) @@ -2227,7 +2241,7 @@ def tensor_from_comp(self, tensor_type, comp, name=None, sage: t.display() t = (x + 1) dx⊗dx - y dx⊗dy + x*y dy⊗dx + (-y^2 + 2) dy⊗dy """ - from sage.tensor.modules.comp import (CompWithSym, CompFullyAntiSym) + from sage.tensor.modules.comp import CompFullyAntiSym, CompWithSym # 0/ Compatibility checks: if comp._ring is not self._ring: diff --git a/src/sage/manifolds/differentiable/vectorframe.py b/src/sage/manifolds/differentiable/vectorframe.py index 594d2e9a729..a4df55bd276 100644 --- a/src/sage/manifolds/differentiable/vectorframe.py +++ b/src/sage/manifolds/differentiable/vectorframe.py @@ -216,10 +216,9 @@ # 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 from sage.misc.cachefunc import cached_method +from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule +from sage.tensor.modules.free_module_basis import FreeModuleBasis, FreeModuleCoBasis class CoFrame(FreeModuleCoBasis): @@ -1405,7 +1404,7 @@ def at(self, point): """ # Case of a non-trivial destination map if self._from_frame is not None: - if self._dest_map.is_identity(): #!# probably not necessary + if self._dest_map.is_identity(): # ! # probably not necessary raise ValueError("the destination map should not be the identity") ambient_point = self._dest_map(point) return self._from_frame.at(ambient_point) @@ -1715,9 +1714,9 @@ def __init__(self, chart): Coordinate frame (M, (∂/∂x,∂/∂y)) sage: TestSuite(e).run() """ + from sage.manifolds.differentiable.chart import DiffChart from sage.misc.latex import latex from sage.typeset.unicode_characters import unicode_partial - from sage.manifolds.differentiable.chart import DiffChart if not isinstance(chart, DiffChart): raise TypeError("the first argument must be a chart") dom = chart.domain() diff --git a/src/sage/manifolds/family.py b/src/sage/manifolds/family.py index 565fa2401cc..8a544061843 100644 --- a/src/sage/manifolds/family.py +++ b/src/sage/manifolds/family.py @@ -15,7 +15,7 @@ - Matthias Koeppe (2021): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2021 Matthias Koeppe # # This program is free software: you can redistribute it and/or modify @@ -23,15 +23,15 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** from functools import total_ordering + from sage.sets.family import FiniteFamily @total_ordering class ManifoldObjectFiniteFamily(FiniteFamily): - r""" Finite family of manifold objects, indexed by their names. @@ -65,6 +65,7 @@ class ManifoldObjectFiniteFamily(FiniteFamily): ... TypeError: all objects must have the same manifold """ + def __init__(self, objects=(), keys=None): r""" Initialize a new instance of :class:`ManifoldObjectFiniteFamily`. @@ -97,8 +98,9 @@ def __init__(self, objects=(), keys=None): if keys is None: keys = sorted(dictionary.keys()) FiniteFamily.__init__(self, dictionary, keys) - names_and_latex_names = sorted((object._name, object._latex_name) - for object in self) + names_and_latex_names = sorted( + (object._name, object._latex_name) for object in self + ) self._name = '{' + ', '.join(keys) + '}' latex_names = (latex_name for name, latex_name in names_and_latex_names) self._latex_name = r'\{' + ', '.join(latex_names) + r'\}' @@ -109,7 +111,9 @@ def __init__(self, objects=(), keys=None): self._manifold = None else: if not all(object._manifold == self._manifold for object in object_iter): - raise TypeError(f'all {self._repr_object_type()} must have the same manifold') + raise TypeError( + f'all {self._repr_object_type()} must have the same manifold' + ) def _repr_object_type(self): r""" @@ -163,7 +167,9 @@ def __repr__(self): 'Set {A, B} of objects of the 2-dimensional topological manifold M' """ if self: - return "Set {} of {} of the {}".format(self._name, self._repr_object_type(), self._manifold) + return "Set {} of {} of the {}".format( + self._name, self._repr_object_type(), self._manifold + ) else: return "{}" @@ -184,7 +190,6 @@ def _latex_(self): class ManifoldSubsetFiniteFamily(ManifoldObjectFiniteFamily): - r""" Finite family of subsets of a topological manifold, indexed by their names. @@ -232,14 +237,17 @@ def from_subsets_or_families(cls, *subsets_or_families): sage: ManifoldSubsetFiniteFamily.from_subsets_or_families(A, Bs, Cs) Set {A, B0, B1, B2, B3, B4, C0, C1} of subsets of the 2-dimensional topological manifold M """ + def generate_subsets(): from sage.manifolds.subset import ManifoldSubset + for arg in subsets_or_families: if isinstance(arg, ManifoldSubset): yield arg else: # arg must be an iterable of ManifoldSubset instances yield from arg + return cls(generate_subsets()) def _repr_object_type(self): diff --git a/src/sage/manifolds/local_frame.py b/src/sage/manifolds/local_frame.py index 42e1579640d..3d13c977f9a 100644 --- a/src/sage/manifolds/local_frame.py +++ b/src/sage/manifolds/local_frame.py @@ -171,9 +171,8 @@ # 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 +from sage.tensor.modules.free_module_basis import FreeModuleBasis, FreeModuleCoBasis class LocalCoFrame(FreeModuleCoBasis): @@ -1414,8 +1413,8 @@ def __init__(self, trivialization): sage: e = phi.frame() sage: TestSuite(e).run() """ + from sage.manifolds.trivialization import Trivialization from sage.misc.latex import latex - from .trivialization import Trivialization if not isinstance(trivialization, Trivialization): raise TypeError("the first argument must be a trivialization") ### diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py index c27cd0b6434..e3d03ad602f 100644 --- a/src/sage/manifolds/manifold.py +++ b/src/sage/manifolds/manifold.py @@ -1321,7 +1321,7 @@ def set_default_chart(self, chart): sage: M.default_chart() Chart (M, (u, v)) """ - from .chart import Chart + from sage.manifolds.chart import Chart if not isinstance(chart, Chart): raise TypeError("{} is not a chart".format(chart)) if chart not in self._atlas: @@ -1692,7 +1692,7 @@ def orientation(self): r""" Get the preferred orientation of ``self`` if available. - An *orientation* of an `n`-dimensional topologial manifold is an + An *orientation* of an `n`-dimensional topological manifold is an atlas of charts whose transition maps are orientation preserving. A homeomorphism `f \colon U \to V` for open subsets `U, V \subset \RR^n` is called *orientation preserving* if for each `x \in U` the @@ -2950,14 +2950,20 @@ def Manifold( sage: isinstance(M, sage.misc.fast_methods.WithEqualityById) True """ - from sage.rings.infinity import infinity + from sage.manifolds.differentiable.degenerate import DegenerateManifold + from sage.manifolds.differentiable.degenerate_submanifold import ( + DegenerateSubmanifold, + ) + from sage.manifolds.differentiable.differentiable_submanifold import ( + DifferentiableSubmanifold, + ) from sage.manifolds.differentiable.manifold import DifferentiableManifold from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold - from sage.manifolds.differentiable.degenerate import DegenerateManifold + from sage.manifolds.differentiable.pseudo_riemannian_submanifold import ( + PseudoRiemannianSubmanifold, + ) from sage.manifolds.topological_submanifold import TopologicalSubmanifold - from sage.manifolds.differentiable.differentiable_submanifold import DifferentiableSubmanifold - from sage.manifolds.differentiable.pseudo_riemannian_submanifold import PseudoRiemannianSubmanifold - from sage.manifolds.differentiable.degenerate_submanifold import DegenerateSubmanifold + from sage.rings.infinity import infinity global _manifold_id diff --git a/src/sage/manifolds/manifold_homset.py b/src/sage/manifolds/manifold_homset.py index c390233ca55..998b755ea6e 100644 --- a/src/sage/manifolds/manifold_homset.py +++ b/src/sage/manifolds/manifold_homset.py @@ -16,7 +16,7 @@ - [Lee2011]_ - [KN1963]_ """ -#****************************************************************************** +# ****************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon # Copyright (C) 2016 Travis Scrimshaw # @@ -25,13 +25,13 @@ # 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 Homset -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation from sage.manifolds.continuous_map import ContinuousMap from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation class TopologicalManifoldHomset(UniqueRepresentation, Homset): @@ -173,12 +173,17 @@ def __init__(self, domain, codomain, name=None, latex_name=None): embedded in the Euclidean plane E^2 to the Euclidean plane E^2 """ from sage.manifolds.manifold import TopologicalManifold + if not isinstance(domain, TopologicalManifold): - raise TypeError("domain = {} is not an ".format(domain) + - "instance of TopologicalManifold") + raise TypeError( + "domain = {} is not an ".format(domain) + + "instance of TopologicalManifold" + ) if not isinstance(codomain, TopologicalManifold): - raise TypeError("codomain = {} is not an ".format(codomain) + - "instance of TopologicalManifold") + raise TypeError( + "codomain = {} is not an ".format(codomain) + + "instance of TopologicalManifold" + ) common_cat = domain.category()._meet_(codomain.category()) Homset.__init__(self, domain, codomain, category=common_cat) if name is None: @@ -187,7 +192,8 @@ def __init__(self, domain, codomain, name=None, latex_name=None): self._name = name if latex_name is None: self._latex_name = r"\mathrm{{Hom}}\left({},{}\right)".format( - domain._latex_name, codomain._latex_name) + domain._latex_name, codomain._latex_name + ) else: self._latex_name = latex_name @@ -211,8 +217,14 @@ def _latex_(self): #### Parent methods #### - def _element_constructor_(self, coord_functions, name=None, latex_name=None, - is_isomorphism=False, is_identity=False): + def _element_constructor_( + self, + coord_functions, + name=None, + latex_name=None, + is_isomorphism=False, + is_identity=False, + ): r""" Construct an element of the homset, i.e. a continuous map `M \to N`, where `M` is the domain of the homset and `N` its codomain. @@ -266,10 +278,14 @@ def _element_constructor_(self, coord_functions, name=None, latex_name=None, (x, y) ↦ (x, y) """ # Standard construction - return self.element_class(self, coord_functions=coord_functions, - name=name, latex_name=latex_name, - is_isomorphism=is_isomorphism, - is_identity=is_identity) + return self.element_class( + self, + coord_functions=coord_functions, + name=name, + latex_name=latex_name, + is_isomorphism=is_isomorphism, + is_identity=is_identity, + ) def _an_element_(self): r""" @@ -330,8 +346,9 @@ def _coerce_map_from_(self, other): True """ if isinstance(other, TopologicalManifoldHomset): - return (other.domain().has_coerce_map_from(self.domain()) - and self.codomain().has_coerce_map_from(other.codomain())) + return other.domain().has_coerce_map_from( + self.domain() + ) and self.codomain().has_coerce_map_from(other.codomain()) return False #!# check diff --git a/src/sage/manifolds/operators.py b/src/sage/manifolds/operators.py index eed5df22eb5..6fff6a3a654 100644 --- a/src/sage/manifolds/operators.py +++ b/src/sage/manifolds/operators.py @@ -33,7 +33,7 @@ - Eric Gourgoulhon (2018): initial version """ -#***************************************************************************** +# ***************************************************************************** # Copyright (C) 2018 Eric Gourgoulhon # # This program is free software: you can redistribute it and/or modify @@ -41,7 +41,7 @@ # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# ***************************************************************************** def grad(scalar): @@ -354,4 +354,5 @@ def dalembertian(field): """ return field.dalembertian() + # NB: norm() is already defined in src/sage/misc/functional.py diff --git a/src/sage/manifolds/point.py b/src/sage/manifolds/point.py index b3647cc1447..ca10cb5c767 100644 --- a/src/sage/manifolds/point.py +++ b/src/sage/manifolds/point.py @@ -87,10 +87,10 @@ # https://www.gnu.org/licenses/ #***************************************************************************** -from sage.structure.element import Element from sage.misc.decorators import options -from sage.symbolic.expression import Expression from sage.rings.integer_ring import ZZ +from sage.structure.element import Element +from sage.symbolic.expression import Expression class ManifoldPoint(Element): @@ -935,11 +935,11 @@ def plot(self, chart=None, ambient_coords=None, mapping=None, gX = X.plot(X, ambient_coords=(y,z)) sphinx_plot(g+gX) """ - from sage.plot.point import point2d - from sage.plot.text import text + from sage.manifolds.chart import Chart from sage.plot.graphics import Graphics from sage.plot.plot3d.shapes2 import point3d, text3d - from sage.manifolds.chart import Chart + from sage.plot.point import point2d + from sage.plot.text import text if self._manifold.base_field_type() != 'real': raise NotImplementedError('plot of points on manifolds over fields different' ' from the real field is not implemented') diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py index 62c728ff5bb..7b850a4b1a4 100644 --- a/src/sage/manifolds/scalarfield.py +++ b/src/sage/manifolds/scalarfield.py @@ -40,16 +40,20 @@ # ***************************************************************************** from __future__ import annotations -from typing import Optional, TYPE_CHECKING -from sage.structure.element import (CommutativeAlgebraElement, - ModuleElementWithMutability) -from sage.symbolic.expression import Expression + +from typing import TYPE_CHECKING, Optional + from sage.manifolds.chart_func import ChartFunction from sage.misc.cachefunc import cached_method +from sage.structure.element import ( + CommutativeAlgebraElement, + ModuleElementWithMutability, +) +from sage.symbolic.expression import Expression if TYPE_CHECKING: - from sage.tensor.modules.format_utilities import FormattedExpansion from sage.manifolds.chart import Chart + from sage.tensor.modules.format_utilities import FormattedExpansion class ScalarField(CommutativeAlgebraElement, ModuleElementWithMutability): @@ -2135,11 +2139,13 @@ def display(self, chart: Optional[Chart] = None) -> FormattedExpansion: \begin{array}{llcl} f:& M & \longrightarrow & \mathbb{R} \\ \text{on}\ U : & \left(x, y\right) & \longmapsto & y^{2} \end{array} """ from sage.misc.latex import latex - from sage.typeset.unicode_characters import (unicode_to, - unicode_mapsto, - unicode_mathbbR, - unicode_mathbbC) from sage.tensor.modules.format_utilities import FormattedExpansion + from sage.typeset.unicode_characters import ( + unicode_mapsto, + unicode_mathbbC, + unicode_mathbbR, + unicode_to, + ) def _display_expression(self, chart, result): r""" @@ -2764,8 +2770,10 @@ def _mul_(self, other): if other.is_trivial_one(): return self # Generic case: - from sage.tensor.modules.format_utilities import (format_mul_txt, - format_mul_latex) + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) com_charts = self.common_charts(other) if com_charts is None: raise ValueError("no common chart for the multiplication") @@ -2809,8 +2817,10 @@ def _div_(self, other): ... ZeroDivisionError: division of a scalar field by zero """ - from sage.tensor.modules.format_utilities import format_mul_txt, \ - format_mul_latex + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) # Trivial cases: if other.is_trivial_zero(): raise ZeroDivisionError("division of a scalar field by zero") diff --git a/src/sage/manifolds/scalarfield_algebra.py b/src/sage/manifolds/scalarfield_algebra.py index 960b4514387..d4a01098eaf 100644 --- a/src/sage/manifolds/scalarfield_algebra.py +++ b/src/sage/manifolds/scalarfield_algebra.py @@ -30,13 +30,13 @@ # http://www.gnu.org/licenses/ #****************************************************************************** -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation -from sage.misc.cachefunc import cached_method from sage.categories.commutative_algebras import CommutativeAlgebras from sage.categories.topological_spaces import TopologicalSpaces -from sage.symbolic.ring import SymbolicRing, SR from sage.manifolds.scalarfield import ScalarField +from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.symbolic.ring import SR, SymbolicRing class ScalarFieldAlgebra(UniqueRepresentation, Parent): @@ -518,7 +518,7 @@ def _coerce_map_from_(self, other): sage: CU._coerce_map_from_(CM) True """ - from .chart_func import ChartFunctionRing + from sage.manifolds.chart_func import ChartFunctionRing if isinstance(other, SymbolicRing): return True # coercion from the base ring (multiplication by the # algebra unit, i.e. self.one()) diff --git a/src/sage/manifolds/section.py b/src/sage/manifolds/section.py index 75af42a57e5..77d8f881ee1 100644 --- a/src/sage/manifolds/section.py +++ b/src/sage/manifolds/section.py @@ -19,11 +19,11 @@ # the License, or (at your option) any later version. # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.rings.integer import Integer +from sage.rings.integer_ring import ZZ from sage.structure.element import ModuleElementWithMutability from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement from sage.tensor.modules.tensor_with_indices import TensorWithIndices -from sage.rings.integer import Integer -from sage.rings.integer_ring import ZZ class Section(ModuleElementWithMutability): @@ -2213,8 +2213,10 @@ def _rmul_(self, scalar): return self.copy() ### # General case: - from sage.tensor.modules.format_utilities import (format_mul_txt, - format_mul_latex) + from sage.tensor.modules.format_utilities import ( + format_mul_latex, + format_mul_txt, + ) resu = self._new_instance() for dom, rst in self._restrictions.items(): resu._restrictions[dom] = scalar.restrict(dom) * rst diff --git a/src/sage/manifolds/section_module.py b/src/sage/manifolds/section_module.py index 6192045f45a..bace0b29866 100644 --- a/src/sage/manifolds/section_module.py +++ b/src/sage/manifolds/section_module.py @@ -26,13 +26,13 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.categories.modules import Modules +from sage.manifolds.section import Section, TrivialSection +from sage.misc.cachefunc import cached_method from sage.rings.infinity import infinity -from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent -from sage.misc.cachefunc import cached_method -from sage.categories.modules import Modules +from sage.structure.unique_representation import UniqueRepresentation from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule -from sage.manifolds.section import Section, TrivialSection class SectionModule(UniqueRepresentation, Parent): @@ -467,7 +467,7 @@ def set_default_frame(self, basis): sage: C0.default_frame().domain() Open subset U of the 3-dimensional topological manifold M """ - from .local_frame import LocalFrame + from sage.manifolds.local_frame import LocalFrame if not isinstance(basis, LocalFrame): raise ValueError("the argument is not a local frame") elif not basis._domain.is_subset(self._domain): @@ -587,7 +587,7 @@ def __init__(self, vbundle, domain): True sage: TestSuite(C0).run() """ - from .scalarfield import ScalarField + from sage.manifolds.scalarfield import ScalarField self._domain = domain name = "C^0({};{})".format(domain._name, vbundle._name) latex_name = r'C^0({};{})'.format(domain._latex_name, diff --git a/src/sage/manifolds/structure.py b/src/sage/manifolds/structure.py index ed166b6438a..6d0797c062d 100644 --- a/src/sage/manifolds/structure.py +++ b/src/sage/manifolds/structure.py @@ -23,15 +23,13 @@ # http://www.gnu.org/licenses/ #***************************************************************************** -from sage.misc.fast_methods import Singleton from sage.manifolds.chart import Chart, RealChart -from sage.manifolds.scalarfield_algebra import ScalarFieldAlgebra -from sage.manifolds.manifold_homset import TopologicalManifoldHomset from sage.manifolds.differentiable.chart import DiffChart, RealDiffChart -from sage.manifolds.differentiable.scalarfield_algebra import \ - DiffScalarFieldAlgebra -from sage.manifolds.differentiable.manifold_homset import \ - DifferentiableManifoldHomset +from sage.manifolds.differentiable.manifold_homset import DifferentiableManifoldHomset +from sage.manifolds.differentiable.scalarfield_algebra import DiffScalarFieldAlgebra +from sage.manifolds.manifold_homset import TopologicalManifoldHomset +from sage.manifolds.scalarfield_algebra import ScalarFieldAlgebra +from sage.misc.fast_methods import Singleton # This is a slight abuse by making this a Singleton, but there is no # need to have different copies of this object. diff --git a/src/sage/manifolds/subset.py b/src/sage/manifolds/subset.py index 453fa02de2f..b0552238afa 100644 --- a/src/sage/manifolds/subset.py +++ b/src/sage/manifolds/subset.py @@ -65,15 +65,17 @@ # http://www.gnu.org/licenses/ #***************************************************************************** from __future__ import annotations -from typing import Optional -from collections import defaultdict + import itertools -from sage.structure.parent import Parent -from sage.structure.unique_representation import UniqueRepresentation -from sage.misc.superseded import deprecation +from collections import defaultdict +from typing import Optional + from sage.categories.sets_cat import Sets from sage.manifolds.family import ManifoldObjectFiniteFamily, ManifoldSubsetFiniteFamily from sage.manifolds.point import ManifoldPoint +from sage.misc.superseded import deprecation +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation class ManifoldSubset(UniqueRepresentation, Parent): @@ -1891,7 +1893,7 @@ def declare_closed(self): if self.is_closed(): return self.complement(is_open=True) - from .subsets.closure import ManifoldSubsetClosure + from sage.manifolds.subsets.closure import ManifoldSubsetClosure for closure in self.manifold().subsets(): if isinstance(closure, ManifoldSubsetClosure): if closure._subset.is_subset(self): @@ -2755,7 +2757,7 @@ def closure(self, name=None, latex_name=None): """ if self.is_closed(): return self - from .subsets.closure import ManifoldSubsetClosure + from sage.manifolds.subsets.closure import ManifoldSubsetClosure return ManifoldSubsetClosure(self, name=name, latex_name=latex_name) #### End of construction of new sets from self diff --git a/src/sage/manifolds/subsets/pullback.py b/src/sage/manifolds/subsets/pullback.py index d62f9936368..2d499892e35 100644 --- a/src/sage/manifolds/subsets/pullback.py +++ b/src/sage/manifolds/subsets/pullback.py @@ -13,23 +13,23 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.categories.sets_cat import Sets, EmptySetError +import sage.geometry.abc from sage.categories.metric_spaces import MetricSpaces +from sage.categories.sets_cat import EmptySetError, Sets +from sage.manifolds.chart import Chart +from sage.manifolds.scalarfield import ScalarField +from sage.manifolds.subset import ManifoldSubset from sage.misc.lazy_import import lazy_import from sage.modules.free_module import FreeModule_generic +from sage.modules.free_module_element import vector +from sage.rings.complex_double import CDF from sage.rings.infinity import infinity, minus_infinity from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.complex_double import CDF from sage.rings.real_double import RDF from sage.rings.real_lazy import CLF, RLF -from sage.symbolic.ring import SR -from sage.modules.free_module_element import vector -from sage.manifolds.subset import ManifoldSubset -from sage.manifolds.chart import Chart -from sage.manifolds.scalarfield import ScalarField from sage.sets.real_set import RealSet -import sage.geometry.abc +from sage.symbolic.ring import SR lazy_import('sage.geometry.relative_interior', 'RelativeInterior') @@ -307,7 +307,7 @@ def _is_open(codomain_subset): if hasattr(codomain_subset, 'minimized_constraints'): try: - from ppl import NNC_Polyhedron, C_Polyhedron + from ppl import C_Polyhedron, NNC_Polyhedron except ImportError: pass else: @@ -837,7 +837,7 @@ def is_closed(self): else: if hasattr(self._codomain_subset, 'is_topologically_closed'): try: - from ppl import NNC_Polyhedron, C_Polyhedron + from ppl import C_Polyhedron, NNC_Polyhedron except ImportError: pass else: diff --git a/src/sage/manifolds/topological_submanifold.py b/src/sage/manifolds/topological_submanifold.py index a99e6d1fca1..9ea40b0f621 100644 --- a/src/sage/manifolds/topological_submanifold.py +++ b/src/sage/manifolds/topological_submanifold.py @@ -45,11 +45,12 @@ # http://www.gnu.org/licenses/ # ***************************************************************************** -from sage.manifolds.manifold import TopologicalManifold from sage.manifolds.continuous_map import ContinuousMap -from sage.symbolic.expression import Expression -from sage.symbolic.assumptions import assumptions, assume +from sage.manifolds.manifold import TopologicalManifold from sage.misc.lazy_import import lazy_import +from sage.symbolic.assumptions import assume, assumptions +from sage.symbolic.expression import Expression + lazy_import("sage.plot.plot3d.parametric_surface", "ParametricSurface") ############################################################################# diff --git a/src/sage/manifolds/trivialization.py b/src/sage/manifolds/trivialization.py index 4c718db8ffe..5898d38a089 100644 --- a/src/sage/manifolds/trivialization.py +++ b/src/sage/manifolds/trivialization.py @@ -20,9 +20,9 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.manifolds.local_frame import TrivializationFrame from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation -from sage.manifolds.local_frame import TrivializationFrame class Trivialization(UniqueRepresentation, SageObject): diff --git a/src/sage/manifolds/utilities.py b/src/sage/manifolds/utilities.py index 190213eeb41..e2a01a1416a 100644 --- a/src/sage/manifolds/utilities.py +++ b/src/sage/manifolds/utilities.py @@ -27,14 +27,15 @@ # **************************************************************************** from operator import pow as _pow -from sage.symbolic.expression import Expression -from sage.symbolic.expression_conversions import ExpressionTreeWalker -from sage.symbolic.ring import SR -from sage.symbolic.constants import pi + from sage.functions.other import abs_symbolic -from sage.misc.functional import sqrt from sage.functions.trig import cos, sin +from sage.misc.functional import sqrt from sage.rings.rational import Rational +from sage.symbolic.constants import pi +from sage.symbolic.expression import Expression +from sage.symbolic.expression_conversions import ExpressionTreeWalker +from sage.symbolic.ring import SR class SimplifySqrtReal(ExpressionTreeWalker): @@ -991,6 +992,7 @@ def _repr_(self): d = d.replace(o, res) import re + from sage.manifolds.manifold import TopologicalManifold if TopologicalManifold.options.omit_function_arguments: list_f = [] @@ -1144,6 +1146,7 @@ def _list_derivatives(ex, list_d, exponent=0): operands = ex.operands() import operator + from sage.misc.latex import latex, latex_variable_name from sage.symbolic.operators import FDerivativeOperator diff --git a/src/sage/manifolds/vector_bundle.py b/src/sage/manifolds/vector_bundle.py index ad830d68469..ebc5e652e14 100644 --- a/src/sage/manifolds/vector_bundle.py +++ b/src/sage/manifolds/vector_bundle.py @@ -32,14 +32,14 @@ # https://www.gnu.org/licenses/ #****************************************************************************** -from sage.structure.category_object import CategoryObject -from sage.categories.vector_bundles import VectorBundles -from sage.structure.unique_representation import UniqueRepresentation import sage.rings.abc +from sage.categories.vector_bundles import VectorBundles +from sage.manifolds.vector_bundle_fiber import VectorBundleFiber from sage.rings.cc import CC -from sage.rings.real_mpfr import RR from sage.rings.integer import Integer -from sage.manifolds.vector_bundle_fiber import VectorBundleFiber +from sage.rings.real_mpfr import RR +from sage.structure.category_object import CategoryObject +from sage.structure.unique_representation import UniqueRepresentation class TopologicalVectorBundle(CategoryObject, UniqueRepresentation): @@ -437,7 +437,7 @@ def trivialization(self, name, domain=None, latex_name=None): """ if domain is None: domain = self._base_space - from .trivialization import Trivialization + from sage.manifolds.trivialization import Trivialization return Trivialization(self, name, domain=domain, latex_name=latex_name) def transitions(self): @@ -638,8 +638,7 @@ def section_module(self, domain=None, force_free=False): """ if domain is None: domain = self._base_space - from sage.manifolds.section_module import (SectionModule, - SectionFreeModule) + from sage.manifolds.section_module import SectionFreeModule, SectionModule if domain not in self._section_modules: if force_free or domain in self._trivial_parts: self._section_modules[domain] = SectionFreeModule(self, domain) @@ -928,8 +927,7 @@ def set_change_of_frame(self, frame1, frame2, change_of_frame, [1 2] [0 3] """ - from sage.tensor.modules.free_module_automorphism import \ - FreeModuleAutomorphism + from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism sec_module = frame1._fmodule if frame2._fmodule != sec_module: raise ValueError("the two frames are not defined on the same " + @@ -1154,7 +1152,7 @@ def set_orientation(self, orientation): [Local frame (E|_U, (e_0,e_1)), Local frame (E|_V, (f_0,f_1))] """ - from .local_frame import LocalFrame + from sage.manifolds.local_frame import LocalFrame if isinstance(orientation, LocalFrame): orientation = [orientation] elif isinstance(orientation, (tuple, list)): diff --git a/src/sage/manifolds/vector_bundle_fiber.py b/src/sage/manifolds/vector_bundle_fiber.py index 325ac1582b2..a7cebfba9f8 100644 --- a/src/sage/manifolds/vector_bundle_fiber.py +++ b/src/sage/manifolds/vector_bundle_fiber.py @@ -17,9 +17,9 @@ # http://www.gnu.org/licenses/ #****************************************************************************** +from sage.manifolds.vector_bundle_fiber_element import VectorBundleFiberElement from sage.symbolic.ring import SR from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule -from sage.manifolds.vector_bundle_fiber_element import VectorBundleFiberElement class VectorBundleFiber(FiniteRankFreeModule): diff --git a/src/sage/matrix/args.pxd b/src/sage/matrix/args.pxd index eda2e428801..ba26cfbafbe 100644 --- a/src/sage/matrix/args.pxd +++ b/src/sage/matrix/args.pxd @@ -12,7 +12,7 @@ cdef enum entries_type: MA_FLAG_SPARSE = 0x20_00 # Sparse by default # types of input entries - MA_ENTRIES_UNKNOWN = 0 # anything + MA_ENTRIES_UNKNOWN = 0 # anything MA_ENTRIES_ZERO = 0x17_01 # zero matrix MA_ENTRIES_SCALAR = 0x17_02 # single scalar value MA_ENTRIES_SEQ_SEQ = 0x10_03 # list of lists diff --git a/src/sage/matrix/matrix0.pyx b/src/sage/matrix/matrix0.pyx index 615d7ac55f7..0c04c74b4af 100644 --- a/src/sage/matrix/matrix0.pyx +++ b/src/sage/matrix/matrix0.pyx @@ -1019,7 +1019,7 @@ cdef class Matrix(sage.structure.element.Matrix): if ind < 0 or ind >= ncols: raise IndexError("matrix index out of range") elif isinstance(col_index, slice): - col_list = list(range(*col_index.indices(ncols))) + col_list = list(range(*col_index.indices(ncols))) else: if not PyIndex_Check(col_index): raise TypeError("index must be an integer") diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index d2f0815e81e..852d749e1e6 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -3056,7 +3056,7 @@ cdef class Matrix(Matrix1): ALGORITHM: - If the base ring has a method `_matrix_charpoly`, we use it. + If the base ring has a method ``_matrix_charpoly``, we use it. In the generic case of matrices over a ring (commutative and with unity), there is a division-free algorithm, which can be accessed @@ -4659,11 +4659,13 @@ cdef class Matrix(Matrix1): algorithm = 'default' elif algorithm not in ['default', 'generic', 'flint', 'pari', 'padic', 'pluq']: raise ValueError("matrix kernel algorithm '%s' not recognized" % algorithm) - elif algorithm == 'padic' and not (isinstance(R, IntegerRing_class) or isinstance(R, RationalField)): + elif algorithm == 'padic' and not isinstance(R, (IntegerRing_class, + RationalField)): raise ValueError("'padic' matrix kernel algorithm only available over the rationals and the integers, not over %s" % R) - elif algorithm == 'flint' and not (isinstance(R, IntegerRing_class) or isinstance(R, RationalField)): + elif algorithm == 'flint' and not isinstance(R, (IntegerRing_class, + RationalField)): raise ValueError("'flint' matrix kernel algorithm only available over the rationals and the integers, not over %s" % R) - elif algorithm == 'pari' and not (isinstance(R, IntegerRing_class) or (isinstance(R, NumberField) and not isinstance(R, RationalField))): + elif algorithm == 'pari' and not (isinstance(R, (IntegerRing_class, NumberField)) and not isinstance(R, RationalField)): raise ValueError("'pari' matrix kernel algorithm only available over non-trivial number fields and the integers, not over %s" % R) elif algorithm == 'generic' and R not in _Fields: raise ValueError("'generic' matrix kernel algorithm only available over a field, not over %s" % R) @@ -5391,9 +5393,7 @@ cdef class Matrix(Matrix1): [0 0 0] [0 0 0] sage: W = T.kernel_on(V); W.basis() - [ - (0, 1, 0) - ] + [(0, 1, 0)] sage: W.is_submodule(V) True """ @@ -5661,22 +5661,21 @@ cdef class Matrix(Matrix1): [264 275 286 297 308 319] [330 341 352 363 374 385] sage: A.decomposition() # needs sage.libs.pari - [ (Ambient free module of rank 4 - over the principal ideal domain Integer Ring, - True) ] + [(Ambient free module of rank 4 over the principal ideal domain Integer Ring, + True)] sage: B.decomposition() # needs sage.libs.pari - [ (Vector space of degree 6 and dimension 2 over Rational Field - Basis matrix: - [ 1 0 -1 -2 -3 -4] - [ 0 1 2 3 4 5], - True), - (Vector space of degree 6 and dimension 4 over Rational Field - Basis matrix: - [ 1 0 0 0 -5 4] - [ 0 1 0 0 -4 3] - [ 0 0 1 0 -3 2] - [ 0 0 0 1 -2 1], - False) ] + [(Vector space of degree 6 and dimension 2 over Rational Field + Basis matrix: + [ 1 0 -1 -2 -3 -4] + [ 0 1 2 3 4 5], + True), + (Vector space of degree 6 and dimension 4 over Rational Field + Basis matrix: + [ 1 0 0 0 -5 4] + [ 0 1 0 0 -4 3] + [ 0 0 1 0 -3 2] + [ 0 0 0 1 -2 1], + False)] """ if algorithm == 'kernel' or self.base_ring() not in _Fields: return self._decomposition_using_kernels(is_diagonalizable=is_diagonalizable, dual=dual) @@ -5862,12 +5861,14 @@ cdef class Matrix(Matrix1): [0 1 0] [0 0 1] sage: D = t.decomposition_of_subspace(v); D - [ (Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: [0 0 1], - True), - (Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: [0 1 0], - True) ] + [(Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: + [0 0 1], + True), + (Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: + [0 1 0], + True)] sage: t.restrict(D[0][0]) [0] sage: t.restrict(D[1][0]) @@ -5882,18 +5883,18 @@ cdef class Matrix(Matrix1): ....: 0, 2, 0, -2, -2, 0, ....: 0, 2, 0, -2, 0, 0]) sage: a.decomposition_of_subspace(ZZ^6) # needs sage.libs.pari - [ (Free module of degree 6 and rank 2 over Integer Ring - Echelon basis matrix: - [ 1 0 1 -1 1 -1] - [ 0 1 0 -1 2 -1], - False), - (Free module of degree 6 and rank 4 over Integer Ring - Echelon basis matrix: - [ 1 0 -1 0 1 0] - [ 0 1 0 0 0 0] - [ 0 0 0 1 0 0] - [ 0 0 0 0 0 1], - False) ] + [(Free module of degree 6 and rank 2 over Integer Ring + Echelon basis matrix: + [ 1 0 1 -1 1 -1] + [ 0 1 0 -1 2 -1], + False), + (Free module of degree 6 and rank 4 over Integer Ring + Echelon basis matrix: + [ 1 0 -1 0 1 0] + [ 0 1 0 0 0 0] + [ 0 0 0 1 0 0] + [ 0 0 0 0 0 1], + False)] TESTS:: @@ -6317,43 +6318,41 @@ cdef class Matrix(Matrix1): [3 4 5] [6 7 8] sage: es = A.eigenspaces_left(format='all'); es # needs sage.rings.number_field - [ (0, - Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (-1.348469228349535?, - Vector space of degree 3 and dimension 1 over Algebraic Field - User basis matrix: - [ 1 0.3101020514433644? -0.3797958971132713?]), - (13.34846922834954?, - Vector space of degree 3 and dimension 1 over Algebraic Field - User basis matrix: - [ 1 1.289897948556636? 1.579795897113272?]) ] + [(0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (-1.348469228349535?, + Vector space of degree 3 and dimension 1 over Algebraic Field + User basis matrix: + [ 1 0.3101020514433644? -0.3797958971132713?]), + (13.34846922834954?, + Vector space of degree 3 and dimension 1 over Algebraic Field + User basis matrix: + [ 1 1.289897948556636? 1.579795897113272?])] sage: # needs sage.rings.number_field sage: es = A.eigenspaces_left(format='galois'); es - [ (0, - Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (a1, - Vector space of degree 3 and dimension 1 over - Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5]) ] + [(0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (a1, + Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5])] sage: es = A.eigenspaces_left(format='galois', ....: algebraic_multiplicity=True); es - [ (0, - Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1], - 1), - (a1, - Vector space of degree 3 and dimension 1 over - Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5], - 1) ] + [(0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1], + 1), + (a1, + Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5], + 1)] sage: e, v, n = es[0]; v = v.basis()[0] sage: delta = e*v - v*A sage: abs(abs(delta)) < 1e-10 @@ -6366,15 +6365,14 @@ cdef class Matrix(Matrix1): [3 4 5] [6 7 8] sage: A.eigenspaces_left(format='galois') # needs sage.rings.number_field - [ (0, - Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (a1, - Vector space of degree 3 and dimension 1 over - Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5]) ] + [(0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (a1, + Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/15*a1 + 2/5 2/15*a1 - 1/5])] We compute the left eigenspaces of the matrix of the Hecke operator `T_2` on level 43 modular symbols, both with all eigenvalues (the default) @@ -6396,48 +6394,47 @@ cdef class Matrix(Matrix1): sage: factor(f) (x - 3) * (x + 2)^2 * (x^2 - 2)^2 sage: A.eigenspaces_left(algebraic_multiplicity=True) - [ (3, - Vector space of degree 7 and dimension 1 over Rational Field - User basis matrix: - [ 1 0 1/7 0 -1/7 0 -2/7], - 1), - (-2, - Vector space of degree 7 and dimension 2 over Rational Field - User basis matrix: - [ 0 1 0 1 -1 1 -1] - [ 0 0 1 0 -1 2 -1], - 2), - (-1.414213562373095?, - Vector space of degree 7 and dimension 2 over Algebraic Field - User basis matrix: - [ 0 1 0 -1 0.4142135623730951? 1 -1] - [ 0 0 1 0 -1 0 2.414213562373095?], - 2), - (1.414213562373095?, - Vector space of degree 7 and dimension 2 over Algebraic Field - User basis matrix: - [ 0 1 0 -1 -2.414213562373095? 1 -1] - [ 0 0 1 0 -1 0 -0.4142135623730951?], - 2) ] + [(3, + Vector space of degree 7 and dimension 1 over Rational Field + User basis matrix: + [ 1 0 1/7 0 -1/7 0 -2/7], + 1), + (-2, + Vector space of degree 7 and dimension 2 over Rational Field + User basis matrix: + [ 0 1 0 1 -1 1 -1] + [ 0 0 1 0 -1 2 -1], + 2), + (-1.414213562373095?, + Vector space of degree 7 and dimension 2 over Algebraic Field + User basis matrix: + [ 0 1 0 -1 0.4142135623730951? 1 -1] + [ 0 0 1 0 -1 0 2.414213562373095?], + 2), + (1.414213562373095?, + Vector space of degree 7 and dimension 2 over Algebraic Field + User basis matrix: + [ 0 1 0 -1 -2.414213562373095? 1 -1] + [ 0 0 1 0 -1 0 -0.4142135623730951?], + 2)] sage: A.eigenspaces_left(format='galois', algebraic_multiplicity=True) - [ (3, - Vector space of degree 7 and dimension 1 over Rational Field - User basis matrix: - [ 1 0 1/7 0 -1/7 0 -2/7], - 1), - (-2, - Vector space of degree 7 and dimension 2 over Rational Field - User basis matrix: - [ 0 1 0 1 -1 1 -1] - [ 0 0 1 0 -1 2 -1], - 2), - (a2, - Vector space of degree 7 and dimension 2 - over Number Field in a2 with defining polynomial x^2 - 2 - User basis matrix: - [ 0 1 0 -1 -a2 - 1 1 -1] - [ 0 0 1 0 -1 0 -a2 + 1], - 2) ] + [(3, + Vector space of degree 7 and dimension 1 over Rational Field + User basis matrix: + [ 1 0 1/7 0 -1/7 0 -2/7], + 1), + (-2, + Vector space of degree 7 and dimension 2 over Rational Field + User basis matrix: + [ 0 1 0 1 -1 1 -1] + [ 0 0 1 0 -1 2 -1], + 2), + (a2, + Vector space of degree 7 and dimension 2 over Number Field in a2 with defining polynomial x^2 - 2 + User basis matrix: + [ 0 1 0 -1 -a2 - 1 1 -1] + [ 0 0 1 0 -1 0 -a2 + 1], + 2)] Next we compute the left eigenspaces over the finite field of order 11. :: @@ -6452,16 +6449,18 @@ cdef class Matrix(Matrix1): sage: A.charpoly() x^4 + 10*x^3 + 3*x^2 + 2*x + 1 sage: A.eigenspaces_left(format='galois', var='beta') - [ (9, - Vector space of degree 4 and dimension 1 over Finite Field of size 11 - User basis matrix: [0 1 5 6]), - (3, Vector space of degree 4 and dimension 1 over Finite Field of size 11 - User basis matrix: [1 0 1 6]), - (beta2, Vector space of degree 4 and dimension 1 - over Univariate Quotient Polynomial Ring in beta2 - over Finite Field of size 11 with modulus x^2 + 9 - User basis matrix: [ 0 0 1 beta2 + 1]) - ] + [(9, + Vector space of degree 4 and dimension 1 over Finite Field of size 11 + User basis matrix: + [0 1 5 6]), + (3, + Vector space of degree 4 and dimension 1 over Finite Field of size 11 + User basis matrix: + [1 0 1 6]), + (beta2, + Vector space of degree 4 and dimension 1 over Univariate Quotient Polynomial Ring in beta2 over Finite Field of size 11 with modulus x^2 + 9 + User basis matrix: + [ 0 0 1 beta2 + 1])] This method is only applicable to exact matrices. The "eigenmatrix" routines for matrices with double-precision @@ -6514,13 +6513,10 @@ cdef class Matrix(Matrix1): NotImplementedError: unable to construct eigenspaces for eigenvalues outside the base field, try the keyword option: format='galois' sage: A.eigenspaces_left(format='galois') # needs sage.rings.number_field - [ (a0, - Vector space of degree 2 and dimension 1 over - Univariate Quotient Polynomial Ring in a0 over - Finite Field in b of size 11^2 - with modulus x^2 + (5*b + 6)*x + 8*b + 10 - User basis matrix: - [ 1 6*b*a0 + 3*b + 1]) ] + [(a0, + Vector space of degree 2 and dimension 1 over Univariate Quotient Polynomial Ring in a0 over Finite Field in b of size 11^2 with modulus x^2 + (5*b + 6)*x + 8*b + 10 + User basis matrix: + [ 1 6*b*a0 + 3*b + 1])] TESTS: @@ -6688,41 +6684,39 @@ cdef class Matrix(Matrix1): [3 4 5] [6 7 8] sage: A.eigenspaces_right() - [ (0, - Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (-1.348469228349535?, - Vector space of degree 3 and dimension 1 over Algebraic Field - User basis matrix: - [ 1 0.1303061543300932? -0.7393876913398137?]), - (13.34846922834954?, - Vector space of degree 3 and dimension 1 over Algebraic Field - User basis matrix: - [ 1 3.069693845669907? 5.139387691339814?]) ] + [(0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (-1.348469228349535?, + Vector space of degree 3 and dimension 1 over Algebraic Field + User basis matrix: + [ 1 0.1303061543300932? -0.7393876913398137?]), + (13.34846922834954?, + Vector space of degree 3 and dimension 1 over Algebraic Field + User basis matrix: + [ 1 3.069693845669907? 5.139387691339814?])] sage: es = A.eigenspaces_right(format='galois'); es - [ (0, - Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (a1, - Vector space of degree 3 and dimension 1 over - Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5]) ] + [(0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (a1, + Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5])] sage: es = A.eigenspaces_right(format='galois', ....: algebraic_multiplicity=True); es - [ (0, - Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1], - 1), - (a1, - Vector space of degree 3 and dimension 1 over - Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5], - 1) ] + [(0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1], + 1), + (a1, + Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5], + 1)] sage: e, v, n = es[0]; v = v.basis()[0] sage: delta = v*e - A*v sage: abs(abs(delta)) < 1e-10 @@ -6735,15 +6729,14 @@ cdef class Matrix(Matrix1): [3 4 5] [6 7 8] sage: A.eigenspaces_right(format='galois') # needs sage.rings.number_field - [ (0, - Vector space of degree 3 and dimension 1 over Rational Field - User basis matrix: - [ 1 -2 1]), - (a1, - Vector space of degree 3 and dimension 1 over - Number Field in a1 with defining polynomial x^2 - 12*x - 18 - User basis matrix: - [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5]) ] + [(0, + Vector space of degree 3 and dimension 1 over Rational Field + User basis matrix: + [ 1 -2 1]), + (a1, + Vector space of degree 3 and dimension 1 over Number Field in a1 with defining polynomial x^2 - 12*x - 18 + User basis matrix: + [ 1 1/5*a1 + 2/5 2/5*a1 - 1/5])] This method is only applicable to exact matrices. The "eigenmatrix" routines for matrices with double-precision @@ -7004,7 +6997,7 @@ cdef class Matrix(Matrix1): [3 4 5] [6 7 8] sage: es = A.eigenvectors_left(); es - [(0, [ (1, -2, 1) ], 1), + [(0, [(1, -2, 1)], 1), (-1.348469228349535?, [(1, 0.3101020514433644?, -0.3797958971132713?)], 1), (13.34846922834954?, [(1, 1.289897948556636?, 1.579795897113272?)], 1)] sage: eval, [evec], mult = es[0] @@ -7018,11 +7011,9 @@ cdef class Matrix(Matrix1): sage: M = matrix(QQ, [[0,-1,0], [1,0,0], [0,0,2]]) sage: M.eigenvectors_left() # needs sage.rings.number_field - [(2, [ (0, 0, 1) ], 1), - (-1*I, [(1, -1*I, 0)], 1), - (1*I, [(1, 1*I, 0)], 1)] + [(2, [(0, 0, 1)], 1), (-1*I, [(1, -1*I, 0)], 1), (1*I, [(1, 1*I, 0)], 1)] sage: M.eigenvectors_left(extend=False) # needs sage.rings.number_field - [(2, [ (0, 0, 1) ], 1)] + [(2, [(0, 0, 1)], 1)] TESTS:: @@ -7135,11 +7126,11 @@ cdef class Matrix(Matrix1): [3 4 5] [6 7 8] sage: es = A.eigenvectors_right(); es - [(0, [ (1, -2, 1) ], 1), + [(0, [(1, -2, 1)], 1), (-1.348469228349535?, [(1, 0.1303061543300932?, -0.7393876913398137?)], 1), (13.34846922834954?, [(1, 3.069693845669907?, 5.139387691339814?)], 1)] sage: A.eigenvectors_right(extend=False) - [(0, [ (1, -2, 1) ], 1)] + [(0, [(1, -2, 1)], 1)] sage: eval, [evec], mult = es[0] sage: delta = eval*evec - A*evec sage: abs(abs(delta)) < 1e-10 @@ -14520,7 +14511,7 @@ cdef class Matrix(Matrix1): # Continuing the "else" branch of Higham's Step (1), and # onto B&K's Step (3) where we find the largest - # off-diagonal entry (in magniture) in column "r". Since + # off-diagonal entry (in magnitude) in column "r". Since # the matrix is Hermitian, we need only look at the # above-diagonal entries to find the off-diagonal of # maximal magnitude. @@ -15901,7 +15892,7 @@ cdef class Matrix(Matrix1): sage: a.exp() # needs sage.symbolic [ 1/11882424341266*((11*sqrt(227345670387496707609) + 5941212170633)*e^(3/1275529100*sqrt(227345670387496707609)) - 11*sqrt(227345670387496707609) + 5941212170633)*e^(-3/2551058200*sqrt(227345670387496707609) + 101/200) 445243650/75781890129165569203*(sqrt(227345670387496707609)*e^(3/1275529100*sqrt(227345670387496707609)) - sqrt(227345670387496707609))*e^(-3/2551058200*sqrt(227345670387496707609) + 101/200)] [ 10000/53470909535697*(sqrt(227345670387496707609)*e^(3/1275529100*sqrt(227345670387496707609)) - sqrt(227345670387496707609))*e^(-3/2551058200*sqrt(227345670387496707609) + 101/200) -1/11882424341266*((11*sqrt(227345670387496707609) - 5941212170633)*e^(3/1275529100*sqrt(227345670387496707609)) - 11*sqrt(227345670387496707609) - 5941212170633)*e^(-3/2551058200*sqrt(227345670387496707609) + 101/200)] - sage: a.change_ring(RDF).exp() # rel tol 6e-14 # needs sage.symbolic + sage: a.change_ring(RDF).exp() # rel tol 1e-13 # needs sage.symbolic [42748127.31532951 7368259.244159399] [234538976.1381042 40426191.45156228] @@ -18621,10 +18612,8 @@ def decomp_seq(v): sage: from sage.matrix.matrix2 import decomp_seq sage: V = [(QQ^3, 2), (QQ^2, 1)] sage: decomp_seq(V) - [ - (Vector space of dimension 2 over Rational Field, 1), - (Vector space of dimension 3 over Rational Field, 2) - ] + [(Vector space of dimension 2 over Rational Field, 1), + (Vector space of dimension 3 over Rational Field, 2)] """ list.sort(v, key=lambda x: x[0].dimension()) return Sequence(v, universe=tuple, check=False, cr=True) diff --git a/src/sage/matrix/matrix_cyclo_dense.pxd b/src/sage/matrix/matrix_cyclo_dense.pxd index 13f72389cf5..1c740082681 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pxd +++ b/src/sage/matrix/matrix_cyclo_dense.pxd @@ -13,4 +13,3 @@ cdef class Matrix_cyclo_dense(Matrix_dense): cdef _randomize_rational_column_unsafe(Matrix_cyclo_dense self, Py_ssize_t col, mpz_t nump1, mpz_t denp1, distribution=?) - diff --git a/src/sage/matrix/matrix_double_dense.pyx b/src/sage/matrix/matrix_double_dense.pyx index 71254649be7..b3ee53e9c37 100644 --- a/src/sage/matrix/matrix_double_dense.pyx +++ b/src/sage/matrix/matrix_double_dense.pyx @@ -2396,8 +2396,8 @@ cdef class Matrix_double_dense(Matrix_numpy_dense): r""" Return ``True`` if the matrix is (skew-)Hermitian. - For internal purposes. This function is used in `is_hermitian` - and `is_skew_hermitian` functions. + For internal purposes. This function is used in ``is_hermitian`` + and ``is_skew_hermitian`` functions. INPUT: diff --git a/src/sage/matrix/matrix_gf2e_dense.pyx b/src/sage/matrix/matrix_gf2e_dense.pyx index 431be04a62b..827aa83775d 100644 --- a/src/sage/matrix/matrix_gf2e_dense.pyx +++ b/src/sage/matrix/matrix_gf2e_dense.pyx @@ -908,22 +908,22 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): if algorithm == 'naive': sig_on() - r = mzed_echelonize_naive(self._entries, full) + r = mzed_echelonize_naive(self._entries, full) sig_off() elif algorithm == 'newton_john': sig_on() - r = mzed_echelonize_newton_john(self._entries, full) + r = mzed_echelonize_newton_john(self._entries, full) sig_off() elif algorithm == 'ple': sig_on() - r = mzed_echelonize_ple(self._entries, full) + r = mzed_echelonize_ple(self._entries, full) sig_off() elif algorithm == 'heuristic': sig_on() - r = mzed_echelonize(self._entries, full) + r = mzed_echelonize(self._entries, full) sig_off() elif algorithm == 'builtin': diff --git a/src/sage/matrix/matrix_gfpn_dense.pyx b/src/sage/matrix/matrix_gfpn_dense.pyx index 9d4e113e522..b73013ebcf8 100644 --- a/src/sage/matrix/matrix_gfpn_dense.pyx +++ b/src/sage/matrix/matrix_gfpn_dense.pyx @@ -903,12 +903,12 @@ cdef class Matrix_gfpn_dense(Matrix_dense): else: raise ValueError("Matrix is empty") if (i < 0) or (i >= self.Data.Nor): - raise IndexError("Index {} out of range 0..{}",format(i,self.Data.Nor-1)) + raise IndexError("Index {} out of range 0..{}",format(i, self.Data.Nor-1)) cdef PTR p - p = MatGetPtr(self.Data,i) - L = [FfToInt(FfExtract(p,k)) for k in range(self.Data.Noc)] - if j!=-1: - if not(isinstance(j,int) or isinstance(j,Integer)): + p = MatGetPtr(self.Data, i) + L = [FfToInt(FfExtract(p, k)) for k in range(self.Data.Noc)] + if j != -1: + if not isinstance(j, (int, Integer)): raise TypeError("Second index must be an integer") if j >= self.Data.Nor: raise IndexError("Index out of range") diff --git a/src/sage/matrix/matrix_integer_dense.pyx b/src/sage/matrix/matrix_integer_dense.pyx index 9ea2335b297..215af3ecd65 100644 --- a/src/sage/matrix/matrix_integer_dense.pyx +++ b/src/sage/matrix/matrix_integer_dense.pyx @@ -2065,7 +2065,7 @@ cdef class Matrix_integer_dense(Matrix_dense): raise ValueError("ntl only computes HNF for square matrices of full rank.") import sage.libs.ntl.ntl_mat_ZZ - v = sage.libs.ntl.ntl_mat_ZZ.ntl_mat_ZZ(self._nrows,self._ncols) + v = sage.libs.ntl.ntl_mat_ZZ.ntl_mat_ZZ(self._nrows,self._ncols) for i from 0 <= i < self._nrows: for j from 0 <= j < self._ncols: v[i,j] = self.get_unsafe(nr-i-1,nc-j-1) @@ -4813,14 +4813,14 @@ cdef class Matrix_integer_dense(Matrix_dense): sage: w.charpoly().factor() (x - 3) * (x + 2) sage: w.decomposition() - [ - (Free module of degree 2 and rank 1 over Integer Ring - Echelon basis matrix: - [ 5 -2], True), - (Free module of degree 2 and rank 1 over Integer Ring - Echelon basis matrix: - [0 1], True) - ] + [(Free module of degree 2 and rank 1 over Integer Ring + Echelon basis matrix: + [ 5 -2], + True), + (Free module of degree 2 and rank 1 over Integer Ring + Echelon basis matrix: + [0 1], + True)] """ F = self.charpoly().factor() if len(F) == 1: @@ -4954,11 +4954,11 @@ cdef class Matrix_integer_dense(Matrix_dense): row_i = A.row(i) row_n = A.row(n) - ag = a//g - bg = b//g + ag = a // g + bg = b // g - new_top = s*row_i + t*row_n - new_bot = bg*row_i - ag*row_n + new_top = s * row_i + t * row_n + new_bot = bg * row_i - ag * row_n # OK -- now we have to make sure the top part of the matrix # but with row i replaced by @@ -5725,9 +5725,9 @@ cdef class Matrix_integer_dense(Matrix_dense): ri = nr for i from 0 <= i < nr: rj = nc - ri = ri-1 + ri -= 1 for j from 0 <= j < nc: - rj = rj-1 + rj -= 1 fmpz_init_set(fmpz_mat_entry(A._matrix, rj, ri), fmpz_mat_entry(self._matrix, i, j)) sig_off() diff --git a/src/sage/matrix/matrix_misc.py b/src/sage/matrix/matrix_misc.py index 35591735e57..a539f22ddff 100644 --- a/src/sage/matrix/matrix_misc.py +++ b/src/sage/matrix/matrix_misc.py @@ -14,8 +14,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.categories.fields import Fields _Fields = Fields() @@ -309,4 +309,4 @@ def permanental_minor_polynomial(A, permanent_only=False, var='t', prec=None): " algorithm... please contact sage-devel@googlegroups.com") p = p[0] - return p[min(nrows,ncols)] if permanent_only else p + return p[min(nrows, ncols)] if permanent_only else p diff --git a/src/sage/matrix/matrix_mod2_dense.pyx b/src/sage/matrix/matrix_mod2_dense.pyx index 07c54d6add9..676a2fc7f49 100644 --- a/src/sage/matrix/matrix_mod2_dense.pyx +++ b/src/sage/matrix/matrix_mod2_dense.pyx @@ -108,7 +108,7 @@ from cysignals.memory cimport check_malloc, sig_free from cysignals.signals cimport sig_on, sig_str, sig_off cimport sage.matrix.matrix_dense as matrix_dense -from sage.matrix.args cimport SparseEntry, MatrixArgs_init +from sage.matrix.args cimport SparseEntry, MatrixArgs_init, MA_ENTRIES_NDARRAY from libc.stdio cimport * from sage.structure.element cimport (Matrix, Vector) from sage.modules.free_module_element cimport FreeModuleElement @@ -257,8 +257,25 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse [] sage: Matrix(GF(2),0,2) [] + + Make sure construction from numpy array is reasonably fast:: + + sage: # needs numpy + sage: import numpy as np + sage: n = 5000 + sage: M = matrix(GF(2), np.random.randint(0, 2, (n, n))) # around 700ms + + Unsupported numpy data types (slower but still works):: + + sage: # needs numpy + sage: n = 100 + sage: M = matrix(GF(2), np.random.randint(0, 2, (n, n)).astype(np.float32)) """ ma = MatrixArgs_init(parent, entries) + if ma.get_type() == MA_ENTRIES_NDARRAY: + from ..modules.numpy_util import set_matrix_mod2_from_numpy + if set_matrix_mod2_from_numpy(self, ma.entries): + return for t in ma.iter(coerce, True): se = t mzd_write_bit(self._entries, se.i, se.j, se.entry) @@ -1111,7 +1128,7 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse self.clear_cache() sig_on() - r = mzd_echelonize(self._entries, full) + r = mzd_echelonize(self._entries, full) sig_off() self.cache('in_echelon_form',True) @@ -1126,14 +1143,14 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse if 'k' in kwds: k = int(kwds['k']) - if k<1 or k>16: + if k < 1 or k > 16: raise RuntimeError("k must be between 1 and 16") k = round(k) else: k = 0 sig_on() - r = mzd_echelonize_m4ri(self._entries, full, k) + r = mzd_echelonize_m4ri(self._entries, full, k) sig_off() self.cache('in_echelon_form',True) @@ -1146,7 +1163,7 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse self.clear_cache() sig_on() - r = mzd_echelonize_pluq(self._entries, full) + r = mzd_echelonize_pluq(self._entries, full) sig_off() self.cache('in_echelon_form',True) @@ -1919,6 +1936,103 @@ cdef class Matrix_mod2_dense(matrix_dense.Matrix_dense): # dense or sparse self.cache('rank', r) return r + def _solve_right_general(self, B, check=True): + """ + Solve the matrix equation AX = B for X using the M4RI library. + + INPUT: + + - ``B`` -- a matrix + - ``check`` -- boolean (default: ``True``); whether to check if the + matrix equation has a solution + + EXAMPLES:: + + sage: A = matrix(GF(2), [[1, 0], [0, 1], [1, 1]]) + sage: A.solve_right(vector([1, 1, 0])) + (1, 1) + sage: A.solve_right(vector([1, 1, 1])) + Traceback (most recent call last): + ... + ValueError: matrix equation has no solutions + + TESTS:: + + sage: n = 128 + sage: m = 128 + sage: A = random_matrix(GF(2), n, m) + sage: B = A * random_vector(GF(2), m) + sage: A * A.solve_right(B) == B + True + sage: m = 64 + sage: A = random_matrix(GF(2), n, m) + sage: B = A * random_vector(GF(2), m) + sage: A * A.solve_right(B) == B + True + sage: m = 256 + sage: A = random_matrix(GF(2), n, m) + sage: B = A * random_vector(GF(2), m) + sage: A * A.solve_right(B) == B + True + sage: matrix(GF(2), 2, 0).solve_right(matrix(GF(2), 2, 2)) == matrix(GF(2), 0, 2) + True + sage: matrix(GF(2), 2, 0).solve_right(matrix(GF(2), 2, 2) + 1) + Traceback (most recent call last): + ... + ValueError: matrix equation has no solutions + sage: matrix(GF(2), 2, 0).solve_right(matrix(GF(2), 2, 2) + 1, check=False) == matrix(GF(2), 0, 2) + True + sage: matrix(GF(2), 2, 2).solve_right(matrix(GF(2), 2, 0)) == matrix(GF(2), 2, 0) + True + + Check that it can be interrupted:: + + sage: set_random_seed(12345) + sage: n, m = 20000, 19968 + sage: A = random_matrix(GF(2), n, m) + sage: x = random_vector(GF(2), m) + sage: B = A*x + sage: alarm(0.5); sol = A.solve_right(B) + Traceback (most recent call last): + ... + AlarmInterrupt + """ + cdef mzd_t *B_entries = (B)._entries + + cdef Matrix_mod2_dense X # the solution + X = self.new_matrix(nrows=self._entries.ncols, ncols=B_entries.ncols) + if self._entries.ncols == 0 or B_entries.ncols == 0: + # special case: empty matrix + if check and B != 0: + raise ValueError("matrix equation has no solutions") + return X + cdef rci_t rows = self._entries.nrows + if self._entries.nrows < self._entries.ncols: + rows = self._entries.ncols # mzd_solve_left requires ncols <= nrows + + cdef mzd_t *lhs = mzd_init(rows, self._entries.ncols) + mzd_copy(lhs, self._entries) + cdef mzd_t *rhs = mzd_init(rows, B_entries.ncols) + mzd_copy(rhs, B_entries) + + cdef int ret + try: + sig_on() + # although it is called mzd_solve_left, it does the same thing as solve_right + ret = mzd_solve_left(lhs, rhs, 0, check) + sig_off() + + if ret == 0: + # solution is placed in rhs + rhs.nrows = self._entries.ncols + mzd_copy(X._entries, rhs) + return X + else: + raise ValueError("matrix equation has no solutions") + finally: + mzd_free(lhs) + mzd_free(rhs) + def _right_kernel_matrix(self, **kwds): r""" Return a pair that includes a matrix of basis vectors diff --git a/src/sage/matrix/matrix_modn_dense_template.pxi b/src/sage/matrix/matrix_modn_dense_template.pxi index 177cebffb38..03e60d56394 100644 --- a/src/sage/matrix/matrix_modn_dense_template.pxi +++ b/src/sage/matrix/matrix_modn_dense_template.pxi @@ -73,7 +73,7 @@ We test corner cases for multiplication:: ....: pass """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2004,2005,2006 William Stein # Copyright (C) 2011 Burcin Erocal # Copyright (C) 2011 Martin Albrecht @@ -83,8 +83,8 @@ We test corner cases for multiplication:: # 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.stdint cimport uint64_t from cpython.bytes cimport * @@ -100,7 +100,7 @@ from sage.parallel.parallelism import Parallelism cimport sage.rings.fast_arith cdef sage.rings.fast_arith.arith_int ArithIntObj -ArithIntObj = sage.rings.fast_arith.arith_int() +ArithIntObj = sage.rings.fast_arith.arith_int() # for copying/pickling from libc.string cimport memcpy @@ -110,7 +110,7 @@ from sage.modules.vector_modn_dense cimport Vector_modn_dense from sage.arith.misc import is_prime from sage.structure.element cimport (Element, Vector, Matrix, - ModuleElement, RingElement) + ModuleElement, RingElement) from sage.matrix.matrix_dense cimport Matrix_dense from sage.matrix.matrix_integer_dense cimport Matrix_integer_dense from sage.rings.finite_rings.integer_mod cimport IntegerMod_int, IntegerMod_abstract @@ -146,7 +146,7 @@ cdef inline celement_invert(celement a, celement n): # always: gcd (n,residue) = gcd (x_int,y_int) # sx*n + tx*residue = x_int # sy*n + ty*residue = y_int - q = x_int / y_int # integer quotient + q = x_int / y_int # integer quotient temp = y_int y_int = x_int - q * y_int x_int = temp @@ -155,7 +155,7 @@ cdef inline celement_invert(celement a, celement n): tx = temp if tx < 0: - tx += n + tx += n # now x_int = gcd (n,residue) return tx @@ -175,9 +175,8 @@ cdef inline linbox_echelonize(celement modulus, celement* entries, Py_ssize_t nr """ Return the reduced row echelon form of this matrix. """ - if linbox_is_zero(modulus, entries, nrows, ncols): - return 0,[] + return 0, [] cdef Py_ssize_t i, j cdef ModField *F = new ModField(modulus) @@ -217,12 +216,12 @@ cdef inline linbox_echelonize_efd(celement modulus, celement* entries, Py_ssize_ # which would yield a segfault in Sage's debug version. TODO: Fix # that bug upstream. if nrows == 0 or ncols == 0: - return 0,[] + return 0, [] cdef ModField *F = new ModField(modulus) cdef DenseMatrix *A = new DenseMatrix(F[0], nrows, ncols) - cdef Py_ssize_t i,j + cdef Py_ssize_t i, j for i in range(nrows): for j in range(ncols): A.setEntry(i, j, entries[i*ncols+j]) @@ -230,12 +229,12 @@ cdef inline linbox_echelonize_efd(celement modulus, celement* entries, Py_ssize_ cdef Py_ssize_t r = reducedRowEchelonize(A[0]) for i in range(nrows): for j in range(ncols): - entries[i*ncols+j] = A.getEntry(i,j) + entries[i*ncols+j] = A.getEntry(i, j) cdef Py_ssize_t ii = 0 cdef list pivots = [] for i in range(r): - for j in range(ii,ncols): + for j in range(ii, ncols): if entries[i*ncols+j] == 1: pivots.append(j) ii = j+1 @@ -316,10 +315,10 @@ cdef inline celement linbox_matrix_matrix_multiply(celement modulus, celement* a pfgemm(F[0], FflasNoTrans, FflasNoTrans, m, n, k, one, A, k, B, n, zero, ans, n, nbthreads) - else : + else: fgemm(F[0], FflasNoTrans, FflasNoTrans, m, n, k, one, - A, k, B, n, zero, - ans, n) + A, k, B, n, zero, + ans, n) if m*n*k > 100000: sig_off() @@ -339,7 +338,7 @@ cdef inline int linbox_matrix_vector_multiply(celement modulus, celement* C, cel sig_on() fgemv(F[0], trans, m, n, one, A, n, b, 1, - zero, C, 1) + zero, C, 1) if m*n > 100000: sig_off() @@ -360,9 +359,7 @@ cdef inline linbox_minpoly(celement modulus, Py_ssize_t nrows, celement* entries if nrows*nrows > 1000: sig_off() - l = [] - for i in range(minP.size()): - l.append( minP.at(i) ) + l = [minP.at(i) for i in range(minP.size())] del F return l @@ -420,10 +417,10 @@ cpdef __matrix_from_rows_of_matrices(X): ``Matrix_modn_dense_float/double._matrix_from_rows_of_matrices`` """ # The code below is just a fast version of the following: - ## from constructor import matrix - ## K = X[0].base_ring() - ## v = sum([y.list() for y in X],[]) - ## return matrix(K, len(X), X[0].nrows()*X[0].ncols(), v) + # from constructor import matrix + # K = X[0].base_ring() + # v = sum([y.list() for y in X],[]) + # return matrix(K, len(X), X[0].nrows()*X[0].ncols(), v) cdef Matrix_modn_dense_template T cdef Py_ssize_t i, n, m @@ -444,7 +441,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef long p = self._base_ring.characteristic() self.p = p if p >= MAX_MODULUS: - raise OverflowError("p (=%s) must be < %s."%(p, MAX_MODULUS)) + raise OverflowError("p (=%s) must be < %s." % (p, MAX_MODULUS)) if zeroed_alloc: self._entries = check_calloc(self._nrows * self._ncols, sizeof(celement)) @@ -729,7 +726,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): PyBytes_AsStringAndSize(s, &buf, &buflen) if buflen != expectedlen: - raise ValueError("incorrect size in matrix pickle (expected %d, got %d)"%(expectedlen, buflen)) + raise ValueError("incorrect size in matrix pickle (expected %d, got %d)" % (expectedlen, buflen)) sig_on() try: @@ -746,7 +743,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): for i from 0 <= i < self._nrows: row_self = self._matrix[i] for j from 0 <= j < self._ncols: - v = (us[0]) + v = (us[0]) v += (us[1]) << 8 v += (us[2]) << 16 v += (us[3]) << 24 @@ -758,7 +755,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): for i from 0 <= i < self._nrows: row_self = self._matrix[i] for j from 0 <= j < self._ncols: - v = (us[word_size-1]) + v = (us[word_size-1]) v += (us[word_size-2]) << 8 v += (us[word_size-3]) << 16 v += (us[word_size-4]) << 24 @@ -790,7 +787,8 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef Matrix_modn_dense_template M cdef celement p = self.p - M = self.__class__.__new__(self.__class__, self._parent,None,None,None, zeroed_alloc=False) + M = self.__class__.__new__(self.__class__, self._parent, + None, None, None, zeroed_alloc=False) sig_on() for i in range(self._nrows*self._ncols): @@ -824,12 +822,13 @@ cdef class Matrix_modn_dense_template(Matrix_dense): sage: 3*A + 9*A == 12*A True """ - cdef Py_ssize_t i,j + cdef Py_ssize_t i, j cdef Matrix_modn_dense_template M cdef celement p = self.p cdef celement a = left - M = self.__class__.__new__(self.__class__, self._parent,None,None,None,zeroed_alloc=False) + M = self.__class__.__new__(self.__class__, self._parent, + None, None, None, zeroed_alloc=False) sig_on() for i in range(self._nrows*self._ncols): @@ -848,7 +847,8 @@ cdef class Matrix_modn_dense_template(Matrix_dense): False """ cdef Matrix_modn_dense_template A - A = self.__class__.__new__(self.__class__,self._parent,None,None,None,zeroed_alloc=False) + A = self.__class__.__new__(self.__class__, self._parent, + None, None, None, zeroed_alloc=False) memcpy(A._entries, self._entries, sizeof(celement)*self._nrows*self._ncols) if self._subdivisions is not None: A.subdivide(*self.subdivisions()) @@ -886,7 +886,8 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef celement k, p cdef Matrix_modn_dense_template M - M = self.__class__.__new__(self.__class__, self._parent,None,None,None,zeroed_alloc=False) + M = self.__class__.__new__(self.__class__, self._parent, + None, None, None, zeroed_alloc=False) p = self.p cdef celement* other_ent = (right)._entries @@ -1125,7 +1126,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): True """ if get_verbose() >= 2: - verbose('mod-p multiply of %s x %s matrix by %s x %s matrix modulo %s'%( + verbose('mod-p multiply of %s x %s matrix by %s x %s matrix modulo %s' % ( self._nrows, self._ncols, right._nrows, right._ncols, self.p)) if self._ncols != right._nrows: @@ -1174,7 +1175,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): True """ if not isinstance(v, Vector_modn_dense): - return (self.new_matrix(1,self._nrows, entries=v.list()) * self)[0] + return (self.new_matrix(1, self._nrows, entries=v.list()) * self)[0] M = self.row_ambient_module() cdef Vector_modn_dense c = M.zero_vector() @@ -1385,7 +1386,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): return g.change_variable_name(var) if algorithm == 'linbox' and (self.p == 2 or not self.base_ring().is_field()): - algorithm = 'generic' # LinBox only supports Z/pZ (p prime) + algorithm = 'generic' # LinBox only supports Z/pZ (p prime) if algorithm == 'linbox': g = self._charpoly_linbox(var) @@ -1512,7 +1513,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): proof = get_proof_flag(proof, "linear_algebra") if algorithm == 'linbox' and (self.p == 2 or not self.base_ring().is_field()): - algorithm='generic' # LinBox only supports fields + algorithm='generic' # LinBox only supports fields if algorithm == 'linbox': if self._nrows != self._ncols: @@ -1533,9 +1534,9 @@ cdef class Matrix_modn_dense_template(Matrix_dense): raise NotImplementedError("Minimal polynomials are not implemented for Z/nZ.") else: - raise ValueError("no algorithm '%s'"%algorithm) + raise ValueError("no algorithm '%s'" % algorithm) - self.cache('minpoly_%s_%s'%(algorithm, var), g) + self.cache('minpoly_%s_%s' % (algorithm, var), g) return g def _charpoly_linbox(self, var='x'): @@ -1729,7 +1730,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): return # already known to be in echelon form if not self.base_ring().is_field(): - raise NotImplementedError("Echelon form not implemented over '%s'."%self.base_ring()) + raise NotImplementedError("Echelon form not implemented over '%s'." % self.base_ring()) if algorithm == 'linbox': self._echelonize_linbox(efd=True) @@ -1747,7 +1748,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): if A != self or A != B: raise ArithmeticError("Bug in echelon form.") else: - raise ValueError("Algorithm '%s' not known"%algorithm) + raise ValueError("Algorithm '%s' not known" % algorithm) def _echelonize_linbox(self, efd=True): """ @@ -1778,13 +1779,15 @@ cdef class Matrix_modn_dense_template(Matrix_dense): self.check_mutability() self.clear_cache() - t = verbose('Calling echelonize mod %d.'%self.p) + t = verbose('Calling echelonize mod %d.' % self.p) if efd: - r, pivots = linbox_echelonize_efd(self.p, self._entries, self._nrows, self._ncols) + r, pivots = linbox_echelonize_efd(self.p, self._entries, + self._nrows, self._ncols) else: - r, pivots = linbox_echelonize(self.p, self._entries, self._nrows, self._ncols) - verbose('done with echelonize',t) - self.cache('in_echelon_form',True) + r, pivots = linbox_echelonize(self.p, self._entries, + self._nrows, self._ncols) + verbose('done with echelonize', t) + self.cache('in_echelon_form', True) self.cache('rank', r) self.cache('pivots', tuple(pivots)) @@ -1821,11 +1824,11 @@ cdef class Matrix_modn_dense_template(Matrix_dense): fifth = self._ncols / 10 + 1 do_verb = (get_verbose() >= 2) for c from 0 <= c < nc: - if do_verb and (c % fifth == 0 and c>0): - tm = verbose('on column %s of %s'%(c, self._ncols), + if do_verb and (c % fifth == 0 and c > 0): + tm = verbose('on column %s of %s' % (c, self._ncols), level = 2, caller_name = 'matrix_modn_dense echelon') - #end if + # end if sig_check() for r from start_row <= r < nr: a = m[r][c] @@ -1842,7 +1845,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): start_row = start_row + 1 break self.cache('pivots', tuple(pivots)) - self.cache('in_echelon_form',True) + self.cache('in_echelon_form', True) def right_kernel_matrix(self, algorithm='linbox', basis='echelon'): r""" @@ -1990,38 +1993,38 @@ cdef class Matrix_modn_dense_template(Matrix_dense): i = -1 for r from m+1 <= r < n: if h[r][m-1]: - i = r - break + i = r + break if i != -1: - # Found a nonzero entry in column m-1 that is strictly - # below row m. Now set i to be the first nonzero position >= - # m in column m-1. - if h[m][m-1]: - i = m - t = h[i][m-1] - t_inv = celement_invert(t,p) - if i > m: - self.swap_rows_c(i,m) - self.swap_columns_c(i,m) - - # Now the nonzero entry in position (m,m-1) is t. - # Use t to clear the entries in column m-1 below m. - for j from m+1 <= j < n: - if h[j][m-1]: - u = (h[j][m-1] * t_inv) % p - self.add_multiple_of_row_c(j, m, p - u, 0) # h[j] -= u*h[m] - # To maintain charpoly, do the corresponding - # column operation, which doesn't mess up the - # matrix, since it only changes column m, and - # we're only worried about column m-1 right - # now. Add u*column_j to column_m. - self.add_multiple_of_column_c(m, j, u, 0) - # end for + # Found a nonzero entry in column m-1 that is strictly + # below row m. Now set i to be the first nonzero position >= + # m in column m-1. + if h[m][m-1]: + i = m + t = h[i][m-1] + t_inv = celement_invert(t, p) + if i > m: + self.swap_rows_c(i, m) + self.swap_columns_c(i, m) + + # Now the nonzero entry in position (m,m-1) is t. + # Use t to clear the entries in column m-1 below m. + for j from m+1 <= j < n: + if h[j][m-1]: + u = (h[j][m-1] * t_inv) % p + self.add_multiple_of_row_c(j, m, p - u, 0) # h[j] -= u*h[m] + # To maintain charpoly, do the corresponding + # column operation, which doesn't mess up the + # matrix, since it only changes column m, and + # we're only worried about column m-1 right + # now. Add u*column_j to column_m. + self.add_multiple_of_column_c(m, j, u, 0) + # end for # end if # end for sig_off() - self.cache('in_hessenberg_form',True) + self.cache('in_hessenberg_form', True) def _charpoly_hessenberg(self, var): """ @@ -2073,7 +2076,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): # Algorithm 2.2.9. cdef Matrix_modn_dense_template c - c = self.new_matrix(nrows=n+1,ncols=n+1) # the 0 matrix + c = self.new_matrix(nrows=n+1, ncols=n+1) # the 0 matrix c._matrix[0][0] = 1 for m from 1 <= m <= n: # Set the m-th row of c to (x - H[m-1,m-1])*c[m-1] = x*c[m-1] - H[m-1,m-1]*c[m-1] @@ -2088,7 +2091,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): for i from 1 <= i < m: t = (t*H._matrix[m-i][m-i-1]) % p # Set the m-th row of c to c[m] - t*H[m-i-1,m-1]*c[m-i-1] - c.add_multiple_of_row_c(m, m-i-1, p - (t*H._matrix[m-i-1][m-1])%p, 0) + c.add_multiple_of_row_c(m, m-i-1, p - (t*H._matrix[m-i-1][m-1]) % p, 0) # The answer is now the n-th row of c. v = [] @@ -2306,13 +2309,13 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef Py_ssize_t nc, i cdef int a = row1[start_col] cdef int b = row2[start_col] - g = ArithIntObj.c_xgcd_int (a,b,&s,&t) + g = ArithIntObj.c_xgcd_int(a, b, &s, &t) v = a/g w = -b/g nc = self.ncols() for i from start_col <= i < nc: - tmp = ( s * row1[i] + t * row2[i]) % p + tmp = (s * row1[i] + t * row2[i]) % p row2[i] = (w* row1[i] + v*row2[i]) % p row1[i] = tmp return g @@ -2446,7 +2449,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef Py_ssize_t i, nc nc = self._ncols for i from start_col <= i < nc: - v_to[i] = ((multiple) * v_from[i] + v_to[i]) % p + v_to[i] = ((multiple) * v_from[i] + v_to[i]) % p cdef add_multiple_of_column_c(self, Py_ssize_t col_to, Py_ssize_t col_from, multiple, Py_ssize_t start_row): """ @@ -2665,7 +2668,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): True """ s = self.base_ring()._magma_init_(magma) - return 'Matrix(%s,%s,%s,StringToIntegerSequence("%s"))'%( + return 'Matrix(%s,%s,%s,StringToIntegerSequence("%s"))' % ( s, self._nrows, self._ncols, self._export_as_string()) cpdef _export_as_string(self): @@ -2758,8 +2761,9 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef Py_ssize_t i, j cdef Matrix_integer_dense L - cdef object P = matrix_space.MatrixSpace(ZZ, self._nrows, self._ncols, sparse=False) - L = Matrix_integer_dense(P,ZZ(0),False,False) + cdef object P = matrix_space.MatrixSpace(ZZ, self._nrows, + self._ncols, sparse=False) + L = Matrix_integer_dense(P, ZZ(0), False, False) cdef celement* A_row for i in range(self._nrows): A_row = self._matrix[i] @@ -2808,7 +2812,7 @@ cdef class Matrix_modn_dense_template(Matrix_dense): cdef Py_ssize_t ncols = self._ncols cdef Matrix_modn_dense_template M = self.new_matrix(nrows=ncols, ncols=nrows) - cdef Py_ssize_t i,j + cdef Py_ssize_t i, j for i from 0 <= i < ncols: for j from 0 <= j < nrows: @@ -2955,8 +2959,9 @@ cdef class Matrix_modn_dense_template(Matrix_dense): memcpy(M._entries+selfsize, other._entries, sizeof(celement)*other._ncols*other._nrows) return M - def submatrix(self, Py_ssize_t row=0, Py_ssize_t col=0, - Py_ssize_t nrows=-1, Py_ssize_t ncols=-1): + def submatrix(self, + Py_ssize_t row=0, Py_ssize_t col=0, + Py_ssize_t nrows=-1, Py_ssize_t ncols=-1): r""" Return the matrix constructed from ``self`` using the specified range of rows and columns. @@ -3024,8 +3029,8 @@ cdef class Matrix_modn_dense_template(Matrix_dense): memcpy(M._entries, self._matrix[row], sizeof(celement)*ncols*nrows) return M - cdef Py_ssize_t i,r - for i,r in enumerate(range(row, row+nrows)) : + cdef Py_ssize_t i, r + for i, r in enumerate(range(row, row+nrows)) : memcpy(M._matrix[i], self._matrix[r]+col, sizeof(celement)*ncols) return M @@ -3241,4 +3246,3 @@ cdef class Matrix_modn_dense_template(Matrix_dense): [0 1] """ return self._entries[j+i*self._ncols] == 0 - diff --git a/src/sage/matrix/matrix_modn_sparse.pyx b/src/sage/matrix/matrix_modn_sparse.pyx index 3334744500c..33056c221ce 100644 --- a/src/sage/matrix/matrix_modn_sparse.pyx +++ b/src/sage/matrix/matrix_modn_sparse.pyx @@ -178,7 +178,7 @@ cdef class Matrix_modn_sparse(Matrix_sparse): cdef get_unsafe(self, Py_ssize_t i, Py_ssize_t j): cdef IntegerMod_int n - n = IntegerMod_int.__new__(IntegerMod_int) + n = IntegerMod_int.__new__(IntegerMod_int) IntegerMod_abstract.__init__(n, self._base_ring) n.ivalue = get_entry(&self.rows[i], j) return n diff --git a/src/sage/matrix/matrix_rational_dense.pyx b/src/sage/matrix/matrix_rational_dense.pyx index 40c63470617..b0c58016c9b 100644 --- a/src/sage/matrix/matrix_rational_dense.pyx +++ b/src/sage/matrix/matrix_rational_dense.pyx @@ -1900,15 +1900,15 @@ cdef class Matrix_rational_dense(Matrix_dense): sage: a = matrix(QQ,3,[1..9]) sage: a.decomposition() - [ - (Vector space of degree 3 and dimension 1 over Rational Field - Basis matrix: - [ 1 -2 1], True), - (Vector space of degree 3 and dimension 2 over Rational Field - Basis matrix: - [ 1 0 -1] - [ 0 1 2], True) - ] + [(Vector space of degree 3 and dimension 1 over Rational Field + Basis matrix: + [ 1 -2 1], + True), + (Vector space of degree 3 and dimension 2 over Rational Field + Basis matrix: + [ 1 0 -1] + [ 0 1 2], + True)] """ X = self._decomposition_rational(is_diagonalizable=is_diagonalizable, echelon_algorithm=algorithm, diff --git a/src/sage/matrix/matrix_space.py b/src/sage/matrix/matrix_space.py index 2ba59292d54..7f5cb645134 100644 --- a/src/sage/matrix/matrix_space.py +++ b/src/sage/matrix/matrix_space.py @@ -297,7 +297,7 @@ def get_matrix_class(R, nrows, ncols, sparse, implementation): except ImportError: pass else: - if isinstance(R, polynomial_ring.PolynomialRing_general) and R.base_ring() in _Fields: + if isinstance(R, polynomial_ring.PolynomialRing_generic) and R.base_ring() in _Fields: try: from . import matrix_polynomial_dense except ImportError: diff --git a/src/sage/matrix/meson.build b/src/sage/matrix/meson.build index 932ac4c40c2..0e51c764de7 100644 --- a/src/sage/matrix/meson.build +++ b/src/sage/matrix/meson.build @@ -2,6 +2,7 @@ iml = cc.find_library('iml') py.install_sources( + '__init__.py', 'action.pxd', 'all.py', 'all__sagemath_meataxe.py', @@ -98,7 +99,7 @@ extension_data = { foreach name, pyx : extension_data dependencies = [py_dep, cysignals, gmp] if name == 'matrix_gfpn_dense' - dependencies += [mtx, meataxe] + dependencies += [mtx] elif name == 'matrix_gap' dependencies += [gap] elif name == 'misc_mpfr' diff --git a/src/sage/matrix/misc.pyx b/src/sage/matrix/misc.pyx index 5f8f834b33f..aa1602ff657 100644 --- a/src/sage/matrix/misc.pyx +++ b/src/sage/matrix/misc.pyx @@ -222,7 +222,7 @@ def matrix_rational_echelon_form_multimodular(Matrix self, height_guess=None, pr tm = verbose("height_guess = %s" % height_guess, level=2, caller_name="multimod echelon") if proof: - M = self._ncols * height_guess * height + 1 + M = self._ncols * height_guess * height + 1 else: M = height_guess + 1 diff --git a/src/sage/matrix/operation_table.py b/src/sage/matrix/operation_table.py index 89943f90b3b..58c53cfa1c7 100644 --- a/src/sage/matrix/operation_table.py +++ b/src/sage/matrix/operation_table.py @@ -777,7 +777,6 @@ def set_print_symbols(self, ascii, latex): raise ValueError('LaTeX symbol must be a string, not %s' % latex) self._ascii_symbol = ascii self._latex_symbol = latex - return None def column_keys(self): r""" @@ -931,7 +930,6 @@ def change_names(self, names): (1,2) """ self._width, self._names, self._name_dict = self._name_maker(names) - return None def matrix_of_variables(self): r""" diff --git a/src/sage/matroids/basis_exchange_matroid.pyx b/src/sage/matroids/basis_exchange_matroid.pyx index 7cf056c4292..8b04ad20205 100644 --- a/src/sage/matroids/basis_exchange_matroid.pyx +++ b/src/sage/matroids/basis_exchange_matroid.pyx @@ -996,7 +996,7 @@ cdef class BasisExchangeMatroid(Matroid): sage: setprint(M.components()) [{0, 1, 3, 4}, {2, 5}] """ - cdef long i,j,e + cdef long i, j, e if not self._E: return SetSystem(self._E) cdef bitset_t *comp @@ -1098,15 +1098,15 @@ cdef class BasisExchangeMatroid(Matroid): cdef bitset_t SS, TT bitset_init(SS, self._groundset_size) bitset_init(TT, self._groundset_size) - self._pack(SS,S) - self._pack(TT,T) - #F = set(self.groundset()) - (S | T) + self._pack(SS, S) + self._pack(TT, T) + # F = set(self.groundset()) - (S | T) cdef bitset_t F, I bitset_init(F, self._groundset_size) bitset_init(I, self._groundset_size) bitset_union(self._input, SS, TT) bitset_complement(F, self._input) - #I = self._augment(S|T, F) + # I = self._augment(S|T, F) self.__augment(I, self._input, F) cdef bitset_t X, X1, X2, next_layer, todo, out_neighbors, R bitset_init(X, self._groundset_size) @@ -1121,52 +1121,52 @@ cdef class BasisExchangeMatroid(Matroid): cdef long e, u, y cdef bint found_path = True while found_path: - #X = F - I - bitset_difference(X,F,I) - #X1 = X - self._closure(T|I) + # X = F - I + bitset_difference(X, F, I) + # X1 = X - self._closure(T|I) bitset_union(self._input, TT, I) self.__closure(X1, self._input) - bitset_difference(X1,X,X1) - #X2 = X - self._closure(S|I) + bitset_difference(X1, X, X1) + # X2 = X - self._closure(S|I) bitset_union(self._input, SS, I) self.__closure(X2, self._input) - bitset_difference(X2,X,X2) + bitset_difference(X2, X, X2) bitset_intersection(R, X1, X2) e = bitset_first(R) if e >= 0: bitset_add(I, e) continue - #predecessor = {x: None for x in X1} + # predecessor = {x: None for x in X1} e = bitset_first(X1) while e>=0: predecessor[e] = -1 e = bitset_next(X1, e+1) - #next_layer = set(X1) + # next_layer = set(X1) bitset_copy(next_layer, X1) bitset_union(R, SS, X1) found_path = False while not bitset_isempty(next_layer) and not found_path: - #todo = next_layer - bitset_copy(todo,next_layer) - #next_layer = {} + # todo = next_layer + bitset_copy(todo, next_layer) + # next_layer = {} bitset_clear(next_layer) u = bitset_first(todo) - while u>=0 and not found_path: - if bitset_in(X,u): - #out_neighbors = self._circuit(I|S.union([u])) - S.union([u]) + while u >= 0 and not found_path: + if bitset_in(X, u): + # out_neighbors = self._circuit(I|S.union([u])) - S.union([u]) bitset_union(self._input, I, SS) bitset_add(self._input, u) self.__circuit(out_neighbors, self._input) bitset_discard(out_neighbors, u) else: - #out_neighbors = X - self._closure(I|T - set([u])) + # out_neighbors = X - self._closure(I|T - set([u])) bitset_union(self._input, I, TT) bitset_discard(self._input, u) self.__closure(out_neighbors, self._input) bitset_difference(out_neighbors, X, out_neighbors) bitset_difference(out_neighbors, out_neighbors, R) y = bitset_first(out_neighbors) - while y>=0: + while y >= 0: predecessor[y] = u if bitset_in(X2, y): found_path = True @@ -1552,7 +1552,7 @@ cdef class BasisExchangeMatroid(Matroid): res._append(I[i+1]) bitset_copy(self._input, I[i+1]) self.__closure(T[i+1], self._input) - bitset_union(T[i+1],T[i+1],T[i]) + bitset_union(T[i+1], T[i+1], T[i]) i = i + 1 else: i = i - 1 @@ -2102,7 +2102,7 @@ cdef class BasisExchangeMatroid(Matroid): from sage.matroids.basis_matroid import BasisMatroid other = BasisMatroid(other) if self is other: - return {e:e for e in self.groundset()} + return {e: e for e in self.groundset()} if len(self) != len(other): return None if self.full_rank() != other.full_rank(): diff --git a/src/sage/matroids/basis_matroid.pyx b/src/sage/matroids/basis_matroid.pyx index b74a76af956..73c75f27b01 100644 --- a/src/sage/matroids/basis_matroid.pyx +++ b/src/sage/matroids/basis_matroid.pyx @@ -955,7 +955,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): if not isinstance(other, BasisMatroid): return self.isomorphism(BasisMatroid(other)) if self is other: - return {e:e for e in self.groundset()} + return {e: e for e in self.groundset()} if len(self) != len(other): return None if self.full_rank() != other.full_rank(): diff --git a/src/sage/matroids/chow_ring.py b/src/sage/matroids/chow_ring.py index 173c8db7f84..5fea543aeb3 100644 --- a/src/sage/matroids/chow_ring.py +++ b/src/sage/matroids/chow_ring.py @@ -5,11 +5,22 @@ - Shriya M """ +# **************************************************************************** +# Copyright (C) 2024 Shriya M <25shriya at gmail.com> +# +# 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.matroids.chow_ring_ideal import ChowRingIdeal_nonaug, AugmentedChowRingIdeal_fy, AugmentedChowRingIdeal_atom_free from sage.rings.quotient_ring import QuotientRing_generic -from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis +from sage.categories.kahler_algebras import KahlerAlgebras from sage.categories.commutative_rings import CommutativeRings +from sage.misc.cachefunc import cached_method + class ChowRing(QuotientRing_generic): r""" @@ -51,6 +62,11 @@ class ChowRing(QuotientRing_generic): :mod:`sage.matroids.chow_ring_ideal` + .. WARNING:: + + Different presentations of Chow rings of non-simple matroids may not be + isomorphic to one another. + INPUT: - ``M`` -- matroid @@ -95,7 +111,7 @@ def __init__(self, R, M, augmented, presentation=None): self._ideal = AugmentedChowRingIdeal_atom_free(M, R) else: self._ideal = ChowRingIdeal_nonaug(M, R) - C = CommutativeRings().Quotients() & GradedAlgebrasWithBasis(R).FiniteDimensional() + C = CommutativeRings().Quotients() & KahlerAlgebras(R) QuotientRing_generic.__init__(self, R=self._ideal.ring(), I=self._ideal, names=self._ideal.ring().variable_names(), @@ -126,7 +142,7 @@ def _latex_(self): EXAMPLES:: - sage: M1 = matroids.Uniform(2,5) + sage: M1 = matroids.Uniform(2, 5) sage: ch = M1.chow_ring(QQ, False) sage: ch._latex_() 'A(\\begin{array}{l}\n\\text{\\texttt{U(2,{ }5):{ }Matroid{ }of{ }rank{ }2{ }on{ }5{ }elements{ }with{ }circuit{-}closures}}\\\\\n\\text{\\texttt{{\\char`\\{}2:{ }{\\char`\\{}{\\char`\\{}0,{ }1,{ }2,{ }3,{ }4{\\char`\\}}{\\char`\\}}{\\char`\\}}}}\n\\end{array})_{\\Bold{Q}}' @@ -143,7 +159,7 @@ def matroid(self): EXAMPLES:: - sage: ch = matroids.Uniform(3,6).chow_ring(QQ, True, 'fy') + sage: ch = matroids.Uniform(3, 6).chow_ring(QQ, True, 'fy') sage: ch.matroid() U(3, 6): Matroid of rank 3 on 6 elements with circuit-closures {3: {{0, 1, 2, 3, 4, 5}}} @@ -196,6 +212,119 @@ def basis(self): monomial_basis = self._ideal.normal_basis() return Family([self.element_class(self, mon, reduce=False) for mon in monomial_basis]) + @cached_method + def lefschetz_element(self): + r""" + Return one Lefschetz element of the given Chow ring. + + EXAMPLES:: + + sage: ch = matroids.catalog.P8pp().chow_ring(QQ, False) + sage: ch.lefschetz_element() + -2*Aab - 2*Aac - 2*Aad - 2*Aae - 2*Aaf - 2*Aag - 2*Aah - 2*Abc + - 2*Abd - 2*Abe - 2*Abf - 2*Abg - 2*Abh - 2*Acd - 2*Ace - 2*Acf + - 2*Acg - 2*Ach - 2*Ade - 2*Adf - 2*Adg - 2*Adh - 2*Aef - 2*Aeg + - 2*Aeh - 2*Afg - 2*Afh - 2*Agh - 6*Aabc - 6*Aabd - 6*Aabe + - 12*Aabfh - 6*Aabg - 6*Aacd - 12*Aacef - 12*Aacgh - 12*Aadeg + - 6*Aadf - 6*Aadh - 6*Aaeh - 6*Aafg - 6*Abcd - 12*Abceg + - 6*Abcf - 6*Abch - 12*Abdeh - 12*Abdfg - 6*Abef - 6*Abgh + - 6*Acde - 12*Acdfh - 6*Acdg - 6*Aceh - 6*Acfg - 6*Adef + - 6*Adgh - 6*Aefg - 6*Aefh - 6*Aegh - 6*Afgh - 56*Aabcdefgh + + The following example finds the Lefschetz element of the Chow ring + of the uniform matroid of rank 4 on 5 elements (non-augmented). + It is then multiplied with the elements of FY-monomial bases of + different degrees:: + + sage: ch = matroids.Uniform(4, 5).chow_ring(QQ, False) + sage: basis_deg = {} + sage: for b in ch.basis(): + ....: deg = b.homogeneous_degree() + ....: if deg not in basis_deg: + ....: basis_deg[deg] = [] + ....: basis_deg[deg].append(b) + ....: + sage: basis_deg + {0: [1], 1: [A02, A12, A01, A012, A03, A13, A013, A23, A023, + A123, A04, A14, A014, A24, A024, A124, A34, A034, A134, A234, + A01234], 2: [A02*A01234, A12*A01234, A01*A01234, A012^2, + A03*A01234, A13*A01234, A013^2, A23*A01234, A023^2, A123^2, + A04*A01234, A14*A01234, A014^2, A24*A01234, A024^2, A124^2, + A34*A01234, A034^2, A134^2, A234^2, A01234^2], 3: [A01234^3]} + sage: g_eq_maps = {} + sage: lefschetz_el = ch.lefschetz_element(); lefschetz_el + -2*A01 - 2*A02 - 2*A03 - 2*A04 - 2*A12 - 2*A13 - 2*A14 - 2*A23 + - 2*A24 - 2*A34 - 6*A012 - 6*A013 - 6*A014 - 6*A023 - 6*A024 + - 6*A034 - 6*A123 - 6*A124 - 6*A134 - 6*A234 - 20*A01234 + sage: for deg in basis_deg: + ....: if deg not in g_eq_maps: + ....: g_eq_maps[deg] = [] + ....: g_eq_maps[deg].extend([i*lefschetz_el for i in basis_deg[deg]]) + ....: + sage: g_eq_maps + {0: [-2*A01 - 2*A02 - 2*A03 - 2*A04 - 2*A12 - 2*A13 - 2*A14 + - 2*A23 - 2*A24 - 2*A34 - 6*A012 - 6*A013 - 6*A014 - 6*A023 + - 6*A024 - 6*A034 - 6*A123 - 6*A124 - 6*A134 - 6*A234 + - 20*A01234], 1: [2*A012^2 + 2*A023^2 + 2*A024^2 + - 10*A02*A01234 + 2*A01234^2, 2*A012^2 + 2*A123^2 + 2*A124^2 + - 10*A12*A01234 + 2*A01234^2, 2*A012^2 + 2*A013^2 + 2*A014^2 + - 10*A01*A01234 + 2*A01234^2, -6*A012^2 + 2*A01*A01234 + + 2*A02*A01234 + 2*A12*A01234, 2*A013^2 + 2*A023^2 + 2*A034^2 + - 10*A03*A01234 + 2*A01234^2, 2*A013^2 + 2*A123^2 + 2*A134^2 + - 10*A13*A01234 + 2*A01234^2, -6*A013^2 + 2*A01*A01234 + + 2*A03*A01234 + 2*A13*A01234, 2*A023^2 + 2*A123^2 + 2*A234^2 + - 10*A23*A01234 + 2*A01234^2, -6*A023^2 + 2*A02*A01234 + + 2*A03*A01234 + 2*A23*A01234, -6*A123^2 + 2*A12*A01234 + + 2*A13*A01234 + 2*A23*A01234, 2*A014^2 + 2*A024^2 + 2*A034^2 + - 10*A04*A01234 + 2*A01234^2, 2*A014^2 + 2*A124^2 + 2*A134^2 + - 10*A14*A01234 + 2*A01234^2, -6*A014^2 + 2*A01*A01234 + + 2*A04*A01234 + 2*A14*A01234, 2*A024^2 + 2*A124^2 + 2*A234^2 + - 10*A24*A01234 + 2*A01234^2, -6*A024^2 + 2*A02*A01234 + + 2*A04*A01234 + 2*A24*A01234, -6*A124^2 + 2*A12*A01234 + + 2*A14*A01234 + 2*A24*A01234, 2*A034^2 + 2*A134^2 + 2*A234^2 + - 10*A34*A01234 + 2*A01234^2, -6*A034^2 + 2*A03*A01234 + + 2*A04*A01234 + 2*A34*A01234, -6*A134^2 + 2*A13*A01234 + + 2*A14*A01234 + 2*A34*A01234, -6*A234^2 + 2*A23*A01234 + + 2*A24*A01234 + 2*A34*A01234, -2*A01*A01234 - 2*A02*A01234 + - 2*A03*A01234 - 2*A04*A01234 - 2*A12*A01234 - 2*A13*A01234 + - 2*A14*A01234 - 2*A23*A01234 - 2*A24*A01234 - 2*A34*A01234 + - 20*A01234^2], 2: [2*A01234^3, 2*A01234^3, 2*A01234^3, + 6*A01234^3, 2*A01234^3, 2*A01234^3, 6*A01234^3, 2*A01234^3, + 6*A01234^3, 6*A01234^3, 2*A01234^3, 2*A01234^3, 6*A01234^3, + 2*A01234^3, 6*A01234^3, 6*A01234^3, 2*A01234^3, 6*A01234^3, + 6*A01234^3, 6*A01234^3, -20*A01234^3], 3: [0]} + """ + w = sum(len(F) * (len(self.matroid().groundset()) - len(F)) * gen + for F, gen in self.defining_ideal().flats_to_generator_dict().items()) + return self.element_class(self, w) + + @cached_method + def poincare_pairing(self, el1, el2): + r""" + Return the Poincaré pairing of any two elements of the + Chow ring. + + EXAMPLES:: + + sage: ch = matroids.Wheel(3).chow_ring(QQ, True, 'atom-free') + sage: A0, A1, A2, A3, A4, A5, A013, A025, A04, A124, A15, A23, A345, A012345 = ch.gens() + sage: u = ch(-1/6*A2*A012345 + 41/48*A012345^2); u + -1/6*A2*A012345 + 41/48*A012345^2 + sage: v = ch(-A345^2 - 1/4*A345); v + -A345^2 - 1/4*A345 + sage: ch.poincare_pairing(v, u) + 3 + """ + r = self.top_degree() + hom_components1 = el1.lift().homogeneous_components() + hom_components2 = el2.lift().homogeneous_components() + new_el = self.base_ring().zero() + for i in hom_components1: + if r - i not in hom_components2: + continue + new_el += hom_components1[i] * hom_components2[r - i] + return new_el.degree() + class Element(QuotientRing_generic.Element): def to_vector(self, order=None): r""" @@ -336,4 +465,4 @@ def homogeneous_degree(self): f = self.lift() if not f.is_homogeneous(): raise ValueError("element is not homogeneous") - return f.degree() \ No newline at end of file + return f.degree() diff --git a/src/sage/matroids/chow_ring_ideal.py b/src/sage/matroids/chow_ring_ideal.py index d0ac04a23ee..00b5592ee42 100644 --- a/src/sage/matroids/chow_ring_ideal.py +++ b/src/sage/matroids/chow_ring_ideal.py @@ -5,6 +5,15 @@ - Shriya M """ +# **************************************************************************** +# Copyright (C) 2024 Shriya M <25shriya at gmail.com> +# +# 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.polynomial.multi_polynomial_ideal import MPolynomialIdeal from sage.matroids.utilities import cmp_elements_key @@ -13,6 +22,7 @@ from sage.combinat.posets.posets import Poset from itertools import product + class ChowRingIdeal(MPolynomialIdeal): def matroid(self): r""" @@ -20,7 +30,7 @@ def matroid(self): EXAMPLES:: - sage: ch = matroids.Uniform(3,6).chow_ring(QQ, False) + sage: ch = matroids.Uniform(3, 6).chow_ring(QQ, False) sage: ch.defining_ideal().matroid() U(3, 6): Matroid of rank 3 on 6 elements with circuit-closures {3: {{0, 1, 2, 3, 4, 5}}} @@ -52,9 +62,43 @@ def _lattice_flats(self): flats = list(lattice_flats) flats.sort(key=lambda X: (len(X), sorted(X))) ranks = {F: self._matroid.rank(F) for F in flats} - chains = lattice_flats.chains() #Only chains + chains = lattice_flats.chains() # Only chains return (ranks, chains) + def flats_to_generator_dict(self): + r""" + Return the corresponding generators of flats/groundset elements of + Chow ring ideal. + + EXAMPLES:: + + sage: ch = matroids.Uniform(4, 6).chow_ring(QQ, True, 'atom-free') + sage: ch.defining_ideal().flats_to_generator_dict() + {frozenset({0}): A0, frozenset({1}): A1, frozenset({2}): A2, + frozenset({3}): A3, frozenset({4}): A4, frozenset({5}): A5, + frozenset({0, 1}): A01, frozenset({0, 2}): A02, + frozenset({0, 3}): A03, frozenset({0, 4}): A04, + frozenset({0, 5}): A05, frozenset({1, 2}): A12, + frozenset({1, 3}): A13, frozenset({1, 4}): A14, + frozenset({1, 5}): A15, frozenset({2, 3}): A23, + frozenset({2, 4}): A24, frozenset({2, 5}): A25, + frozenset({3, 4}): A34, frozenset({3, 5}): A35, + frozenset({4, 5}): A45, frozenset({0, 1, 2}): A012, + frozenset({0, 1, 3}): A013, frozenset({0, 1, 4}): A014, + frozenset({0, 1, 5}): A015, frozenset({0, 2, 3}): A023, + frozenset({0, 2, 4}): A024, frozenset({0, 2, 5}): A025, + frozenset({0, 3, 4}): A034, frozenset({0, 3, 5}): A035, + frozenset({0, 4, 5}): A045, frozenset({1, 2, 3}): A123, + frozenset({1, 2, 4}): A124, frozenset({1, 2, 5}): A125, + frozenset({1, 3, 4}): A134, frozenset({1, 3, 5}): A135, + frozenset({1, 4, 5}): A145, frozenset({2, 3, 4}): A234, + frozenset({2, 3, 5}): A235, frozenset({2, 4, 5}): A245, + frozenset({3, 4, 5}): A345, + frozenset({0, 1, 2, 3, 4, 5}): A012345} + """ + return dict(self._flats_generator) + + class ChowRingIdeal_nonaug(ChowRingIdeal): r""" The Chow ring ideal of a matroid `M`. @@ -93,7 +137,7 @@ class ChowRingIdeal_nonaug(ChowRingIdeal): Chow ring ideal of uniform matroid of rank 3 on 6 elements:: - sage: ch = matroids.Uniform(3,6).chow_ring(QQ, False) + sage: ch = matroids.Uniform(3, 6).chow_ring(QQ, False) sage: ch.defining_ideal() Chow ring ideal of U(3, 6): Matroid of rank 3 on 6 elements with circuit-closures {3: {{0, 1, 2, 3, 4, 5}}} - non augmented @@ -116,8 +160,8 @@ def __init__(self, M, R): for X in self._matroid.flats(i)] names = ['A{}'.format(''.join(str(x) for x in sorted(F, key=cmp_elements_key))) for F in flats] try: - poly_ring = PolynomialRing(R, names) #self.ring - except ValueError: # variables are not proper names + poly_ring = PolynomialRing(R, names) # self.ring + except ValueError: # variables are not proper names poly_ring = PolynomialRing(R, 'A', len(flats)) gens = poly_ring.gens() self._flats_generator = dict(zip(flats, gens)) @@ -392,8 +436,8 @@ def __init__(self, M, R): try: names_groundset = ['A{}'.format(''.join(str(x))) for x in E] names_flats = ['B{}'.format(''.join(str(x) for x in sorted(F, key=cmp_elements_key))) for F in self._flats] - poly_ring = PolynomialRing(R, names_groundset + names_flats) #self.ring() - except ValueError: #variables are not proper names + poly_ring = PolynomialRing(R, names_groundset + names_flats) # self.ring() + except ValueError: # variables are not proper names poly_ring = PolynomialRing(R, 'A', len(E) + len(self._flats)) for i, x in enumerate(E): self._flats_generator[x] = poly_ring.gens()[i] @@ -526,7 +570,7 @@ def groebner_basis(self, algorithm='', *args, **kwargs): for H in lattice_flats.order_filter([F]): term1 += self._flats_generator[H] if term1 != poly_ring.zero(): - gb.append(term1**(self._matroid.rank(F) + 1)) #5.6 (MM2022) + gb.append(term1**(self._matroid.rank(F) + 1)) # 5.6 (MM2022) order_ideal_modified = lattice_flats.order_ideal([F]) order_ideal_modified.remove(F) for G in order_ideal_modified: # nested flats @@ -540,7 +584,7 @@ def normal_basis(self, algorithm='', *args, **kwargs): EXAMPLES:: - sage: ch = matroids.Uniform(2,5).chow_ring(QQ, True, 'fy') + sage: ch = matroids.Uniform(2, 5).chow_ring(QQ, True, 'fy') sage: I = ch.defining_ideal() sage: I.normal_basis() [1, B0, B1, B2, B3, B4, B01234, B01234^2] @@ -643,8 +687,8 @@ def __init__(self, M, R): for X in self._matroid.flats(i)] names = ['A{}'.format(''.join(str(x) for x in sorted(F, key=cmp_elements_key))) for F in self._flats] try: - poly_ring = PolynomialRing(R, names) #self.ring - except ValueError: # variables are not proper names + poly_ring = PolynomialRing(R, names) # self.ring + except ValueError: # variables are not proper names poly_ring = PolynomialRing(R, 'A', len(self._flats)) gens = poly_ring.gens() self._flats_generator = dict(zip(self._flats, gens)) @@ -717,7 +761,7 @@ def groebner_basis(self, algorithm='', *args, **kwargs): EXAMPLES:: - sage: M1 = matroids.Uniform(3,6) + sage: M1 = matroids.Uniform(3, 6) sage: ch = M1.chow_ring(QQ, True, 'atom-free') sage: ch.defining_ideal().groebner_basis(algorithm='') Polynomial Sequence with 253 Polynomials in 22 Variables @@ -797,4 +841,4 @@ def normal_basis(self, algorithm='', *args, **kwargs): for val, c in zip(subset, combination): expression *= flats_gen[val] ** c monomial_basis.append(expression) - return PolynomialSequence(R, [monomial_basis]) \ No newline at end of file + return PolynomialSequence(R, [monomial_basis]) diff --git a/src/sage/matroids/circuit_closures_matroid.pyx b/src/sage/matroids/circuit_closures_matroid.pyx index a4251298ebc..72cd1c4fc16 100644 --- a/src/sage/matroids/circuit_closures_matroid.pyx +++ b/src/sage/matroids/circuit_closures_matroid.pyx @@ -62,7 +62,8 @@ from cpython.object cimport Py_EQ, Py_NE from sage.structure.richcmp cimport rich_to_bool, richcmp from sage.matroids.matroid cimport Matroid from sage.matroids.set_system cimport SetSystem -from sage.matroids.utilities import setprint_s, cmp_elements_key +from sage.matroids.utilities import setprint_s + cdef class CircuitClosuresMatroid(Matroid): r""" diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx index cd44db7772b..a93efd85b33 100644 --- a/src/sage/matroids/circuits_matroid.pyx +++ b/src/sage/matroids/circuits_matroid.pyx @@ -186,7 +186,6 @@ cdef class CircuitsMatroid(Matroid): 6 """ cdef set XX = set(X) - cdef int i cdef frozenset C while True: try: diff --git a/src/sage/matroids/constructor.py b/src/sage/matroids/constructor.py index 8548b2bfede..f1c0af7bea7 100644 --- a/src/sage/matroids/constructor.py +++ b/src/sage/matroids/constructor.py @@ -805,11 +805,11 @@ def Matroid(groundset=None, data=None, **kwds): if isinstance(data, Graph): key = 'graph' elif isinstance(data, Matrix) or ( - isinstance(data, tuple) and isinstance(data[0], Matrix)): + isinstance(data, tuple) and isinstance(data[0], Matrix)): key = 'matrix' elif isinstance(data, sage.modules.with_basis.morphism.ModuleMorphism) or ( - isinstance(data, tuple) and - isinstance(data[0], sage.modules.with_basis.morphism.ModuleMorphism)): + isinstance(data, tuple) and + isinstance(data[0], sage.modules.with_basis.morphism.ModuleMorphism)): key = 'morphism' elif isinstance(data, sage.matroids.matroid.Matroid): key = 'matroid' @@ -1032,11 +1032,9 @@ def revlex_sort_key(s): subsets = sorted(combinations(range(N), rk), key=revlex_sort_key) if len(data) != len(subsets): raise ValueError("expected string of length %s (%s choose %s), got %s" % - (len(subsets), N, rk, len(data))) - bases = [] - for i, x in enumerate(data): - if x != '0': - bases.append([groundset[c] for c in subsets[i]]) + (len(subsets), N, rk, len(data))) + bases = [[groundset[c] for c in subsets[i]] + for i, x in enumerate(data) if x != '0'] M = BasisMatroid(groundset=groundset, bases=bases) # Circuit closures: diff --git a/src/sage/matroids/dual_matroid.py b/src/sage/matroids/dual_matroid.py index d4dce31ddc2..3c7c92e6c9c 100644 --- a/src/sage/matroids/dual_matroid.py +++ b/src/sage/matroids/dual_matroid.py @@ -53,6 +53,7 @@ from sage.matroids.matroid import Matroid + class DualMatroid(Matroid): r""" Dual of a matroid. diff --git a/src/sage/matroids/extension.pyx b/src/sage/matroids/extension.pyx index 778e6d6ef70..83b792e8d2b 100644 --- a/src/sage/matroids/extension.pyx +++ b/src/sage/matroids/extension.pyx @@ -211,6 +211,9 @@ cdef class LinearSubclassesIter: self._nodes = [first_cut] + def __iter__(self): + return self + def __next__(self): """ Return the next linear subclass. diff --git a/src/sage/matroids/graphic_matroid.pyx b/src/sage/matroids/graphic_matroid.pyx index 53bd8adef39..c718535b4aa 100644 --- a/src/sage/matroids/graphic_matroid.pyx +++ b/src/sage/matroids/graphic_matroid.pyx @@ -608,7 +608,7 @@ cdef class GraphicMatroid(Matroid): # then use method from abstract matroid class conset, delset = sanitize_contractions_deletions(self, contractions, deletions) M = self._minor(contractions=conset, deletions=delset) - should_be_true, elements = Matroid._has_minor(M, N, certificate=True) + _, elements = Matroid._has_minor(M, N, certificate=True) # elements is a tuple (contractions, deletions, dict) # There should be no more contractions diff --git a/src/sage/matroids/lean_matrix.pyx b/src/sage/matroids/lean_matrix.pyx index e0f86c6db83..82de4b9a648 100644 --- a/src/sage/matroids/lean_matrix.pyx +++ b/src/sage/matroids/lean_matrix.pyx @@ -521,16 +521,16 @@ cdef class LeanMatrix: for z in range(self.ncols()): if z in P_cols+Q_cols: continue - sol,cert = self.shifting(P_rows,P_cols,Q_rows,Q_cols,z,None,m) + sol, cert = self.shifting(P_rows, P_cols, Q_rows, Q_cols, z, None, m) if sol: return True, cert - sol,cert = self.shifting(Q_rows,Q_cols,P_rows,P_cols,None,z,m) + sol, cert = self.shifting(Q_rows, Q_cols, P_rows, P_cols, None, z, m) if sol: return True, cert - sol,cert = self.shifting(P_rows,P_cols,Q_rows,Q_cols,None,z,m) + sol, cert = self.shifting(P_rows, P_cols, Q_rows, Q_cols, None, z, m) if sol: return True, cert - sol,cert = self.shifting(Q_rows,Q_cols,P_rows,P_cols,z,None,m) + sol, cert = self.shifting(Q_rows, Q_cols, P_rows, P_cols, z, None, m) if sol: return True, cert return False, None @@ -600,26 +600,29 @@ cdef class LeanMatrix: B = self.matrix_from_rows_and_columns(list(U_1), range(len(Y))) B.gauss_jordan_reduce(lV_2) # find a unique representation of every rows in X_3xV_1 using rows in U_2xV_1 - BT = self.matrix_from_rows_and_columns(range(len(X)),list(V_1)).transpose() + BT = self.matrix_from_rows_and_columns(range(len(X)), + list(V_1)).transpose() BT.gauss_jordan_reduce(lU_2) cdef set X_p = set(X_1) cdef set Y_p = set(Y_1) while True: - #rowshifts - X_p_new = set([]) + # rowshifts + X_p_new = set() for x in set(X_3): for y in Y_p: - if sum([BT.get_unsafe(rU[u],x)*self.get_unsafe(u,y) for u in U_2]) != self.get_unsafe(x,y): + if sum([BT.get_unsafe(rU[u], x) * self.get_unsafe(u, y) + for u in U_2]) != self.get_unsafe(x, y): X_1.append(x) X_3.remove(x) X_p_new.add(x) break - #colshifts - Y_p_new = set([]) + # colshifts + Y_p_new = set() for y in set(Y_3): for x in X_p: - if sum([B.get_unsafe(rV[v],y)*self.get_unsafe(x,v) for v in V_2]) != self.get_unsafe(x,y): + if sum([B.get_unsafe(rV[v], y) * self.get_unsafe(x, v) + for v in V_2]) != self.get_unsafe(x, y): Y_1.append(y) Y_3.remove(y) Y_p_new.add(y) @@ -1327,7 +1330,7 @@ cdef class BinaryMatrix(LeanMatrix): for r in range(len(rows)): row = self._M[rows[r]] row2 = A._M[r] - bitset_intersection(row2, row, mask) # yes, this is safe + bitset_intersection(row2, row, mask) # yes, this is safe for g in range(lg): if bitset_in(row, cols[g]): bitset_add(row2, gaps[g]) @@ -2006,8 +2009,8 @@ cdef class TernaryMatrix(LeanMatrix): row1 = self._M1[rows[r]] row0_2 = A._M0[r] row1_2 = A._M1[r] - bitset_intersection(row0_2, row0, mask) # yes, this is safe - bitset_intersection(row1_2, row1, mask) # yes, this is safe + bitset_intersection(row0_2, row0, mask) # yes, this is safe + bitset_intersection(row1_2, row1, mask) # yes, this is safe for g in range(lg): p = cols[g] if bitset_in(row0, p): @@ -2590,7 +2593,7 @@ cdef class QuaternaryMatrix(LeanMatrix): row1 = self._M1[rows[r]] row0_2 = A._M0[r] row1_2 = A._M1[r] - bitset_intersection(row0_2, row0, mask) # yes, this is safe + bitset_intersection(row0_2, row0, mask) # yes, this is safe bitset_intersection(row1_2, row1, mask) for g in range(lg): p = cols[g] @@ -3233,11 +3236,11 @@ cdef class RationalMatrix(LeanMatrix): elif isinstance(M, LeanMatrix): for i in range(M.nrows()): for j in range(M.ncols()): - mpq_set(self._entries[i * self._ncols + j], Rational((M).get_unsafe(i,j)).value) + mpq_set(self._entries[i * self._ncols + j], Rational((M).get_unsafe(i, j)).value) else: # Sage Matrix or otherwise for i in range(M.nrows()): for j in range(M.ncols()): - mpq_set(self._entries[i * self._ncols + j], Rational(M[i,j]).value) + mpq_set(self._entries[i * self._ncols + j], Rational(M[i, j]).value) def __dealloc__(self): """ @@ -3358,7 +3361,7 @@ cdef class RationalMatrix(LeanMatrix): A = RationalMatrix(self._nrows, self._ncols + Mn) for i in range(self._nrows): for j in range(self._ncols): - mpq_set(A._entries[A.index(i,j)], self._entries[self.index(i,j)]) + mpq_set(A._entries[A.index(i, j)], self._entries[self.index(i, j)]) mpq_set(A._entries[i*A._ncols + self._ncols + j], (M)._entries[i*Mn + j]) return A @@ -3366,9 +3369,10 @@ cdef class RationalMatrix(LeanMatrix): cdef RationalMatrix A = RationalMatrix(self._nrows, self._ncols + self._nrows) cdef long i, j for i in range(self._nrows): - mpq_set_si(A._entries[A.index(i,i)], 1, 1) + mpq_set_si(A._entries[A.index(i, i)], 1, 1) for j in range(self._ncols): - mpq_set(A._entries[A.index(i,self._nrows+j)], self._entries[self.index(i,j)]) + mpq_set(A._entries[A.index(i, self._nrows + j)], + self._entries[self.index(i, j)]) return A cpdef base_ring(self): diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 9030ce47f25..02d1d3c28d9 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -2731,15 +2731,15 @@ cdef class LinearMatroid(BasisExchangeMatroid): dX = dict(zip(range(len(X)), X)) dY = dict(zip(range(len(Y)), Y)) - for (x, y) in spanning_forest(M): - P_rows=[x] - P_cols=[y] - Q_rows=[] - Q_cols=[] - sol,cert_pair = M2.shifting_all(P_rows, P_cols, Q_rows, Q_cols, 2) + for x, y in spanning_forest(M): + P_rows = [x] + P_cols = [y] + Q_rows = [] + Q_cols = [] + sol, cert_pair = M2.shifting_all(P_rows, P_cols, Q_rows, Q_cols, 2) if sol: if certificate: - cert = set([]) + cert = set() for x in cert_pair[0]: cert.add(dX[x]) for y in cert_pair[1]: @@ -2795,8 +2795,8 @@ cdef class LinearMatroid(BasisExchangeMatroid): M = M2._matrix_() X, Y = self._current_rows_cols() - dX = dict(zip(range(len(X)),X)) - dY = dict(zip(range(len(Y)),Y)) + dX = dict(zip(range(len(X)), X)) + dY = dict(zip(range(len(Y)), Y)) n = len(X) m = len(Y) @@ -2817,22 +2817,22 @@ cdef class LinearMatroid(BasisExchangeMatroid): Yp = list(range(m)) Yp.remove(y1) - B = B.matrix_from_rows_and_columns(Xp,Yp) + B = B.matrix_from_rows_and_columns(Xp, Yp) # produce a spanning forest of B - for (x,y) in spanning_forest(B): + for x, y in spanning_forest(B): if x >= x1: x = x + 1 if y >= y1: y = y + 1 # rank 2 matrix and rank 0 matrix - P_rows = [x,x1] - P_cols = [y,y1] + P_rows = [x, x1] + P_cols = [y, y1] Q_rows = [] Q_cols = [] # make sure the matrix has rank 2 - if M.matrix_from_rows_and_columns(P_rows,P_cols).rank() == 2: - sol,cert_pair = M2.shifting_all(P_rows, P_cols, Q_rows, Q_cols, 3) + if M.matrix_from_rows_and_columns(P_rows, P_cols).rank() == 2: + sol, cert_pair = M2.shifting_all(P_rows, P_cols, Q_rows, Q_cols, 3) if sol: break # rank 1 matrix and rank 1 matrix @@ -2841,7 +2841,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): Q_rows = [x] Q_cols = [y] # both matrix have rank 1 - sol,cert_pair = M2.shifting_all(P_rows, P_cols, Q_rows, Q_cols, 3) + sol, cert_pair = M2.shifting_all(P_rows, P_cols, Q_rows, Q_cols, 3) if sol: break if sol: @@ -2906,7 +2906,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): if action in Semigroups: G, action = action, G else: - G, action = G_action, None # the None action is g.__call__ + G, action = G_action, None # the None action is g.__call__ from sage.algebras.orlik_terao import OrlikTeraoInvariantAlgebra @@ -3835,7 +3835,7 @@ cdef class BinaryMatroid(LinearMatroid): global GF2 cdef int r, c B= self.basis() - C = [self._fundamental_cocircuit(B,e) for e in B] + C = [self._fundamental_cocircuit(B, e) for e in B] c = 1 col = {} @@ -3850,21 +3850,22 @@ cdef class BinaryMatroid(LinearMatroid): for f in range(e): for g in range(f): if not C[e].issuperset(C[f] & C[g]): - M.append([col[e,f], col[e,g]]) + M.append([col[e, f], col[e, g]]) r += 1 if not C[f].issuperset(C[e] & C[g]): - M.append([col[f,e], col[f,g]]) + M.append([col[f, e], col[f, g]]) r += 1 if not C[g].issuperset(C[e] & C[f]): - M.append([col[g,e], col[g,f]]) + M.append([col[g, e], col[g, f]]) r += 1 if len(C[e] & C[f] & C[g]) > 0: - M.append([0,col[e,f], col[e,g], col[f,e], col[f,g], col[g,e], col[g,f]]) + M.append([0, col[e, f], col[e, g], col[f, e], + col[f, g], col[g, e], col[g, f]]) r += 1 cdef BinaryMatrix m = BinaryMatrix(r, c) for r in range(len(M)): for c in M[r]: - m.set(r,c) + m.set(r, c) # now self is graphic iff there is a binary vector x so that M*x = 0 and x_0 = 1, so: return BinaryMatroid(m).corank(frozenset([0])) > 0 @@ -4730,9 +4731,9 @@ cdef class TernaryMatroid(LinearMatroid): C = [self._idx[f] for f in F] A, C2 = (self._A).matrix_from_rows_and_columns_reordered(R, C) return TernaryMatroid(matrix=A, - groundset=[self._E[c] for c in C2], - basis=bas, - keep_initial_representation=False) + groundset=[self._E[c] for c in C2], + basis=bas, + keep_initial_representation=False) cpdef is_valid(self, certificate=False): r""" @@ -5498,9 +5499,9 @@ cdef class QuaternaryMatroid(LinearMatroid): C = [self._idx[f] for f in F] A, C2 = (self._A).matrix_from_rows_and_columns_reordered(R, C) return QuaternaryMatroid(matrix=A, - groundset=[self._E[c] for c in C2], - basis=bas, - keep_initial_representation=False) + groundset=[self._E[c] for c in C2], + basis=bas, + keep_initial_representation=False) cpdef is_valid(self, certificate=False): r""" @@ -6166,8 +6167,9 @@ cdef class RegularMatroid(LinearMatroid): VO.extend(X) m = isomorphic(HS[2], HO[2], HS[0], VO, 1, 1) if m: - idx={str(f):f for f in other.groundset()} - return {e:idx[m[str(e)]] for e in self.groundset() if str(e) in m} + idx = {str(f): f for f in other.groundset()} + 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""" diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index ff853ba9f5a..fab7b9008bf 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -3415,7 +3415,7 @@ cdef class Matroid(SageObject): if action in Semigroups: G, action = action, G else: - G, action = G_action, None # the None action is g.__call__ + G, action = G_action, None # the None action is g.__call__ from sage.algebras.orlik_solomon import OrlikSolomonInvariantAlgebra @@ -3669,7 +3669,7 @@ cdef class Matroid(SageObject): False """ if self is other: - return {e:e for e in self.groundset()} + return {e: e for e in self.groundset()} if self.full_rank() == other.full_rank(): return SetSystem(self.groundset(), self.nonbases())._isomorphism(SetSystem(other.groundset(), other.nonbases())) else: @@ -5204,7 +5204,7 @@ cdef class Matroid(SageObject): sage: M._connectivity(frozenset('ab'), frozenset('cd')) 2 """ - return len(self._link(S,T)[0]) - self.full_rank() + self.rank(S) + self.rank(T) + return len(self._link(S, T)[0]) - self.full_rank() + self.rank(S) + self.rank(T) cpdef link(self, S, T): r""" @@ -5409,7 +5409,7 @@ cdef class Matroid(SageObject): continue # Given Q1, Q2 partition of Q, find all extensions for r2 in range(r+1): - for R1 in map(set,combinations(R, r2)): + for R1 in map(set, combinations(R, r2)): R2 = R - R1 # F is the set of elements cannot be in the extension of Q1 F = set([]) @@ -5417,7 +5417,7 @@ cdef class Matroid(SageObject): # if Q1|R1 is full if m-len(Q1)-len(R1) == 0: T = frozenset(Q1 | R1) - for B in map(set,combinations(U, m-len(Q2)-len(R2))): + for B in map(set, combinations(U, m-len(Q2)-len(R2))): S = frozenset(Q2 | R2 | B) _, X = self._link(S, T) if self.connectivity(X) < m: @@ -5434,7 +5434,7 @@ cdef class Matroid(SageObject): # extension of Q2 is full if len(F) == m-len(Q2)-len(R2): S = frozenset(Q2 | R2 | F) - for A in map(set, combinations(U,m-len(Q1)-len(R1))): + for A in map(set, combinations(U, m-len(Q1)-len(R1))): T = frozenset(Q1 | R1 | A) _, X = self._link(S, T) if self.connectivity(X) < m: @@ -5669,7 +5669,7 @@ cdef class Matroid(SageObject): T = frozenset([g, h]) I, X = self._link(S, T) # check if connectivity between S,T is < 2 - if len(I) + 2 < self.full_rank(): # note: rank(S) = rank(T) = 2 + if len(I) + 2 < self.full_rank(): # note: rank(S) = rank(T) = 2 if certificate: return False, X else: @@ -5685,7 +5685,7 @@ cdef class Matroid(SageObject): T = frozenset([f, h]) I, X = self._link(S, T) # check if connectivity between S,T is < 2 - if len(I) + 2 < self.full_rank(): # note: rank(S) = rank(T) = 2 + if len(I) + 2 < self.full_rank(): # note: rank(S) = rank(T) = 2 if certificate: return False, X else: @@ -5700,7 +5700,7 @@ cdef class Matroid(SageObject): T = frozenset([e, h]) I, X = self._link(S, T) # check if connectivity between S,T is < 2 - if len(I) + 2 < self.full_rank(): # note: rank(S) = rank(T) = 2 + if len(I) + 2 < self.full_rank(): # note: rank(S) = rank(T) = 2 if certificate: return False, X else: @@ -5774,12 +5774,12 @@ cdef class Matroid(SageObject): for x in (X & self.fundamental_circuit(X, y)): M[rdX[x], rdY[y]]=1 - for (x,y) in spanning_forest(M): - P_rows=set([dX[x]]) - P_cols=set([dY[y]]) - Q_rows=set([]) - Q_cols=set([]) - sol,cert = self._shifting_all(X, P_rows, P_cols, Q_rows, Q_cols, 2) + for x, y in spanning_forest(M): + P_rows = set([dX[x]]) + P_cols = set([dY[y]]) + Q_rows = set() + Q_cols = set() + sol, cert = self._shifting_all(X, P_rows, P_cols, Q_rows, Q_cols, 2) if sol: if certificate: return False, cert @@ -5837,15 +5837,15 @@ cdef class Matroid(SageObject): # the partial matrix M = matrix(len(X), len(Y)) for y in Y: - for x in (X & self.fundamental_circuit(X,y)): - M[rdX[x],rdY[y]]=1 + for x in (X & self.fundamental_circuit(X, y)): + M[rdX[x], rdY[y]] = 1 n = len(X) m = len(Y) # compute a connected set of stars T = spanning_stars(M) - for (x1,y1) in T: + for x1, y1 in T: # The whiting out B = M for (x, y) in product(range(n), range(m)): @@ -5858,20 +5858,20 @@ cdef class Matroid(SageObject): Xp.remove(x1) Yp = list(range(m)) Yp.remove(y1) - B = B.matrix_from_rows_and_columns(Xp,Yp) + B = B.matrix_from_rows_and_columns(Xp, Yp) # produce a spanning forest of B - for (x,y) in spanning_forest(B): + for x, y in spanning_forest(B): if x >= x1: x = x+1 if y >= y1: y = y+1 # rank 2 matrix and rank 0 matrix - P_rows = set([dX[x],dX[x1]]) - P_cols = set([dY[y],dY[y1]]) - Q_rows = set([]) - Q_cols = set([]) - sol,cert = self._shifting_all(X, P_rows, P_cols, Q_rows, Q_cols, 3) + P_rows = set([dX[x], dX[x1]]) + P_cols = set([dY[y], dY[y1]]) + Q_rows = set() + Q_cols = set() + sol, cert = self._shifting_all(X, P_rows, P_cols, Q_rows, Q_cols, 3) if sol: if certificate: return False, cert @@ -5881,7 +5881,7 @@ cdef class Matroid(SageObject): P_cols = set([dY[y1]]) Q_rows = set([dX[x]]) Q_cols = set([dY[y]]) - sol,cert = self._shifting_all(X, P_rows, P_cols, Q_rows, Q_cols, 3) + sol, cert = self._shifting_all(X, P_rows, P_cols, Q_rows, Q_cols, 3) if sol: if certificate: return False, cert @@ -5937,16 +5937,16 @@ cdef class Matroid(SageObject): """ Y = self.groundset()-X for z in (Y - P_cols) - Q_cols: - sol,cert = self._shifting(X,P_rows,P_cols|set([z]),Q_rows,Q_cols,m) + sol, cert = self._shifting(X, P_rows, P_cols|set([z]), Q_rows, Q_cols, m) if sol: return True, cert - sol,cert = self._shifting(X,Q_rows,Q_cols,P_rows,P_cols|set([z]),m) + sol, cert = self._shifting(X, Q_rows, Q_cols, P_rows, P_cols|set([z]), m) if sol: return True, cert - sol,cert = self._shifting(X,P_rows,P_cols,Q_rows,Q_cols|set([z]),m) + sol, cert = self._shifting(X, P_rows, P_cols, Q_rows, Q_cols|set([z]), m) if sol: return True, cert - sol,cert = self._shifting(X,Q_rows,Q_cols|set([z]),P_rows,P_cols,m) + sol, cert = self._shifting(X, Q_rows, Q_cols|set([z]), P_rows, P_cols, m) if sol: return True, cert return False, None @@ -6008,26 +6008,26 @@ cdef class Matroid(SageObject): Y = self.groundset()-X # Returns true if there is a m-separator if (self._rank(Y_2|(X-X_1)) - len(X-X_1) - + self._rank(Y_1|(X-X_2)) - len(X-X_2) != m-1): + + self._rank(Y_1|(X-X_2)) - len(X-X_2) != m-1): return False, None if len(X_1|Y_1) < m: return False, None remainX = set(X-(X_1|X_2)) remainY = set(Y-(Y_1|Y_2)) while True: - #rowshifts + # rowshifts rowshift = False for x in set(remainX): if (self._rank(Y_1|(X-(X_2|set([x])))) - len(X-(X_2|set([x]))) - > self._rank(Y_1|(X-X_2)) - len(X-X_2)): + > self._rank(Y_1|(X-X_2)) - len(X-X_2)): X_1 = X_1 | {x} remainX.remove(x) rowshift = True - #colshifts + # colshifts colshift = False for y in set(remainY): if (self._rank(Y_2|set([y])|(X-X_1)) - len(X-X_1) - > self._rank(Y_2|(X-X_1)) - len(X-X_1)): + > self._rank(Y_2|(X-X_1)) - len(X-X_1)): Y_1 = Y_1 | {y} remainY.remove(y) colshift = True @@ -6353,7 +6353,7 @@ cdef class Matroid(SageObject): True """ M = self._local_binary_matroid() - m = {e:e for e in self.groundset()} + m = {e: e for e in self.groundset()} if randomized_tests > 0: E = list(self.groundset()) for r in range(randomized_tests): @@ -6458,20 +6458,20 @@ cdef class Matroid(SageObject): for C in G.connected_components_subgraphs(): T.update(C.min_spanning_tree()) for edge in T: - e,f = edge[2] - A.set(bdx[e],idx[f], 1) + e, f = edge[2] + A.set(bdx[e], idx[f], 1) W = list(set(G.edges(sort=False)) - set(T)) H = G.subgraph(edges = T) while W: edge = W.pop(-1) - e,f = edge[2] + e, f = edge[2] path = H.shortest_path(e, f) for i in range(len(W)): edge2 = W[i] if edge2[0] in path and edge2[1] in path: W[i] = edge edge = edge2 - e,f = edge[2] + e, f = edge[2] while path[0]!= e and path[0] != f: path.pop(0) while path[-1]!= e and path[-1] != f: @@ -6485,9 +6485,9 @@ cdef class Matroid(SageObject): else: x = x * A.get(bdx[path[i+1]], idx[path[i]]) if (len(path) % 4 == 0) == self.is_dependent(set(basis).symmetric_difference(path)): - A.set(bdx[e],idx[f],x) + A.set(bdx[e], idx[f], x) else: - A.set(bdx[e],idx[f],-x) + A.set(bdx[e], idx[f], -x) H.add_edge(edge) from sage.matroids.linear_matroid import TernaryMatroid return TernaryMatroid(groundset=E, matrix=A, basis=basis, keep_initial_representation=False) @@ -6534,7 +6534,7 @@ cdef class Matroid(SageObject): NonFano: Ternary matroid of rank 3 on 7 elements, type 0- """ M = self._local_ternary_matroid() - m = {e:e for e in self.groundset()} + m = {e: e for e in self.groundset()} if randomized_tests > 0: E = list(self.groundset()) for r in range(randomized_tests): @@ -6816,7 +6816,7 @@ cdef class Matroid(SageObject): """ cdef frozenset C if k2 is None: - k2 = len(self.groundset()) + 1 # This is always larger than the rank + k2 = len(self.groundset()) + 1 # This is always larger than the rank for C in self.circuits_iterator(): if len(C) < k1 or len(C) > k2: continue @@ -7478,7 +7478,7 @@ cdef class Matroid(SageObject): todo = set(X1) next_layer = set() while todo: - while todo: # todo is subset of X + while todo: # todo is subset of X u = todo.pop() m = w[u] if u not in out_neighbors: @@ -7491,7 +7491,7 @@ cdef class Matroid(SageObject): next_layer.add(y) todo = next_layer next_layer = set() - while todo: # todo is subset of Y + while todo: # todo is subset of Y u = todo.pop() m = w[u] if u not in out_neighbors: @@ -7505,11 +7505,11 @@ cdef class Matroid(SageObject): todo = next_layer next_layer = set() - X3 = X2.intersection(w) # w is the set of elements reachable from X1 - if not X3: # if no path from X1 to X2, then no augmenting set exists + X3 = X2.intersection(w) # w is the set of elements reachable from X1 + if not X3: # if no path from X1 to X2, then no augmenting set exists return False, frozenset(w) else: - s = min([w[x] for x in X3]) # find shortest length of an X1 - X2 path + s = min([w[x] for x in X3]) # find shortest length of an X1 - X2 path for u in X3: if w[u] == s: break @@ -7639,7 +7639,7 @@ cdef class Matroid(SageObject): layers[dist] = set(todo) if X3: break - while todo: # todo is subset of X + while todo: # todo is subset of X u = todo.pop() m = w[u] if u not in out_neighbors: @@ -7658,7 +7658,7 @@ cdef class Matroid(SageObject): break if not todo: break - while todo: # todo is subset of Y + while todo: # todo is subset of Y u = todo.pop() m = w[u] if u not in out_neighbors: @@ -7708,15 +7708,13 @@ cdef class Matroid(SageObject): for v in layers[d[u]+1] - visited: # check if edge (u,v) exists in the auxiliary digraph exist = False - if ((u in Y) and - (v in E-Y) and - (self.is_dependent(Y|set([v]))) and - (self.is_independent((Y|set([v])) - set([u])))): + if ((u in Y) and (v in E-Y) and + (self.is_dependent(Y|{v})) and + (self.is_independent((Y|{v}) - {u}))): exist = True - if ((u in E-Y) and - (v in Y) and - (not other.is_independent(Y|set([u]))) and - (other.is_independent((Y|set([u])) - set([v])))): + if ((u in E-Y) and (v in Y) and + (not other.is_independent(Y|{u})) and + (other.is_independent((Y|{u}) - {v}))): exist = True if exist: stack.append(v) @@ -8172,8 +8170,8 @@ cdef class Matroid(SageObject): B = list(self.basis()) elif B is not None and not self.is_basis(B): return - lineorders2=matroids_plot_helpers.lineorders_union(self._cached_info['lineorders'],lineorders) - return matroids_plot_helpers.geomrep(self,B,lineorders2,pd=pos_dict, sp=save_pos) + lineorders2 = matroids_plot_helpers.lineorders_union(self._cached_info['lineorders'], lineorders) + return matroids_plot_helpers.geomrep(self, B, lineorders2, pd=pos_dict, sp=save_pos) cpdef show(self, B=None, lineorders=None, pos_method=None, pos_dict=None, save_pos=False, lims=None): """ @@ -8216,12 +8214,12 @@ cdef class Matroid(SageObject): B = list(self.basis()) elif B is not None and not self.is_basis(B): return - B1=B - lineorders1=lineorders - pm=pos_method - pd=pos_dict - sp=save_pos - G=self.plot(B1,lineorders1,pm,pd,sp) + B1 = B + lineorders1 = lineorders + pm = pos_method + pd = pos_dict + sp = save_pos + G = self.plot(B1, lineorders1, pm, pd, sp) if lims is None: G.show() else: @@ -8265,7 +8263,7 @@ cdef class Matroid(SageObject): # check sanity of pos_dict and add it to cached info if sane if pos_dict is not None: from sage.matroids import matroids_plot_helpers - if matroids_plot_helpers.posdict_is_sane(self,pos_dict): + if matroids_plot_helpers.posdict_is_sane(self, pos_dict): self._cached_info = {'plot_positions': pos_dict, 'lineorders': lineorders} return @@ -8461,11 +8459,11 @@ cdef class Matroid(SageObject): # constructed yet. DM = IM.disjoint_union(SimplicialComplex()) - ## simplices are \{y_i\}_{i\in I}\cup\{x_{F_1},\ldots,x_{F_\ell}\}, - ## by [BMHPW20a]_ thm 4 it is pure of dimension r(M)-1 + # simplices are \{y_i\}_{i\in I}\cup\{x_{F_1},\ldots,x_{F_\ell}\}, + # by [BMHPW20a]_ thm 4 it is pure of dimension r(M)-1 for c in LM.chains(exclude=LM.maximal_elements()): - if c: # the facets of IM are already present + if c: # the facets of IM are already present # get the cardinality of intersection of facet with IM r = self._rank(self.groundset()) - len(c) diff --git a/src/sage/matroids/meson.build b/src/sage/matroids/meson.build index f60970da5b9..8fd8ae12895 100644 --- a/src/sage/matroids/meson.build +++ b/src/sage/matroids/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'advanced.py', 'all.py', 'basis_exchange_matroid.pxd', diff --git a/src/sage/matroids/set_system.pyx b/src/sage/matroids/set_system.pyx index d9a2f631fbf..0bf9cb2b7fa 100644 --- a/src/sage/matroids/set_system.pyx +++ b/src/sage/matroids/set_system.pyx @@ -772,6 +772,9 @@ cdef class SetSystemIterator: self._pointer = -1 self._len = len(H) + def __iter__(self): + return self + def __next__(self): """ Return the next subset of a SetSystem. diff --git a/src/sage/matroids/union_matroid.pyx b/src/sage/matroids/union_matroid.pyx index e371d5fb313..86c78c8463d 100644 --- a/src/sage/matroids/union_matroid.pyx +++ b/src/sage/matroids/union_matroid.pyx @@ -97,11 +97,11 @@ cdef class MatroidUnion(Matroid): summands.append(e.delete(e.groundset()-X)) sum_matroid = MatroidSum(summands) d = {} - for (i,x) in sum_matroid.groundset(): + for i, x in sum_matroid.groundset(): if x not in d: - d[x]=set() + d[x] = set() d[x].add(i) - part_matroid = PartitionMatroid([[(i,x) for i in d[x]] for x in d]) + part_matroid = PartitionMatroid([[(i, x) for i in d[x]] for x in d]) return len(sum_matroid._intersection_unweighted(part_matroid)) def _repr_(self): @@ -156,7 +156,7 @@ cdef class MatroidSum(Matroid): E = set() for i in range(len(self.summands)): g = self.summands[i].groundset() - E.update(zip([i]*len(g),g)) + E.update(zip([i] * len(g), g)) self._groundset = frozenset(E) def _repr_(self): diff --git a/src/sage/matroids/utilities.py b/src/sage/matroids/utilities.py index c9b903594c5..eb8b493c2e0 100644 --- a/src/sage/matroids/utilities.py +++ b/src/sage/matroids/utilities.py @@ -792,7 +792,6 @@ def split_vertex(G, u, v=None, edges=None): G.delete_edge(e) # This modifies the graph without needing to return anything - return def cmp_elements_key(x): diff --git a/src/sage/meson.build b/src/sage/meson.build index 80b2a030518..d0cf55161b9 100644 --- a/src/sage/meson.build +++ b/src/sage/meson.build @@ -86,6 +86,7 @@ foreach package : no_processing endforeach py.install_sources( + '__init__.py', 'all.py', 'all__sagemath_bliss.py', 'all__sagemath_categories.py', diff --git a/src/sage/misc/binary_tree.pxd b/src/sage/misc/binary_tree.pxd index 4e54f74a71a..1200b4b3d95 100644 --- a/src/sage/misc/binary_tree.pxd +++ b/src/sage/misc/binary_tree.pxd @@ -4,24 +4,24 @@ cdef struct binary_tree_node: binary_tree_node *right void *value -#cdef binary_tree_node *BinaryTreeNode(int, object) -#cdef void free_binary_tree_node(binary_tree_node *) -#cdef void binary_tree_dealloc(binary_tree_node *) -#cdef void binary_tree_insert(binary_tree_node *self, int, object) -#cdef object binary_tree_get(binary_tree_node *, int) -#cdef object binary_tree_delete(binary_tree_node *, int) -#cdef binary_tree_node *binary_tree_left_excise(binary_tree_node *) -#cdef binary_tree_node *binary_tree_right_excise(binary_tree_node *) -#cdef binary_tree_node *binary_tree_head_excise(binary_tree_node *) -#cdef object binary_tree_list(binary_tree_node *, int) +# cdef binary_tree_node *BinaryTreeNode(int, object) +# cdef void free_binary_tree_node(binary_tree_node *) +# cdef void binary_tree_dealloc(binary_tree_node *) +# cdef void binary_tree_insert(binary_tree_node *self, int, object) +# cdef object binary_tree_get(binary_tree_node *, int) +# cdef object binary_tree_delete(binary_tree_node *, int) +# cdef binary_tree_node *binary_tree_left_excise(binary_tree_node *) +# cdef binary_tree_node *binary_tree_right_excise(binary_tree_node *) +# cdef binary_tree_node *binary_tree_head_excise(binary_tree_node *) +# cdef object binary_tree_list(binary_tree_node *, int) -#cdef int LIST_PREORDER, LIST_POSTORDER, LIST_INORDER, LIST_KEYS, LIST_VALUES -#LIST_PREORDER = 1 -#LIST_INORDER = 2 -#LIST_POSTORDER = 4 -#LIST_KEYS = 8 -#LIST_VALUES = 16 +# cdef int LIST_PREORDER, LIST_POSTORDER, LIST_INORDER, LIST_KEYS, LIST_VALUES +# LIST_PREORDER = 1 +# LIST_INORDER = 2 +# LIST_POSTORDER = 4 +# LIST_KEYS = 8 +# LIST_VALUES = 16 cdef class BinaryTree: diff --git a/src/sage/misc/binary_tree.pyx b/src/sage/misc/binary_tree.pyx index 0756218e53c..14111178271 100644 --- a/src/sage/misc/binary_tree.pyx +++ b/src/sage/misc/binary_tree.pyx @@ -145,7 +145,7 @@ cdef binary_tree_node *binary_tree_head_excise(binary_tree_node *self) noexcept: cdef int LIST_PREORDER, LIST_POSTORDER, LIST_INORDER, LIST_KEYS, LIST_VALUES -LIST_PREORDER = 1 +LIST_PREORDER = 1 LIST_INORDER = 2 LIST_POSTORDER = 4 LIST_KEYS = 8 diff --git a/src/sage/misc/bindable_class.py b/src/sage/misc/bindable_class.py index 743b5a19da6..c23ba0c2c43 100644 --- a/src/sage/misc/bindable_class.py +++ b/src/sage/misc/bindable_class.py @@ -113,7 +113,7 @@ class BindableClass(metaclass=ClasscallMetaclass): Still, documentation works as usual:: sage: outer.Inner.__doc__ - ' some documentation ' + '...some documentation ' TESTS:: diff --git a/src/sage/misc/c3.pyx b/src/sage/misc/c3.pyx index 8dc7e9a9feb..9329065a27b 100644 --- a/src/sage/misc/c3.pyx +++ b/src/sage/misc/c3.pyx @@ -192,9 +192,10 @@ cpdef list C3_algorithm(object start, str bases, str attribute, bint proper): cdef object O, X cdef list tails = [getattr(obj, attribute) for obj in args] tails.append(args) - tails = [list(reversed(tail)) for tail in tails] - cdef list heads = [tail.pop() for tail in tails] - cdef list tailsets = [set([O for O in tail]) for tail in tails] + tails = [list(reversed(tail)) for tail in tails] + cdef list heads = [tail.pop() for tail in tails] + cdef list tailsets = [set([O for O in tail]) + for tail in tails] cdef int i, j, nbheads nbheads = len(heads) diff --git a/src/sage/misc/c3_controlled.pyx b/src/sage/misc/c3_controlled.pyx index 885dcf673f0..765e83fbec2 100644 --- a/src/sage/misc/c3_controlled.pyx +++ b/src/sage/misc/c3_controlled.pyx @@ -380,7 +380,7 @@ cdef tuple atoms = ("FacadeSets", "MagmasAndAdditiveMagmas", "Rngs", "Domains", "HopfAlgebras") -cdef dict flags = { atom: 1 << i for i,atom in enumerate(atoms) } +cdef dict flags = {atom: 1 << i for i, atom in enumerate(atoms)} cdef class CmpKey: r""" @@ -574,7 +574,7 @@ cdef class CmpKeyNamed: return result except KeyError: pass - result = _cmp_key.__get__(inst,cls) + result = _cmp_key.__get__(inst, cls) D[key] = result return result @@ -615,9 +615,9 @@ def C3_merge(list lists): cdef list tail, l cdef set tailset - cdef list tails = [l[::-1] for l in lists if l] - cdef list heads = [tail.pop() for tail in tails] - cdef list tailsets = [set(O for O in tail) for tail in tails] # + cdef list tails = [l[::-1] for l in lists if l] + cdef list heads = [tail.pop() for tail in tails] + cdef list tailsets = [set(O for O in tail) for tail in tails] # cdef int i, j, nbheads nbheads = len(heads) @@ -632,7 +632,7 @@ def C3_merge(list lists): if j == i: continue tailset = tailsets[j] - if O in tailset: # O + if O in tailset: # O next_item_found = False break if next_item_found: @@ -641,13 +641,13 @@ def C3_merge(list lists): # if the tail is already empty. # j goes down so that ``del heads[j]`` does not screw up the numbering for j in range(nbheads-1, -1, -1): - if heads[j] == O: # is O + if heads[j] == O: # is O tail = tails[j] if tail: X = tail.pop() heads[j] = X tailset = tailsets[j] - tailset.remove(X) # X) + tailset.remove(X) # X) else: del heads[j] del tails[j] @@ -792,7 +792,7 @@ cpdef tuple C3_sorted_merge(list lists, key=identity): lists = list(lists) if not lists: raise ValueError("The input should be a non empty list of lists (or iterables)") - #for l in lists: + # for l in lists: # assert sorted(l, key = key, reverse=True) == l,\ # "Each input list should be sorted %s"%l @@ -819,10 +819,10 @@ cpdef tuple C3_sorted_merge(list lists, key=identity): cdef list tail, l cdef set tailset - cdef list tails = [l[::-1] for l in lists if l] - cdef list heads = [tail.pop() for tail in tails] + cdef list tails = [l[::-1] for l in lists if l] + cdef list heads = [tail.pop() for tail in tails] cdef set tmp_set - cdef list tailsets = [] # remove closure [set(key(O) for O in tail) for tail in tails] + cdef list tailsets = [] # remove closure [set(key(O) for O in tail) for tail in tails] for tail in tails: tmp_set = set() for O in tail: @@ -855,10 +855,10 @@ cpdef tuple C3_sorted_merge(list lists, key=identity): # "keys should be distinct"%(tails[i]) while nbheads: - #print_state() - #check_state() + # print_state() + # check_state() # Find the position of the largest head which will become the next item - max_i = 0 + max_i = 0 max_key = key(heads[0]) for i in range(1, nbheads): O = heads[i] @@ -915,10 +915,10 @@ cpdef tuple C3_sorted_merge(list lists, key=identity): # Use a heap or something for fast sorted insertion? # Since Python uses TimSort, that's probably not so bad. tails[-1].append(O) - tails[-1].sort(key = key) + tails[-1].sort(key=key) tailsets[-1].add(O_key) suggestion.add(O) - #check_state() + # check_state() # Insert max_value in the last list, if needed to hold off the bad items if max_bad is not None: @@ -927,10 +927,10 @@ cpdef tuple C3_sorted_merge(list lists, key=identity): if last_head is not None and last_head != max_bad: tails[-1].append(last_head) tailsets[-1].add(key(last_head)) - #check_state() + # check_state() heads[-1] = max_value holder[max_bad] = max_value - #check_state() + # check_state() out.append(max_value) # Clear O from other heads, removing the line altogether @@ -951,10 +951,10 @@ cpdef tuple C3_sorted_merge(list lists, key=identity): nbheads -= 1 if last_list_non_empty and j == nbheads: last_list_non_empty = False - #check_state() + # check_state() suggestion.update(holder.values()) cdef list suggestion_list = sorted(suggestion, key=key, reverse=True) - #assert C3_merge(lists[:-1]+[suggestion_list]) == out + # assert C3_merge(lists[:-1]+[suggestion_list]) == out return (out, suggestion_list) @@ -1373,7 +1373,7 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): sage: sorted([x.value for x in HierarchyElement(10, P).all_bases()]) [1, 2, 5, 10] """ - return {self} | { x for base in self._bases for x in base.all_bases() } + return {self} | {x for base in self._bases for x in base.all_bases()} def all_bases_len(self): """ @@ -1386,7 +1386,7 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): sage: HierarchyElement(30, P).all_bases_len() # needs sage.graphs 12 """ - return sum( len(x._bases) for x in self.all_bases()) + return sum(len(x._bases) for x in self.all_bases()) def all_bases_controlled_len(self): """ @@ -1399,4 +1399,4 @@ class HierarchyElement(object, metaclass=ClasscallMetaclass): sage: HierarchyElement(30, P).all_bases_controlled_len() # needs sage.graphs 13 """ - return sum( len(x._bases_controlled) for x in self.all_bases()) + return sum(len(x._bases_controlled) for x in self.all_bases()) diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index 52c10174dca..df4fa8d4457 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -442,20 +442,21 @@ from inspect import isfunction from sage.misc.weak_dict cimport CachedWeakValueDictionary from sage.misc.decorators import decorator_keywords -cdef frozenset special_method_names = frozenset(['__abs__', '__add__', - '__and__', '__call__', '__cmp__', '__coerce__', '__complex__', '__contains__', '__del__', - '__delattr__', '__delete__', '__delitem__', '__delslice__', '__dir__', '__div__', - '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__get__', '__getattr__', - '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__hex__', - '__iadd__', '__iand__', '__idiv__', '__ifloordiv__', '__ilshift__', '__imod__', '__imul__', - '__index__', '__init__', '__instancecheck__', '__int__', '__invert__', '__ior__', '__ipow__', - '__irshift__', '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__', - '__length_hint__', '__long__', '__lshift__', '__lt__', '__missing__', '__mod__', '__mul__', - '__ne__', '__neg__', '__new__', '__oct__', '__or__', '__pos__', '__pow__', - '__radd__', '__rand__', '__rdiv__', '__repr__', '__reversed__', '__rfloordiv__', '__rlshift__', - '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', - '__rtruediv__', '__rxor__', '__set__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', - '__str__', '__sub__', '__subclasscheck__', '__truediv__', '__unicode__', '__xor__', 'next']) +cdef frozenset special_method_names = frozenset( + ['__abs__', '__add__', + '__and__', '__call__', '__cmp__', '__coerce__', '__complex__', '__contains__', '__del__', + '__delattr__', '__delete__', '__delitem__', '__delslice__', '__dir__', '__div__', + '__eq__', '__float__', '__floordiv__', '__format__', '__ge__', '__get__', '__getattr__', + '__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__', '__hex__', + '__iadd__', '__iand__', '__idiv__', '__ifloordiv__', '__ilshift__', '__imod__', '__imul__', + '__index__', '__init__', '__instancecheck__', '__int__', '__invert__', '__ior__', '__ipow__', + '__irshift__', '__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__', + '__length_hint__', '__long__', '__lshift__', '__lt__', '__missing__', '__mod__', '__mul__', + '__ne__', '__neg__', '__new__', '__oct__', '__or__', '__pos__', '__pow__', + '__radd__', '__rand__', '__rdiv__', '__repr__', '__reversed__', '__rfloordiv__', '__rlshift__', + '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', + '__rtruediv__', '__rxor__', '__set__', '__setattr__', '__setitem__', '__setslice__', '__sizeof__', + '__str__', '__sub__', '__subclasscheck__', '__truediv__', '__unicode__', '__xor__', 'next']) def _cached_function_unpickle(module, name, cache=None): @@ -500,7 +501,7 @@ def _cached_function_unpickle(module, name, cache=None): sage: f(0) 0 """ - ret = getattr(__import__(module, fromlist=['']),name) + ret = getattr(__import__(module, fromlist=['']), name) if cache is not None: ret.cache.update(cache) return ret @@ -777,8 +778,9 @@ cdef class CachedFunction(): self.__cached_module__ = f.__module__ except AttributeError: self.__cached_module__ = f.__objclass__.__module__ - if argument_fixer is not None: # it is None unless the argument fixer - # was known previously. See #15038. + if argument_fixer is not None: + # it is None unless the argument fixer + # was known previously. See #15038. self._argument_fixer = argument_fixer @property @@ -811,7 +813,7 @@ cdef class CachedFunction(): -1 """ self._argument_fixer = ArgumentFixer(self.f, - classmethod=self.is_classmethod) + classmethod=self.is_classmethod) cdef fix_args_kwds(self, tuple args, dict kwds): r""" @@ -848,10 +850,10 @@ cdef class CachedFunction(): return _cached_function_unpickle, (self.__cached_module__, self.__name__, self.cache) ######### - ## Introspection - ## - ## We provide some methods explicitly, and - ## forward other questions to the cached function. + # Introspection + # + # We provide some methods explicitly, and + # forward other questions to the cached function. def _instancedoc_(self): """ @@ -894,15 +896,15 @@ cdef class CachedFunction(): try: sourcelines = sage_getsourcelines(f) filename = sage_getfile_relative(f) - #this is a rather expensive way of getting the line number, because - #retrieving the source requires reading the source file and in many - #cases this is not required (in cython it's embedded in the docstring, - #on code objects you'll find it in co_filename and co_firstlineno) - #however, this hasn't been factored out yet in sageinspect - #and the logic in sage_getsourcelines is rather intricate. - file_info = "File: {} (starting at line {})".format(filename,sourcelines[1])+os.linesep - - doc = file_info+doc + # this is a rather expensive way of getting the line number, because + # retrieving the source requires reading the source file and in many + # cases this is not required (in cython it's embedded in the docstring, + # on code objects you'll find it in co_filename and co_firstlineno) + # however, this hasn't been factored out yet in sageinspect + # and the logic in sage_getsourcelines is rather intricate. + file_info = "File: {} (starting at line {})".format(filename, sourcelines[1]) + os.linesep + + doc = file_info + doc except IOError: pass return doc @@ -1249,7 +1251,7 @@ cdef class CachedFunction(): ak = normalize_input(a) if self.get_key_args_kwds(ak[0], ak[1]) not in self.cache: arglist2.append(ak) - for ((args,kwargs), val) in P(arglist2): + for ((args, kwargs), val) in P(arglist2): self.set_cache(val, *args, **kwargs) @@ -1462,7 +1464,7 @@ class CachedMethodPickle(): we replace the actual cached method by a place holder, that kills itself as soon as any attribute is requested. Then, the original cached attribute is reinstated. But the - cached values are in fact saved (if `do_pickle` is set.) + cached values are in fact saved (if ``do_pickle`` is set.) EXAMPLES:: @@ -1605,7 +1607,7 @@ class CachedMethodPickle(): x^2*y*z^3 - x*y^2*z^3 + 2*y^3*z^3 + z^6, x*y^3 + y^4 + x*z^3, x^3 + y^3 + z^3]} """ - return CachedMethodPickle,(self._instance,self._name,self._cache) + return CachedMethodPickle, (self._instance, self._name, self._cache) def __call__(self, *args, **kwds): """ @@ -1629,7 +1631,7 @@ class CachedMethodPickle(): Cached version of """ self._instance.__dict__.__delitem__(self._name) - CM = getattr(self._instance,self._name) + CM = getattr(self._instance, self._name) if self._cache is not None: if isinstance(CM, CachedMethodCallerNoArgs): CM.cache = self._cache @@ -1667,14 +1669,14 @@ class CachedMethodPickle(): Cached version of """ self._instance.__dict__.__delitem__(self._name) - CM = getattr(self._instance,self._name) + CM = getattr(self._instance, self._name) if self._cache is not None: if isinstance(CM, CachedMethodCallerNoArgs): CM.cache = self._cache else: for k, v in self._cache: CM.cache[k] = v - return getattr(CM,s) + return getattr(CM, s) cdef class CachedMethodCaller(CachedFunction): @@ -1786,10 +1788,10 @@ cdef class CachedMethodCaller(CachedFunction): sage: J.groebner_basis Cached version of """ - if isinstance(self._cachedmethod, CachedInParentMethod) or hasattr(self._instance,self._cachedmethod._cache_name): - return CachedMethodPickle,(self._instance,self.__name__) + if isinstance(self._cachedmethod, CachedInParentMethod) or hasattr(self._instance, self._cachedmethod._cache_name): + return CachedMethodPickle, (self._instance, self.__name__) else: - return CachedMethodPickle,(self._instance,self.__name__,self.cache) + return CachedMethodPickle, (self._instance, self.__name__, self.cache) def _instance_call(self, *args, **kwds): """ @@ -2086,11 +2088,12 @@ cdef class CachedMethodCaller(CachedFunction): cls = type(self) Caller = cls(self._cachedmethod, inst, - cache=self._cachedmethod._get_instance_cache(inst), - name=self._cachedmethod._cachedfunc.__name__, key=self.key, do_pickle=self.do_pickle) + cache=self._cachedmethod._get_instance_cache(inst), + name=self._cachedmethod._cachedfunc.__name__, + key=self.key, do_pickle=self.do_pickle) try: - setattr(inst,self._cachedmethod._cachedfunc.__name__, Caller) + setattr(inst, self._cachedmethod._cachedfunc.__name__, Caller) return Caller except AttributeError: pass @@ -2139,7 +2142,7 @@ cdef class CachedMethodCaller(CachedFunction): ak = normalize_input(a) if self.get_key_args_kwds(ak[0], ak[1]) not in self.cache: arglist2.append(ak) - for ((args,kwargs), val) in P(arglist2): + for ((args, kwargs), val) in P(arglist2): self.set_cache(val, *args, **kwargs) @@ -2227,12 +2230,12 @@ cdef class CachedMethodCallerNoArgs(CachedFunction): 4 """ # initialize CachedFunction - if isinstance(f,str): + if isinstance(f, str): try: - F = getattr(inst.__class__,f) + F = getattr(inst.__class__, f) except AttributeError: - F = getattr(inst,f) - if isinstance(F,CachedFunction): + F = getattr(inst, f) + if isinstance(F, CachedFunction): f = F.f else: f = F @@ -2277,9 +2280,8 @@ cdef class CachedMethodCallerNoArgs(CachedFunction): Cached version of """ if self.do_pickle: - return CachedMethodPickle,(self._instance, self.__name__, self.cache) - else: - return CachedMethodPickle,(self._instance, self.__name__) + return CachedMethodPickle, (self._instance, self.__name__, self.cache) + return CachedMethodPickle, (self._instance, self.__name__) def _instance_call(self): """ @@ -2465,7 +2467,7 @@ cdef class CachedMethodCallerNoArgs(CachedFunction): pass Caller = CachedMethodCallerNoArgs(inst, self.f, name=self.__name__, do_pickle=self.do_pickle) try: - setattr(inst,self.__name__, Caller) + setattr(inst, self.__name__, Caller) return Caller except AttributeError: pass @@ -2827,7 +2829,7 @@ cdef class CachedMethod(): if self.nargs == 0: if isinstance(f, object) and not isfunction(f): try: - if METH_NOARGS&PyCFunction_GetFlags(f.__get__(inst,cls)): + if METH_NOARGS&PyCFunction_GetFlags(f.__get__(inst, cls)): self.nargs = 1 except Exception: pass @@ -2971,7 +2973,7 @@ cdef class CachedSpecialMethod(CachedMethod): self.nargs = 1 Caller = CachedMethodCallerNoArgs(inst, f, name=name, do_pickle=self._cachedfunc.do_pickle) else: - self.nargs = 2 # don't need the exact number + self.nargs = 2 # don't need the exact number Caller = CachedMethodCaller(self, inst, cache=self._get_instance_cache(inst), name=name, @@ -2987,7 +2989,7 @@ cdef class CachedSpecialMethod(CachedMethod): do_pickle=self._cachedfunc.do_pickle) if inst is not None: try: - setattr(inst,name, Caller) + setattr(inst, name, Caller) return Caller except AttributeError: pass @@ -3280,7 +3282,7 @@ cdef class CachedInParentMethod(CachedMethod): return P.__dict__.setdefault(self._cache_name, default) except AttributeError: pass - if not hasattr(P,'_cached_methods'): + if not hasattr(P, '_cached_methods'): raise TypeError("The parent of this element does not allow attribute assignment\n" + " and does not descend from the Parent base class.\n" + " Cannot use CachedInParentMethod.") @@ -3295,7 +3297,7 @@ cdef class CachedInParentMethod(CachedMethod): """ Caller = GloballyCachedMethodCaller(self, inst, cache=self._get_instance_cache(inst), key=self._cachedfunc.key, do_pickle=self._cachedfunc.do_pickle) try: - setattr(inst,self._cachedfunc.__name__, Caller) + setattr(inst, self._cachedfunc.__name__, Caller) except AttributeError: pass return Caller @@ -3382,7 +3384,7 @@ class FileCache(): l = len(prefix) for f in os.listdir(dir): if f[:l] == prefix: - files.append( dir + f ) + files.append(dir + f) return files def items(self): @@ -3601,7 +3603,7 @@ class FileCache(): f = self._filename(key) save(key, f+'.key.sobj') - save((key,value), f + '.sobj') + save((key, value), f + '.sobj') if self._cache is not None: self._cache[key] = value diff --git a/src/sage/misc/citation.pyx b/src/sage/misc/citation.pyx index fbe932ba49a..96fe00e98c4 100644 --- a/src/sage/misc/citation.pyx +++ b/src/sage/misc/citation.pyx @@ -97,12 +97,12 @@ def get_systems(cmd): from sage.repl.preparse import preparse cmd = preparse(cmd) - #Run the command and get the stats + # Run the command and get the stats filename = tmp_filename() cProfile.runctx(cmd, globals(), {}, filename) stats = pstats.Stats(filename) - #Strings is a list of method names and modules which get run + # Strings is a list of method names and modules which get run def string_from_stat(a): s = a[0] if SAGE_LOCAL: @@ -114,7 +114,7 @@ def get_systems(cmd): strings = [string_from_stat(a) for a in stats.stats] - #Remove trivial functions + # Remove trivial functions bad_res = [re.compile(r'is_.*Element'), re.compile("is_[a-z_]*_type")] for bad_re in bad_res: i = 0 diff --git a/src/sage/misc/classcall_metaclass.pxd b/src/sage/misc/classcall_metaclass.pxd index 1ae792f074b..24022139808 100644 --- a/src/sage/misc/classcall_metaclass.pxd +++ b/src/sage/misc/classcall_metaclass.pxd @@ -1,10 +1,10 @@ # sage_setup: distribution = sagemath-objects -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.nested_class cimport NestedClassMetaclass diff --git a/src/sage/misc/constant_function.pyx b/src/sage/misc/constant_function.pyx index 2e9c3d9fe44..044b83ad24f 100644 --- a/src/sage/misc/constant_function.pyx +++ b/src/sage/misc/constant_function.pyx @@ -3,15 +3,15 @@ r""" Constant functions """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Nicolas M. Thiery # # 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.richcmp cimport richcmp from sage.structure.sage_object cimport SageObject diff --git a/src/sage/misc/cython.py b/src/sage/misc/cython.py index 95491a5c623..29c013eab19 100644 --- a/src/sage/misc/cython.py +++ b/src/sage/misc/cython.py @@ -24,6 +24,8 @@ import re import sys import shutil +import webbrowser +from pathlib import Path from sage.env import (SAGE_LOCAL, cython_aliases, sage_include_directories) @@ -78,9 +80,16 @@ def _standard_libs_libdirs_incdirs_aliases(): sequence_number = {} +def _webbrowser_open_file(path): + """ + Open a html file in a web browser. + """ + webbrowser.open(Path(path).as_uri()) + + def cython(filename, verbose=0, compile_message=False, - use_cache=False, create_local_c_file=False, annotate=True, sage_namespace=True, - create_local_so_file=False): + use_cache=False, create_local_c_file=False, annotate=True, view_annotate=False, + view_annotate_callback=_webbrowser_open_file, sage_namespace=True, create_local_so_file=False): r""" Compile a Cython file. This converts a Cython file to a C (or C++ file), and then compiles that. The .c file and the .so file are @@ -110,6 +119,14 @@ def cython(filename, verbose=0, compile_message=False, in the temporary directory, but if ``create_local_c_file`` is also True, then save a copy of the .html file in the current directory. + - ``view_annotate`` -- boolean (default: ``False``); if ``True``, open the + annotated html file in a web browser + + - ``view_annotate_callback`` -- function; a function that takes a string + being the path to the html file. This can be overridden to change + what to do with the annotated html file. Have no effect unless + ``view_annotate`` is ``True``. + - ``sage_namespace`` -- boolean (default: ``True``); if ``True``, import ``sage.all`` @@ -226,17 +243,34 @@ def cython(filename, verbose=0, compile_message=False, ....: from sage.misc.cachefunc cimport cache_key ....: ''') - In Cython 0.29.33 using `from PACKAGE cimport MODULE` is broken - when `PACKAGE` is a namespace package, see :issue:`35322`:: + Test ``view_annotate``:: sage: cython(''' - ....: from sage.misc cimport cachefunc - ....: ''') + ....: def f(int n): + ....: return n*n + ....: ''', view_annotate=True) # optional -- webbrowser + + :: + + sage: cython(''' + ....: def f(int n): + ....: return n*n + ....: ''', view_annotate=True, annotate=False) Traceback (most recent call last): ... - RuntimeError: Error compiling Cython file: - ... - ...: 'sage/misc.pxd' not found + ValueError: cannot view annotated file without creating it + + :: + + sage: collected_paths = [] + sage: cython(''' + ....: def f(int n): + ....: return n*n + ....: ''', view_annotate=True, view_annotate_callback=collected_paths.append) + sage: collected_paths + ['...'] + sage: len(collected_paths) + 1 """ if not filename.endswith('pyx'): print("Warning: file (={}) should have extension .pyx".format(filename), file=sys.stderr) @@ -380,7 +414,7 @@ def cython(filename, verbose=0, compile_message=False, cython_messages = re.sub( "^.*The keyword 'nogil' should appear at the end of the function signature line. " "Placing it before 'except' or 'noexcept' will be disallowed in a future version of Cython.\n", - "", cython_messages, 0, re.MULTILINE) + "", cython_messages, flags=re.MULTILINE) sys.stderr.write(cython_messages) sys.stderr.flush() @@ -392,6 +426,11 @@ def cython(filename, verbose=0, compile_message=False, shutil.copy(os.path.join(target_dir, name + ".html"), os.curdir) + if view_annotate: + if not annotate: + raise ValueError("cannot view annotated file without creating it") + view_annotate_callback(os.path.join(target_dir, name + ".html")) + # This emulates running "setup.py build" with the correct options # # setuptools plugins considered harmful: @@ -578,6 +617,9 @@ def cython_import_all(filename, globals, **kwds): - ``filename`` -- string; name of a file that contains Cython code + + See the function :func:`sage.misc.cython.cython` for documentation + for the other inputs. """ m = cython_import(filename, **kwds) for k, x in m.__dict__.items(): @@ -621,6 +663,9 @@ def compile_and_load(code, **kwds): - ``code`` -- string containing code that could be in a .pyx file that is attached or put in a %cython block in the notebook + See the function :func:`sage.misc.cython.cython` for documentation + for the other inputs. + OUTPUT: a module, which results from compiling the given code and importing it diff --git a/src/sage/misc/decorators.py b/src/sage/misc/decorators.py index f93f1227448..004e7b51922 100644 --- a/src/sage/misc/decorators.py +++ b/src/sage/misc/decorators.py @@ -51,6 +51,18 @@ def sage_wraps(wrapped, assigned=WRAPPER_ASSIGNMENTS, updated=WRAPPER_UPDATES): the special attribute ``_sage_argspec_`` of the wrapping function (for an example, see e.g. ``@options`` decorator in this module). + Note that in ``.pyx`` files which is compiled by Cython, because Sage uses + ``binding=False`` compiler directive by default, you need to explicitly + specify ``binding=True`` for all functions decorated with ``sage_wraps``:: + + sage: import cython + sage: def square(f): + ....: @sage_wraps(f) + ....: @cython.binding(True) + ....: def new_f(x): + ....: return f(x)*f(x) + ....: return new_f + EXAMPLES: Demonstrate that documentation string and source are retained from the diff --git a/src/sage/misc/derivative.pyx b/src/sage/misc/derivative.pyx index 24ceb09a1db..24bb401e4be 100644 --- a/src/sage/misc/derivative.pyx +++ b/src/sage/misc/derivative.pyx @@ -1,4 +1,4 @@ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -10,8 +10,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** r""" Utility functions for making derivative() behave uniformly across Sage. diff --git a/src/sage/misc/fast_methods.pyx b/src/sage/misc/fast_methods.pyx index d38c1802c45..7c939a5f810 100644 --- a/src/sage/misc/fast_methods.pyx +++ b/src/sage/misc/fast_methods.pyx @@ -18,15 +18,15 @@ AUTHOR: - Simon King (2013-10): Add :class:`Singleton` """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2013 Simon A. King # # 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.misc.classcall_metaclass import ClasscallMetaclass, typecall from sage.misc.constant_function import ConstantFunction diff --git a/src/sage/misc/function_mangling.pyx b/src/sage/misc/function_mangling.pyx index e410a49a900..6eded73fc63 100644 --- a/src/sage/misc/function_mangling.pyx +++ b/src/sage/misc/function_mangling.pyx @@ -146,7 +146,7 @@ cdef class ArgumentFixer: cdef dict default_map self._defaults = default_map = {} - for k,v in zip(self._arg_names[-self._ndefault:], defaults): + for k, v in zip(self._arg_names[-self._ndefault:], defaults): default_map[k] = v def __repr__(self): @@ -221,10 +221,10 @@ cdef class ArgumentFixer: val = defaults[name] else: val = args[i] - ARGS.append((name,val)) + ARGS.append((name, val)) extra_args = args[self._nargs:] for k in sorted(kwargs_.keys()): - ARGS.append((k,kwargs_[k])) + ARGS.append((k, kwargs_[k])) return tuple(extra_args), tuple(ARGS) def fix_to_pos(self, *args, **kwds): @@ -289,7 +289,7 @@ cdef class ArgumentFixer: if lenargs >= nargs: return args, () # we take the given arguments, plus the default arguments - return args + self._default_tuple[-nargs+lenargs:],() + return args + self._default_tuple[-nargs+lenargs:], () cdef list Largs = list(args) cdef dict kwargs = dict(kwds) cdef Py_ssize_t i diff --git a/src/sage/misc/functional.py b/src/sage/misc/functional.py index 7286501c0f1..4399007c91d 100644 --- a/src/sage/misc/functional.py +++ b/src/sage/misc/functional.py @@ -105,10 +105,7 @@ def basis(x): sage: V = VectorSpace(QQ, 3) # needs sage.modules sage: S = V.subspace([[1,2,0], [2,2,-1]]) # needs sage.modules sage: basis(S) # needs sage.modules - [ - (1, 0, -1), - (0, 1, 1/2) - ] + [(1, 0, -1), (0, 1, 1/2)] """ return x.basis() @@ -220,9 +217,8 @@ def decomposition(x): sage: M = matrix([[2, 3], [3, 4]]) # needs sage.libs.pari sage.modules sage: M.decomposition() # needs sage.libs.pari sage.modules - [ - (Ambient free module of rank 2 over the principal ideal domain Integer Ring, True) - ] + [(Ambient free module of rank 2 over the principal ideal domain Integer Ring, + True)] sage: # needs sage.groups sage: G. = DirichletGroup(20) @@ -910,11 +906,7 @@ def kernel(x): Basis matrix: [] sage: kernel(A.transpose()).basis() - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] """ return x.kernel() @@ -1137,6 +1129,13 @@ def log(*args, **kwds): sage: log(0, 2) -Infinity + + Check if :issue:`37794` is fixed:: + + sage: log(int(0), 2) + -Infinity + sage: log(int(0), 1/2) + +Infinity """ base = kwds.pop('base', None) if base: diff --git a/src/sage/misc/inherit_comparison.pyx b/src/sage/misc/inherit_comparison.pyx index 9758d25574d..5455cfe53a5 100644 --- a/src/sage/misc/inherit_comparison.pyx +++ b/src/sage/misc/inherit_comparison.pyx @@ -26,7 +26,7 @@ AUTHOR: - Jeroen Demeyer (2015-05-22): initial version, see :issue:`18329` """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Jeroen Demeyer # # This program is free software: you can redistribute it and/or modify @@ -34,7 +34,7 @@ AUTHOR: # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from cpython.object cimport PyTypeObject from sage.misc.classcall_metaclass cimport ClasscallMetaclass diff --git a/src/sage/misc/inline_fortran.py b/src/sage/misc/inline_fortran.py index ccd4b1da87c..85f3740d984 100644 --- a/src/sage/misc/inline_fortran.py +++ b/src/sage/misc/inline_fortran.py @@ -12,7 +12,7 @@ def _import_module_from_path(name, path=None): - """ + r""" Import the module named ``name`` by searching the given path entries (or `sys.path` by default). @@ -162,9 +162,7 @@ def eval(self, x, globals=None, locals=None): # What follows are the arguments to f2py itself (appended later # just for logical separation) - cmd += ['-c', '-m', name, fortran_file, '--quiet', - '--f77exec=sage-inline-fortran', - '--f90exec=sage-inline-fortran'] + s_lib_path + s_lib + cmd += ['-c', '-m', name, fortran_file, '--quiet', '--backend', 'meson'] + s_lib_path + s_lib try: out = subprocess.check_output(cmd, stderr=subprocess.STDOUT) diff --git a/src/sage/misc/instancedoc.pyx b/src/sage/misc/instancedoc.pyx index 4641b53b13d..0661ac43dd1 100644 --- a/src/sage/misc/instancedoc.pyx +++ b/src/sage/misc/instancedoc.pyx @@ -108,7 +108,7 @@ Check that inheritance works (after passing the subclass to 'Instance docstring' """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2017 Jeroen Demeyer # # This program is free software: you can redistribute it and/or modify @@ -116,7 +116,7 @@ Check that inheritance works (after passing the subclass to # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from cpython.object cimport PyObject, PyTypeObject diff --git a/src/sage/misc/latex_macros.py b/src/sage/misc/latex_macros.py index fc389b32a72..1cce2fa6f14 100644 --- a/src/sage/misc/latex_macros.py +++ b/src/sage/misc/latex_macros.py @@ -43,6 +43,8 @@ contain '\newcommand' lines for each of the entries in ``macros``. """ +import importlib + def produce_latex_macro(name, *sample_args): r""" @@ -69,7 +71,7 @@ def produce_latex_macro(name, *sample_args): sage: produce_latex_macro('GF', 37) '\\newcommand{\\GF}[1]{\\Bold{F}_{#1}}' - If the Sage object is not in the global name space, describe it + If the Sage object is not in the global namespace, describe it like so:: sage: produce_latex_macro('sage.rings.finite_rings.finite_field_constructor.FiniteField', 3) @@ -84,22 +86,16 @@ def produce_latex_macro(name, *sample_args): else: module, real_name = names_split newcommand = '\\newcommand{\\' + real_name + '}' - count = 0 - args = "(" - for x in sample_args: - count += 1 - args += str(x) + ',' - args += ')' - exec('from ' + module + ' import ' + real_name) - if count: - defn = '[' + str(count) + ']{' - defn += eval('str(LatexCall()(' + real_name + args + '))') + '}' + sage_object = getattr(importlib.import_module(module), real_name) + if sample_args: + defn = '[' + str(len(sample_args)) + ']{' + defn += str(LatexCall()(sage_object(*sample_args))) + '}' else: - defn = '{' + eval('str(LatexCall()(' + real_name + '))') + '}' - count = 0 - for x in sample_args: - count += 1 - defn = defn.replace(str(x), "#" + str(count)) + defn = '{' + str(LatexCall()(sage_object)) + '}' + for i, x in enumerate(sample_args): + s = str(x) + assert s in defn + defn = defn.replace(s, "#" + str(i+1)) return newcommand + defn diff --git a/src/sage/misc/lazy_attribute.pyx b/src/sage/misc/lazy_attribute.pyx index 7514aee1569..7c2eaffa86e 100644 --- a/src/sage/misc/lazy_attribute.pyx +++ b/src/sage/misc/lazy_attribute.pyx @@ -107,7 +107,7 @@ cdef class _lazy_attribute(): """ cdef CM cdef result - if a is None: # when doing cls.x for cls a class and x a lazy attribute + if a is None: # when doing cls.x for cls a class and x a lazy attribute return self try: # _cached_methods is supposed to be a public Cython attribute. @@ -132,7 +132,7 @@ cdef class _lazy_attribute(): for supercls in cls.__mro__: if self.__name__ in supercls.__dict__ and self is supercls.__dict__[self.__name__]: cls = supercls - return getattr(super(cls, a),self.__name__) + return getattr(super(cls, a), self.__name__) try: setattr(a, self.__name__, result) except AttributeError: @@ -497,11 +497,11 @@ class lazy_attribute(_lazy_attribute): self.f = f if hasattr(f, "__doc__"): self.__doc__ = f.__doc__ - elif hasattr(f, "__doc__"): # Needed to handle Cython methods + elif hasattr(f, "__doc__"): # Needed to handle Cython methods self.__doc__ = f.__doc__ if hasattr(f, "__name__"): self.__name__ = f.__name__ - elif hasattr(f, "__name__"): # Needed to handle Cython methods + elif hasattr(f, "__name__"): # Needed to handle Cython methods self.__name__ = f.__name__ if hasattr(f, "__module__"): self.__module__ = f.__module__ diff --git a/src/sage/misc/lazy_import.pyx b/src/sage/misc/lazy_import.pyx index cde9be93d7e..f309429537b 100644 --- a/src/sage/misc/lazy_import.pyx +++ b/src/sage/misc/lazy_import.pyx @@ -990,7 +990,8 @@ cdef class LazyImport(): def lazy_import(module, names, as_=None, *, - at_startup=False, namespace=None, deprecation=None, feature=None): + at_startup=False, namespace=None, + deprecation=None, feature=None): """ Create a lazy import object and inject it into the caller's global namespace. For the purposes of introspection and calling, this is diff --git a/src/sage/misc/lazy_list.pyx b/src/sage/misc/lazy_list.pyx index 65d397996fc..3f48dce9831 100644 --- a/src/sage/misc/lazy_list.pyx +++ b/src/sage/misc/lazy_list.pyx @@ -117,7 +117,7 @@ empty_lazy_list.cache = [] def lazy_list(data=None, initial_values=None, start=None, stop=None, step=None, - update_function=None): + update_function=None): r""" Return a lazy list. @@ -224,7 +224,7 @@ def lazy_list(data=None, initial_values=None, start=None, stop=None, step=None, assert callable(update_function) return lazy_list_from_update_function(update_function, cache) - if isinstance(data, (tuple,list)): + if isinstance(data, (tuple, list)): data = cache + list(data) l = lazy_list_generic(data, start=0, stop=len(data), step=1) elif isinstance(data, lazy_list_generic): @@ -1137,7 +1137,7 @@ cdef class lazy_list_from_update_function(lazy_list_generic): stop 2147483647 # 32-bit step 1 """ - cdef Py_ssize_t l,ll + cdef Py_ssize_t l, ll l = len(self.cache) while l <= i: self.update_function(self.cache) diff --git a/src/sage/misc/lazy_string.pyx b/src/sage/misc/lazy_string.pyx index 48a26c9b609..553664d639f 100644 --- a/src/sage/misc/lazy_string.pyx +++ b/src/sage/misc/lazy_string.pyx @@ -25,13 +25,13 @@ Note that the function is recomputed each time:: l'2' """ -#Copyright (c) 2009 by Armin Ronacher. +# Copyright (c) 2009 by Armin Ronacher. # -#Some rights reserved. +# Some rights reserved. # -#Redistribution and use in source and binary forms, with or without -#modification, are permitted provided that the following conditions are -#met: +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. @@ -45,17 +45,17 @@ Note that the function is recomputed each time:: # promote products derived from this software without specific # prior written permission. # -#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -#A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -#OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -#SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -#LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -#DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -#THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -#OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. from cpython.object cimport PyObject_Call, PyObject_RichCompare diff --git a/src/sage/misc/meson.build b/src/sage/misc/meson.build index f4ba17ef30a..97d4bf9e6a1 100644 --- a/src/sage/misc/meson.build +++ b/src/sage/misc/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'abstract_method.py', 'all.py', 'all__sagemath_environment.py', diff --git a/src/sage/misc/nested_class.pyx b/src/sage/misc/nested_class.pyx index e42569abe3e..1f661b8240a 100644 --- a/src/sage/misc/nested_class.pyx +++ b/src/sage/misc/nested_class.pyx @@ -91,7 +91,7 @@ cdef dict sys_modules = sys.modules __all__ = ['modify_for_nested_pickle', 'nested_pickle', 'NestedClassMetaclass', 'MainClass' # Comment out to silence Sphinx warning about nested classes. - #, 'SubClass', 'CopiedClass', 'A1' + # , 'SubClass', 'CopiedClass', 'A1' ] cpdef modify_for_nested_pickle(cls, str name_prefix, module, first_run=True): @@ -325,7 +325,7 @@ class MainClass(object, metaclass=NestedClassMetaclass): sage: MainClass.NestedClass.NestedSubClass.__name__ 'MainClass.NestedClass.NestedSubClass' """ - def dummy(self, x, *args, r=(1,2,3.4), **kwds): + def dummy(self, x, *args, r=(1, 2, 3.4), **kwds): """ A dummy method to demonstrate the embedding of method signature for nested classes. diff --git a/src/sage/misc/package_dir.py b/src/sage/misc/package_dir.py index b15374e3bbc..3ef3adf73be 100644 --- a/src/sage/misc/package_dir.py +++ b/src/sage/misc/package_dir.py @@ -603,7 +603,7 @@ def handle_file(root, file): else: handle_file(*os.path.split(path)) - print(f"sage --fixdistributions: checking consistency") + print("sage --fixdistributions: checking consistency") for package in ordinary_packages: if len(package_distributions_per_directives[package]) > 1: diff --git a/src/sage/misc/persist.pyx b/src/sage/misc/persist.pyx index 7429388112e..f7f83a696b8 100644 --- a/src/sage/misc/persist.pyx +++ b/src/sage/misc/persist.pyx @@ -57,7 +57,7 @@ from sage.misc.sage_unittest import TestSuite # Apart from this, you are free to use these variables as you like. # # However, the standard utilisation is the following. -# The pickling method (namely `__reduce__`) checks if the id of the +# The pickling method (namely ``__reduce__``) checks if the id of the # current element appears in the dictionary `already_pickled`. If it # does not, the methods records that this element is about to be # pickled by adding the entry { id: True } to `already_pickled`. @@ -72,8 +72,8 @@ from sage.misc.sage_unittest import TestSuite # `already_unpickled` and finally returns the element. # # For a working example, see sage.rings.padics.lazy_template.LazyElement_unknown -already_pickled = { } -already_unpickled = { } +already_pickled = {} +already_unpickled = {} cdef _normalize_filename(s): @@ -92,7 +92,7 @@ def load(*filename, compress=True, verbose=True, **kwargs): an ``.sobj`` extension added if it doesn't have one. Or, if the input is a filename ending in ``.py``, ``.pyx``, ``.sage``, ``.spyx``, ``.f``, ``.f90`` or ``.m``, load that file into the current running - session. + session using :func:`sage.repl.load.load`. Loaded files are not loaded into their own namespace, i.e., this is much more like Python's ``execfile`` than Python's ``import``. @@ -176,7 +176,7 @@ def load(*filename, compress=True, verbose=True, **kwargs): sage.repl.load.load(filename, globals()) return - ## Check if filename starts with "http://" or "https://" + # Check if filename starts with "http://" or "https://" lower = filename.lower() if lower.startswith("http://") or lower.startswith("https://"): from sage.misc.remote_file import get_remote_file @@ -186,7 +186,7 @@ def load(*filename, compress=True, verbose=True, **kwargs): tmpfile_flag = False filename = _normalize_filename(filename) - ## Load file by absolute filename + # Load file by absolute filename with open(filename, 'rb') as fobj: X = loads(fobj.read(), compress=compress, **kwargs) try: @@ -194,7 +194,7 @@ def load(*filename, compress=True, verbose=True, **kwargs): except AttributeError: pass - ## Delete the tempfile, if it exists + # Delete the tempfile, if it exists if tmpfile_flag: os.unlink(filename) @@ -303,7 +303,7 @@ def _base_dumps(obj, compress=True): global already_pickled gherkin = SagePickler.dumps(obj) - already_pickled = { } + already_pickled = {} if compress: return comp.compress(gherkin) @@ -334,7 +334,7 @@ def dumps(obj, compress=True): ans = obj.dumps(compress) except (AttributeError, RuntimeError, TypeError): ans = _base_dumps(obj, compress=compress) - already_pickled = { } + already_pickled = {} return ans @@ -588,8 +588,7 @@ def unpickle_global(module, name): def error(): raise ImportError("cannot import {1} from {0}, call " - "register_unpickle_override({0!r}, {1!r}, ...) to fix this".format( - module, name)) + "register_unpickle_override({0!r}, {1!r}, ...) to fix this".format(module, name)) mod = sys.modules.get(module) if mod is not None: @@ -624,9 +623,9 @@ class _BasePickler(pickle.Pickler): """ def __init__(self, file_obj, protocol=None, persistent_id=None, *, - fix_imports=True): + fix_imports=True): super(_BasePickler, self).__init__(file_obj, protocol, - fix_imports=fix_imports) + fix_imports=fix_imports) self._persistent_id = persistent_id def persistent_id(self, obj): @@ -825,7 +824,7 @@ class SagePickler(_BasePickler): buf = io.BytesIO() pickler = cls(buf, **kwargs) pickler.dump(obj) - already_pickled = { } + already_pickled = {} return buf.getvalue() @@ -988,7 +987,7 @@ def loads(s, compress=True, **kwargs): unpickler = SageUnpickler(io.BytesIO(s), **kwargs) global already_unpickled ans = unpickler.load() - already_unpickled = { } + already_unpickled = {} return ans @@ -1060,7 +1059,7 @@ def picklejar(obj, dir=None): global already_pickled s = comp.compress(SagePickler.dumps(obj)) - already_pickled = { } + already_pickled = {} typ = str(type(obj)) name = ''.join([x if (x.isalnum() or x == '_') else '_' for x in typ]) diff --git a/src/sage/misc/randstate.pyx b/src/sage/misc/randstate.pyx index 79435da9ce7..fe3351d126b 100644 --- a/src/sage/misc/randstate.pyx +++ b/src/sage/misc/randstate.pyx @@ -529,11 +529,11 @@ cdef class randstate: if seed is None: if use_urandom: - seed = long(binascii.hexlify(os.urandom(16)), 16) + seed = int(binascii.hexlify(os.urandom(16)), 16) else: - seed = long(time.time() * 256) + seed = int(time.time() * 256) else: - seed = long(seed) + seed = int(seed) # If seed==0, leave it at the default seed used by # gmp_randinit_default() @@ -605,9 +605,9 @@ cdef class randstate: from sage.rings.integer_ring import ZZ rand = cls() if seed is None: - rand.seed(long(ZZ.random_element(long(1)<<128))) + rand.seed(int(ZZ.random_element(1<<128))) else: - rand.seed(long(seed)) + rand.seed(int(seed)) self._python_random = rand return rand @@ -624,7 +624,7 @@ cdef class randstate: 48314508034782595865062786044921182484 """ from sage.rings.integer_ring import ZZ - return ZZ.random_element(long(1)<<128) + return ZZ.random_element(1<<128) cpdef long_seed(self): r""" @@ -638,7 +638,7 @@ cdef class randstate: 256056279774514099508607350947089272595 """ from sage.rings.integer_ring import ZZ - return long(ZZ.random_element(long(1)<<128)) + return int(ZZ.random_element(1<<128)) cpdef set_seed_libc(self, bint force): r""" @@ -688,7 +688,7 @@ cdef class randstate: if force or _ntl_seed_randstate is not self: import sage.libs.ntl.ntl_ZZ as ntl_ZZ from sage.rings.integer_ring import ZZ - ntl_ZZ.ntl_setSeed(ZZ.random_element(long(1)<<128)) + ntl_ZZ.ntl_setSeed(ZZ.random_element(1<<128)) _ntl_seed_randstate = self def set_seed_gap(self): @@ -715,7 +715,7 @@ cdef class randstate: mersenne_seed, classic_seed = self._gap_saved_seed else: from sage.rings.integer_ring import ZZ - seed = ZZ.random_element(long(1)<<128) + seed = ZZ.random_element(1<<128) classic_seed = seed mersenne_seed = seed @@ -838,8 +838,8 @@ cdef class randstate: sage: current_randstate().c_rand_double() 0.22437207488974298 """ - cdef double a = gmp_urandomb_ui(self.gmp_state, 25) * (1.0 / 33554432.0) # divide by 2^25 - cdef double b = gmp_urandomb_ui(self.gmp_state, 28) * (1.0 / 9007199254740992.0) # divide by 2^53 + cdef double a = gmp_urandomb_ui(self.gmp_state, 25) * (1.0 / 33554432.0) # divide by 2^25 + cdef double b = gmp_urandomb_ui(self.gmp_state, 28) * (1.0 / 9007199254740992.0) # divide by 2^53 return a+b def __dealloc__(self): @@ -1004,9 +1004,7 @@ def benchmark_libc(): sage: timeit('benchmark_mt()') # random 125 loops, best of 3: 2.12 ms per loop """ - cdef int i - cdef randstate rstate = _current_randstate - for i from 0 <= i < 100000: + for _ in range(100000): c_libc_random() diff --git a/src/sage/misc/replace_dot_all.py b/src/sage/misc/replace_dot_all.py index ea51a9b3159..a43d6c0a929 100644 --- a/src/sage/misc/replace_dot_all.py +++ b/src/sage/misc/replace_dot_all.py @@ -194,14 +194,15 @@ def find_replacements(location, package_regex=None, verbose=False): to_exec = to_exec.replace("'", '').replace('"', '') if (to_exec[-1] == ','): to_exec = to_exec[:-1] - exec(to_exec) + glob = dict() + exec(to_exec, glob) except ModuleNotFoundError as err: print(f'ModuleNotFoundError: {err} found when trying to execute {to_exec}') except ImportError as err: print(f'ImportError: {err} found when trying to execute {to_exec}') try: # try to evaluate the list of module names to get a list of the modules themselves which we can call import_statements on - modules = eval(to_eval) + modules = eval(to_eval, glob) except NameError as err: print(f'NameError: {err} found when trying to evaluate {to_eval} at {location}:{row_index + 1}') except SyntaxError as err: diff --git a/src/sage/misc/sagedoc.py b/src/sage/misc/sagedoc.py index 0505f6039a9..6147ec4983b 100644 --- a/src/sage/misc/sagedoc.py +++ b/src/sage/misc/sagedoc.py @@ -694,7 +694,7 @@ def format(s, embedded=False): We check that the todo Sphinx extension is correctly activated:: sage: sage.misc.sagedoc.format(sage.combinat.ranker.on_fly.__doc__) # needs sphinx - " Return ... Todo: add tests as in combinat::rankers\n" + "...Return ...Todo: add tests as in combinat::rankers\n" In the following use case, the ``nodetex`` directive would have been ignored prior to :issue:`11815`:: @@ -1135,10 +1135,11 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', The following produces an error because the string 'fetch(' is a malformed regular expression:: - sage: print(search_src(" fetch(", "def", interact=False)) - Traceback (most recent call last): - ... - error: missing ), unterminated subpattern at position 6 + sage: try: + ....: print(search_src(" fetch(", "def", interact=False)) + ....: except Exception as e: + ....: print(e) + missing ), unterminated subpattern at position 6 To fix this, *escape* the parenthesis with a backslash:: @@ -1186,7 +1187,6 @@ def search_src(string, extra1='', extra2='', extra3='', extra4='', misc/sagedoc.py:... len(search_src("matrix", interact=False).splitlines())... misc/sagedoc.py:... len(search_src("matrix", module="sage.calculus", interact=False).splitlines())... misc/sagedoc.py:... len(search_src("matrix", path_re="calc"... - misc/sagedoc.py:... print(search_src(" fetch(", "def", interact=False))... misc/sagedoc.py:... print(search_src(r" fetch\(", "def", interact=False))... misc/sagedoc.py:... print(search_src(r" fetch\(", "def", "pyx", interact=False))... misc/sagedoc.py:... s = search_src('Matrix', path_re='matrix', interact=False); s.find('x') > 0... @@ -1456,7 +1456,7 @@ class _sage_doc: sage: browse_sage_doc._open("reference", testing=True)[0] # needs sagemath_doc_html 'http://localhost:8000/doc/live/reference/index.html' sage: browse_sage_doc(identity_matrix, 'rst')[-107:-47] # needs sage.modules - 'Full MatrixSpace of 3 by 3 sparse matrices over Integer Ring' + '...Full MatrixSpace of 3 by 3 sparse matrices...' """ def __init__(self): """ diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 585112b5061..12f319fc8e3 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -1986,7 +1986,7 @@ def sage_getdoc(obj, obj_name='', embedded=False): sage: from sage.misc.sageinspect import sage_getdoc sage: sage_getdoc(identity_matrix)[87:124] # needs sage.modules - 'Return the n x n identity matrix over' + '...the n x n identity matrix...' sage: def f(a, b, c, d=1): return a+b+c+d ... sage: import functools diff --git a/src/sage/misc/search.pxd b/src/sage/misc/search.pxd index 8cc43ba1b0f..f73e9061b8d 100644 --- a/src/sage/misc/search.pxd +++ b/src/sage/misc/search.pxd @@ -1 +1 @@ -cpdef search(object v, object x) \ No newline at end of file +cpdef search(object v, object x) diff --git a/src/sage/misc/stopgap.pyx b/src/sage/misc/stopgap.pyx index e6f626ae9b4..ccf18faf22b 100644 --- a/src/sage/misc/stopgap.pyx +++ b/src/sage/misc/stopgap.pyx @@ -2,7 +2,7 @@ Stopgaps """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 William Stein # # This program is free software: you can redistribute it and/or modify @@ -10,7 +10,7 @@ Stopgaps # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** import warnings diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index 6aaa8e6fb6f..fcc63bb1013 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -105,7 +105,7 @@ def deprecation_cython(issue_number, message, stacklevel=3): TESTS: - We check that `deprecation_cython` in a cython function generates a warning + We check that ``deprecation_cython`` in a cython function generates a warning with the same callsite reference as `deprecation` in a python function, whereas `deprecation` in a cython function does not:: diff --git a/src/sage/misc/table.py b/src/sage/misc/table.py index 086e8fd49ed..61ead0537b1 100644 --- a/src/sage/misc/table.py +++ b/src/sage/misc/table.py @@ -69,11 +69,11 @@ class table(SageObject): \end{tabular} sage: table(rows=rows, frame=True) ┌─────┬───┬────┐ - │ a | b | c | + │ a │ b │ c │ ├─────┼───┼────┤ - │ 100 | 2 | 3 | + │ 100 │ 2 │ 3 │ ├─────┼───┼────┤ - │ 4 | 5 | 60 | + │ 4 │ 5 │ 60 │ └─────┴───┴────┘ sage: latex(table(rows=rows, frame=True)) \begin{tabular}{|l|l|l|} \hline @@ -83,11 +83,11 @@ class table(SageObject): \end{tabular} sage: table(rows, header_column=True, frame=True) ┌─────╥───┬────┐ - │ a ║ b | c | + │ a ║ b │ c │ ├─────╫───┼────┤ - │ 100 ║ 2 | 3 | + │ 100 ║ 2 │ 3 │ ├─────╫───┼────┤ - │ 4 ║ 5 | 60 | + │ 4 ║ 5 │ 60 │ └─────╨───┴────┘ sage: latex(table(rows, header_row=True, frame=True)) \begin{tabular}{|l|l|l|} \hline @@ -109,15 +109,15 @@ class table(SageObject): sage: table([(x,n(sin(x), digits=2)) for x in [0..3]], # needs sage.symbolic ....: header_row=["$x$", r"$\sin(x)$"], frame=True) ┌─────┬───────────┐ - │ $x$ | $\sin(x)$ | + │ $x$ │ $\sin(x)$ │ ╞═════╪═══════════╡ - │ 0 | 0.00 | + │ 0 │ 0.00 │ ├─────┼───────────┤ - │ 1 | 0.84 | + │ 1 │ 0.84 │ ├─────┼───────────┤ - │ 2 | 0.91 | + │ 2 │ 0.91 │ ├─────┼───────────┤ - │ 3 | 0.14 | + │ 3 │ 0.14 │ └─────┴───────────┘ You can create the transpose of this table in several ways, for @@ -127,9 +127,9 @@ class table(SageObject): ....: [n(sin(x), digits=2) for x in [0..3]]], ....: header_column=['$x$', r'$\sin(x)$'], frame=True) ┌───────────╥──────┬──────┬──────┬──────┐ - │ $x$ ║ 0 | 1 | 2 | 3 | + │ $x$ ║ 0 │ 1 │ 2 │ 3 │ ├───────────╫──────┼──────┼──────┼──────┤ - │ $\sin(x)$ ║ 0.00 | 0.84 | 0.91 | 0.14 | + │ $\sin(x)$ ║ 0.00 │ 0.84 │ 0.91 │ 0.14 │ └───────────╨──────┴──────┴──────┴──────┘ or by passing the original data as the ``columns`` of the table @@ -138,9 +138,9 @@ class table(SageObject): sage: table(columns=[(x, n(sin(x), digits=2)) for x in [0..3]], # needs sage.symbolic ....: header_column=['$x$', r'$\sin(x)$'], frame=True) ┌───────────╥──────┬──────┬──────┬──────┐ - │ $x$ ║ 0 | 1 | 2 | 3 | + │ $x$ ║ 0 │ 1 │ 2 │ 3 │ ├───────────╫──────┼──────┼──────┼──────┤ - │ $\sin(x)$ ║ 0.00 | 0.84 | 0.91 | 0.14 | + │ $\sin(x)$ ║ 0.00 │ 0.84 │ 0.91 │ 0.14 │ └───────────╨──────┴──────┴──────┴──────┘ or by taking the :meth:`transpose` of the original table:: @@ -148,9 +148,9 @@ class table(SageObject): sage: table(rows=[(x, n(sin(x), digits=2)) for x in [0..3]], # needs sage.symbolic ....: header_row=['$x$', r'$\sin(x)$'], frame=True).transpose() ┌───────────╥──────┬──────┬──────┬──────┐ - │ $x$ ║ 0 | 1 | 2 | 3 | + │ $x$ ║ 0 │ 1 │ 2 │ 3 │ ├───────────╫──────┼──────┼──────┼──────┤ - │ $\sin(x)$ ║ 0.00 | 0.84 | 0.91 | 0.14 | + │ $\sin(x)$ ║ 0.00 │ 0.84 │ 0.91 │ 0.14 │ └───────────╨──────┴──────┴──────┴──────┘ In either plain text or LaTeX, entries in tables can be aligned to the @@ -166,11 +166,11 @@ class table(SageObject): 4 5 60 sage: table(rows, align='right', frame=True) ┌─────┬───┬────┐ - │ a | b | c | + │ a │ b │ c │ ├─────┼───┼────┤ - │ 100 | 2 | 3 | + │ 100 │ 2 │ 3 │ ├─────┼───┼────┤ - │ 4 | 5 | 60 | + │ 4 │ 5 │ 60 │ └─────┴───┴────┘ To generate HTML you should use ``html(table(...))``:: @@ -253,7 +253,7 @@ def __init__(self, rows=None, columns=None, header_row=False, sage: table([1,2,3], frame=True) ┌───┬───┬───┐ - │ 1 | 2 | 3 | + │ 1 │ 2 │ 3 │ └───┴───┴───┘ """ # If both rows and columns are set, raise an error. @@ -342,20 +342,20 @@ def options(self, **kwds): sage: T = table([[1,2,3], [4,5,6]], header_row=['a', 'b', 'c'], frame=True) sage: T ┌───┬───┬───┐ - │ a | b | c | + │ a │ b │ c │ ╞═══╪═══╪═══╡ - │ 1 | 2 | 3 | + │ 1 │ 2 │ 3 │ ├───┼───┼───┤ - │ 4 | 5 | 6 | + │ 4 │ 5 │ 6 │ └───┴───┴───┘ sage: T.options(header_row=False) sage: T ┌───┬───┬───┐ - │ a | b | c | + │ a │ b │ c │ ├───┼───┼───┤ - │ 1 | 2 | 3 | + │ 1 │ 2 │ 3 │ ├───┼───┼───┤ - │ 4 | 5 | 6 | + │ 4 │ 5 │ 6 │ └───┴───┴───┘ If you do specify a list for ``header_row``, an error is raised:: @@ -398,11 +398,11 @@ def transpose(self): sage: T = table([[1,2,3], [4,5,6]], header_row=['x', 'y', 'z'], frame=True) sage: T.transpose() ┌───╥───┬───┐ - │ x ║ 1 | 4 | + │ x ║ 1 │ 4 │ ├───╫───┼───┤ - │ y ║ 2 | 5 | + │ y ║ 2 │ 5 │ ├───╫───┼───┤ - │ z ║ 3 | 6 | + │ z ║ 3 │ 6 │ └───╨───┴───┘ """ return table(list(zip(*self._rows)), @@ -508,7 +508,7 @@ def _str_table_row(self, row, header_row=False, last_row=False): ' 1 │ 2 3\n├────┼─────┼───────┤\n' sage: T.options(frame=True) sage: T._str_table_row([1,2,3], False) - '│ 1 ║ 2 | 3 |\n├────╫─────┼───────┤\n' + '│ 1 ║ 2 │ 3 │\n├────╫─────┼───────┤\n' Check that :issue:`14601` has been fixed:: @@ -552,7 +552,7 @@ def _str_table_row(self, row, header_row=False, last_row=False): for entry, width in zip(row, widths): s += ("{!s:" + align_char + str(width) + "}").format(entry) if frame: - s += " | " + s += " │ " else: s += " " s = s.rstrip(' ') @@ -696,15 +696,15 @@ def _html_(self): ....: header_row=True, frame=True) sage: T # needs sage.symbolic ┌─────┬───────────┐ - │ $x$ | $\sin(x)$ | + │ $x$ │ $\sin(x)$ │ ╞═════╪═══════════╡ - │ 0 | 0.00 | + │ 0 │ 0.00 │ ├─────┼───────────┤ - │ 1 | 0.84 | + │ 1 │ 0.84 │ ├─────┼───────────┤ - │ 2 | 0.91 | + │ 2 │ 0.91 │ ├─────┼───────────┤ - │ 3 | 0.14 | + │ 3 │ 0.14 │ └─────┴───────────┘ sage: print(html(T)) # needs sage.symbolic
diff --git a/src/sage/misc/temporary_file.py b/src/sage/misc/temporary_file.py index 998260be8eb..4e9ece019d2 100644 --- a/src/sage/misc/temporary_file.py +++ b/src/sage/misc/temporary_file.py @@ -32,7 +32,9 @@ # as the parent for all temporary files & directories created by them. # This lets us clean up after those two functions when sage exits normally # using an atexit hook -TMP_DIR_FILENAME_BASE = tempfile.TemporaryDirectory() +# Note that `TemporaryDirectory()` will cleanup on program exit; +# we keep the atexit hook to be redundant, in case that fails. +TMP_DIR_FILENAME_BASE = tempfile.TemporaryDirectory(prefix='sage_') atexit.register(lambda: TMP_DIR_FILENAME_BASE.cleanup()) @@ -533,14 +535,17 @@ def spyx_tmp() -> str: We cache the result of this function "by hand" so that the same temporary directory will always be returned. A function is used to delay creating a directory until (if) it is needed. The temporary - directory is removed when sage terminates by way of an atexit - hook. + directory is automatically removed when sage terminates. """ global _spyx_tmp if _spyx_tmp: return _spyx_tmp - d = tempfile.TemporaryDirectory() - _spyx_tmp = os.path.join(d.name, 'spyx') - atexit.register(lambda: d.cleanup()) + # We don't use `tempfile.TemporaryDirectory()` here because it + # is not clear when it will or will not be cleaned. Sometimes it + # might not be cleaned up at all, and starting in python 3.13 it + # might be cleaned up on child exit, breaking parallel testing. + # For some reason this doesn't affect the `TemporaryDirectory` + # stored in the global `TMP_DIR_FILENAME_BASE`. + _spyx_tmp = tmp_dir(name='spyx_') return _spyx_tmp diff --git a/src/sage/misc/weak_dict.pyx b/src/sage/misc/weak_dict.pyx index ce69b6a840a..c288d312bd9 100644 --- a/src/sage/misc/weak_dict.pyx +++ b/src/sage/misc/weak_dict.pyx @@ -404,7 +404,7 @@ cdef class WeakValueDictionary(dict): True """ out = WeakValueDictionary() - for k,v in self.items(): + for k, v in self.items(): out[deepcopy(k, memo)] = v return out @@ -624,7 +624,7 @@ cdef class WeakValueDictionary(dict): ... KeyError: 'popitem(): weak value dictionary is empty' """ - for k,v in self.items(): + for k, v in self.items(): del self[k] return k, v raise KeyError('popitem(): weak value dictionary is empty') diff --git a/src/sage/modular/abvar/abvar.py b/src/sage/modular/abvar/abvar.py index 92b1e9f9abe..2030bfb09bb 100644 --- a/src/sage/modular/abvar/abvar.py +++ b/src/sage/modular/abvar/abvar.py @@ -10,11 +10,9 @@ sage: A = J0(33) sage: D = A.decomposition(); D - [ - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), - Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), + Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33)] sage: loads(dumps(D)) == D True sage: loads(dumps(A)) == A @@ -513,9 +511,7 @@ def label(self) -> str: sage: B = phi.image(); B Abelian subvariety of dimension 1 of J0(33) sage: B.decomposition() - [ - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33)] sage: C = J.degeneracy_map(33,3).image(); C Abelian subvariety of dimension 1 of J0(33) sage: C == B @@ -937,11 +933,9 @@ def intersection(self, other): intersection:: sage: J = J0(67); D = J.decomposition(); D - [ - Simple abelian subvariety 67a(1,67) of dimension 1 of J0(67), - Simple abelian subvariety 67b(1,67) of dimension 2 of J0(67), - Simple abelian subvariety 67c(1,67) of dimension 2 of J0(67) - ] + [Simple abelian subvariety 67a(1,67) of dimension 1 of J0(67), + Simple abelian subvariety 67b(1,67) of dimension 2 of J0(67), + Simple abelian subvariety 67c(1,67) of dimension 2 of J0(67)] sage: (D[0] + D[1]).intersection(D[1] + D[2]) (Finite subgroup with invariants [5, 10] over QQbar of Abelian subvariety of dimension 3 of J0(67), Abelian subvariety of dimension 2 of J0(67)) @@ -1777,14 +1771,12 @@ def conductor(self): 5^24 sage: A = J0(11^2); A.decomposition() - [ - Simple abelian subvariety 11a(1,121) of dimension 1 of J0(121), - Simple abelian subvariety 11a(11,121) of dimension 1 of J0(121), - Simple abelian subvariety 121a(1,121) of dimension 1 of J0(121), - Simple abelian subvariety 121b(1,121) of dimension 1 of J0(121), - Simple abelian subvariety 121c(1,121) of dimension 1 of J0(121), - Simple abelian subvariety 121d(1,121) of dimension 1 of J0(121) - ] + [Simple abelian subvariety 11a(1,121) of dimension 1 of J0(121), + Simple abelian subvariety 11a(11,121) of dimension 1 of J0(121), + Simple abelian subvariety 121a(1,121) of dimension 1 of J0(121), + Simple abelian subvariety 121b(1,121) of dimension 1 of J0(121), + Simple abelian subvariety 121c(1,121) of dimension 1 of J0(121), + Simple abelian subvariety 121d(1,121) of dimension 1 of J0(121)] sage: A.conductor().factor() 11^10 @@ -3160,11 +3152,9 @@ def degen_t(self, none_if_not_known=False): EXAMPLES:: sage: D = J0(33).decomposition(); D - [ - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), - Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), + Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33)] sage: D[0].degen_t() (1, 33) sage: D[1].degen_t() @@ -3296,36 +3286,28 @@ def decomposition(self, simple=True, bound=None): sage: A = w.abelian_variety(); A Abelian subvariety of dimension 1 of J0(33) sage: D = A.decomposition(); D - [ - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33)] sage: D[0] == A True sage: B = A + J0(33)[0]; B Abelian subvariety of dimension 2 of J0(33) sage: dd = B.decomposition(simple=False); dd - [ - Abelian subvariety of dimension 2 of J0(33) - ] + [Abelian subvariety of dimension 2 of J0(33)] sage: dd[0] == B True sage: dd = B.decomposition(); dd - [ - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33)] sage: sum(dd) == B True We decompose a product of two Jacobians:: sage: (J0(33) * J0(11)).decomposition() - [ - Simple abelian subvariety 11a(1,11) of dimension 1 of J0(33) x J0(11), - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) x J0(11), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33) x J0(11), - Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33) x J0(11) - ] + [Simple abelian subvariety 11a(1,11) of dimension 1 of J0(33) x J0(11), + Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) x J0(11), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33) x J0(11), + Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33) x J0(11)] """ try: return self.__decomposition[(simple, bound)] @@ -3504,11 +3486,11 @@ def _classify_ambient_factors(self, simple=True, bound=None): sage: A = (d1 + d2).image(); A Abelian subvariety of dimension 1 of J0(33) sage: A._classify_ambient_factors() - ([1], [0, 2], [ - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), - Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33) - ]) + ([1], + [0, 2], + [Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), + Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33)]) """ # Decompose an arbitrary abelian variety amb = self.ambient_variety() @@ -3538,10 +3520,8 @@ def _isogeny_to_product_of_simples(self): EXAMPLES:: sage: J = J0(37) ; J.decomposition() - [ - Simple abelian subvariety 37a(1,37) of dimension 1 of J0(37), - Simple abelian subvariety 37b(1,37) of dimension 1 of J0(37) - ] + [Simple abelian subvariety 37a(1,37) of dimension 1 of J0(37), + Simple abelian subvariety 37b(1,37) of dimension 1 of J0(37)] sage: phi = J._isogeny_to_product_of_simples() ; phi Abelian variety morphism: From: Abelian variety J0(37) of dimension 2 @@ -3774,11 +3754,9 @@ def _factors_with_same_label(self, other): EXAMPLES:: sage: D = J0(33).decomposition(); D - [ - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), - Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), + Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33)] sage: D[0]._factors_with_same_label(D[1]) [Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33)] sage: D[0]._factors_with_same_label(D[2]) @@ -3837,11 +3815,9 @@ def _complement_shares_no_factors_with_same_label(self): elliptic curves with a third nonisogenous curve:: sage: D = J0(33).decomposition(); D - [ - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), - Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), + Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33)] sage: D[0]._complement_shares_no_factors_with_same_label() False sage: (D[0]+D[1])._complement_shares_no_factors_with_same_label() @@ -3855,10 +3831,8 @@ def _complement_shares_no_factors_with_same_label(self): :: sage: D = (J0(11) * J0(11)).decomposition(); D - [ - Simple abelian subvariety 11a(1,11) of dimension 1 of J0(11) x J0(11), - Simple abelian subvariety 11a(1,11) of dimension 1 of J0(11) x J0(11) - ] + [Simple abelian subvariety 11a(1,11) of dimension 1 of J0(11) x J0(11), + Simple abelian subvariety 11a(1,11) of dimension 1 of J0(11) x J0(11)] sage: D[0]._complement_shares_no_factors_with_same_label() False @@ -3866,10 +3840,8 @@ def _complement_shares_no_factors_with_same_label(self): isogeny, class that matters:: sage: D = (J0(11)*J1(11)).decomposition(); D - [ - Simple abelian subvariety 11aG1(1,11) of dimension 1 of J0(11) x J1(11), - Simple abelian subvariety 11a(1,11) of dimension 1 of J0(11) x J1(11) - ] + [Simple abelian subvariety 11aG1(1,11) of dimension 1 of J0(11) x J1(11), + Simple abelian subvariety 11a(1,11) of dimension 1 of J0(11) x J1(11)] sage: D[0]._complement_shares_no_factors_with_same_label() True sage: D[0].newform_label() @@ -3893,28 +3865,22 @@ def __getitem__(self, i): sage: J = J0(389) sage: J.decomposition() - [ - Simple abelian subvariety 389a(1,389) of dimension 1 of J0(389), - Simple abelian subvariety 389b(1,389) of dimension 2 of J0(389), - Simple abelian subvariety 389c(1,389) of dimension 3 of J0(389), - Simple abelian subvariety 389d(1,389) of dimension 6 of J0(389), - Simple abelian subvariety 389e(1,389) of dimension 20 of J0(389) - ] + [Simple abelian subvariety 389a(1,389) of dimension 1 of J0(389), + Simple abelian subvariety 389b(1,389) of dimension 2 of J0(389), + Simple abelian subvariety 389c(1,389) of dimension 3 of J0(389), + Simple abelian subvariety 389d(1,389) of dimension 6 of J0(389), + Simple abelian subvariety 389e(1,389) of dimension 20 of J0(389)] sage: J[2] Simple abelian subvariety 389c(1,389) of dimension 3 of J0(389) sage: J[-1] Simple abelian subvariety 389e(1,389) of dimension 20 of J0(389) sage: J = J0(125); J.decomposition() - [ - Simple abelian subvariety 125a(1,125) of dimension 2 of J0(125), - Simple abelian subvariety 125b(1,125) of dimension 2 of J0(125), - Simple abelian subvariety 125c(1,125) of dimension 4 of J0(125) - ] + [Simple abelian subvariety 125a(1,125) of dimension 2 of J0(125), + Simple abelian subvariety 125b(1,125) of dimension 2 of J0(125), + Simple abelian subvariety 125c(1,125) of dimension 4 of J0(125)] sage: J[:2] - [ - Simple abelian subvariety 125a(1,125) of dimension 2 of J0(125), - Simple abelian subvariety 125b(1,125) of dimension 2 of J0(125) - ] + [Simple abelian subvariety 125a(1,125) of dimension 2 of J0(125), + Simple abelian subvariety 125b(1,125) of dimension 2 of J0(125)] """ return self.decomposition()[i] @@ -4014,13 +3980,11 @@ def __add__(self, other): EXAMPLES:: sage: A = J0(42); D = A.decomposition(); D - [ - Simple abelian subvariety 14a(1,42) of dimension 1 of J0(42), - Simple abelian subvariety 14a(3,42) of dimension 1 of J0(42), - Simple abelian subvariety 21a(1,42) of dimension 1 of J0(42), - Simple abelian subvariety 21a(2,42) of dimension 1 of J0(42), - Simple abelian subvariety 42a(1,42) of dimension 1 of J0(42) - ] + [Simple abelian subvariety 14a(1,42) of dimension 1 of J0(42), + Simple abelian subvariety 14a(3,42) of dimension 1 of J0(42), + Simple abelian subvariety 21a(1,42) of dimension 1 of J0(42), + Simple abelian subvariety 21a(2,42) of dimension 1 of J0(42), + Simple abelian subvariety 42a(1,42) of dimension 1 of J0(42)] sage: D[0] + D[1] Abelian subvariety of dimension 2 of J0(42) sage: D[1].is_subvariety(D[0] + D[1]) @@ -4312,13 +4276,11 @@ def is_subvariety(self, other): More examples:: sage: A = J0(42); D = A.decomposition(); D - [ - Simple abelian subvariety 14a(1,42) of dimension 1 of J0(42), - Simple abelian subvariety 14a(3,42) of dimension 1 of J0(42), - Simple abelian subvariety 21a(1,42) of dimension 1 of J0(42), - Simple abelian subvariety 21a(2,42) of dimension 1 of J0(42), - Simple abelian subvariety 42a(1,42) of dimension 1 of J0(42) - ] + [Simple abelian subvariety 14a(1,42) of dimension 1 of J0(42), + Simple abelian subvariety 14a(3,42) of dimension 1 of J0(42), + Simple abelian subvariety 21a(1,42) of dimension 1 of J0(42), + Simple abelian subvariety 21a(2,42) of dimension 1 of J0(42), + Simple abelian subvariety 42a(1,42) of dimension 1 of J0(42)] sage: D[0].is_subvariety(A) True sage: D[1].is_subvariety(D[0] + D[1]) @@ -4465,16 +4427,12 @@ def decomposition(self, simple=True, bound=None): sage: J = J0(33) sage: J.decomposition() - [ - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), - Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), + Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33)] sage: J1(17).decomposition() - [ - Simple abelian subvariety 17aG1(1,17) of dimension 1 of J1(17), - Simple abelian subvariety 17bG1(1,17) of dimension 4 of J1(17) - ] + [Simple abelian subvariety 17aG1(1,17) of dimension 1 of J1(17), + Simple abelian subvariety 17bG1(1,17) of dimension 4 of J1(17)] """ try: return self.__decomposition[(simple, bound)] @@ -4501,11 +4459,11 @@ def decomposition(self, simple=True, bound=None): else: X = A.decomposition(bound=bound) for B in X: - for t in divisors(M // N): - D.append(ModularAbelianVariety_modsym(B.degeneracy_map(M, t).image(), - is_simple=True, newform_level=(N, G), - isogeny_number=isogeny_number, - number=(t, M))) + D.extend(ModularAbelianVariety_modsym(B.degeneracy_map(M, t).image(), + is_simple=True, newform_level=(N, G), + isogeny_number=isogeny_number, + number=(t, M)) + for t in divisors(M // N)) isogeny_number += 1 elif A == amb.cuspidal_submodule(): D = [ModularAbelianVariety_modsym(B) @@ -4985,10 +4943,8 @@ def factor_new_space(M): sage: M = ModularSymbols(37).cuspidal_subspace() sage: sage.modular.abvar.abvar.factor_new_space(M) - [ - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(37) of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(37) of weight 2 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(37) of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(37) of weight 2 with sign 0 over Rational Field] """ t = None p = 2 @@ -5020,12 +4976,8 @@ def factor_modsym_space_new_factors(M): sage: M = ModularSymbols(33) sage: sage.modular.abvar.abvar.factor_modsym_space_new_factors(M) - [[ - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field - ], - [ - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field - ]] + [[Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field], + [Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field]] """ eps = M.character() K = eps.conductor() if eps is not None else 1 @@ -5051,27 +5003,36 @@ def simple_factorization_of_modsym_space(M, simple=True): sage: M = ModularSymbols(33) sage: sage.modular.abvar.abvar.simple_factorization_of_modsym_space(M) - [ - (11, 0, 1, Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field), - (11, 0, 3, Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field), - (33, 0, 1, Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field) - ] + [(11, + 0, + 1, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field), + (11, + 0, + 3, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field), + (33, + 0, + 1, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field)] sage: sage.modular.abvar.abvar.simple_factorization_of_modsym_space(M, simple=False) - [ - (11, 0, None, Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field), - (33, 0, None, Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field) - ] + [(11, + 0, + None, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field), + (33, + 0, + None, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field)] TESTS: Check that :issue:`21799` is fixed:: sage: JH(28, [15]).decomposition() - [ - Simple abelian subvariety 14aGH[15](1,28) of dimension 1 of JH(28,[15]), - Simple abelian subvariety 14aGH[15](2,28) of dimension 1 of JH(28,[15]), - Simple abelian subvariety 28aGH[15](1,28) of dimension 2 of JH(28,[15]) - ] + [Simple abelian subvariety 14aGH[15](1,28) of dimension 1 of JH(28,[15]), + Simple abelian subvariety 14aGH[15](2,28) of dimension 1 of JH(28,[15]), + Simple abelian subvariety 28aGH[15](1,28) of dimension 2 of JH(28,[15])] """ D = [] for G in factor_modsym_space_new_factors(M): @@ -5127,18 +5088,24 @@ def modsym_lattices(M, factors): sage: M = ModularSymbols(33) sage: factors = sage.modular.abvar.abvar.simple_factorization_of_modsym_space(M, simple=False) sage: sage.modular.abvar.abvar.modsym_lattices(M, factors) - [ - (11, 0, None, Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field, Free module of degree 6 and rank 4 over Integer Ring - Echelon basis matrix: - [ 1 0 0 0 -1 2] - [ 0 1 0 0 -1 1] - [ 0 0 1 0 -2 2] - [ 0 0 0 1 -1 -1]), - (33, 0, None, Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field, Free module of degree 6 and rank 2 over Integer Ring - Echelon basis matrix: - [ 1 0 0 -1 0 0] - [ 0 0 1 0 1 -1]) - ] + [(11, + 0, + None, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field, + Free module of degree 6 and rank 4 over Integer Ring + Echelon basis matrix: + [ 1 0 0 0 -1 2] + [ 0 1 0 0 -1 1] + [ 0 0 1 0 -2 2] + [ 0 0 0 1 -1 -1]), + (33, + 0, + None, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field, + Free module of degree 6 and rank 2 over Integer Ring + Echelon basis matrix: + [ 1 0 0 -1 0 0] + [ 0 0 1 0 1 -1])] """ # 1. Change basis of everything to the ambient integral modular symbols space # 2. Clear denominator. diff --git a/src/sage/modular/abvar/abvar_ambient_jacobian.py b/src/sage/modular/abvar/abvar_ambient_jacobian.py index 7674b41807a..e6f7e590fc0 100644 --- a/src/sage/modular/abvar/abvar_ambient_jacobian.py +++ b/src/sage/modular/abvar/abvar_ambient_jacobian.py @@ -335,25 +335,19 @@ def decomposition(self, simple=True, bound=None): EXAMPLES:: sage: J0(33).decomposition(simple=False) - [ - Abelian subvariety of dimension 2 of J0(33), - Abelian subvariety of dimension 1 of J0(33) - ] + [Abelian subvariety of dimension 2 of J0(33), + Abelian subvariety of dimension 1 of J0(33)] sage: J0(33).decomposition(simple=False)[1].is_simple() True sage: J0(33).decomposition(simple=False)[0].is_simple() False sage: J0(33).decomposition(simple=False) - [ - Abelian subvariety of dimension 2 of J0(33), - Simple abelian subvariety 33a(None,33) of dimension 1 of J0(33) - ] + [Abelian subvariety of dimension 2 of J0(33), + Simple abelian subvariety 33a(None,33) of dimension 1 of J0(33)] sage: J0(33).decomposition(simple=True) - [ - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), - Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), + Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33)] """ try: return self.__decomposition[simple] diff --git a/src/sage/modular/abvar/homology.py b/src/sage/modular/abvar/homology.py index 21a129072fa..d8b6b168bdb 100644 --- a/src/sage/modular/abvar/homology.py +++ b/src/sage/modular/abvar/homology.py @@ -29,10 +29,8 @@ sage: H.base_ring() Integer Ring sage: d = H.decomposition(); d - [ - Submodule of rank 2 of Integral Homology of Abelian variety J0(43) of dimension 3, - Submodule of rank 4 of Integral Homology of Abelian variety J0(43) of dimension 3 - ] + [Submodule of rank 2 of Integral Homology of Abelian variety J0(43) of dimension 3, + Submodule of rank 4 of Integral Homology of Abelian variety J0(43) of dimension 3] sage: a = d[0] sage: a.hecke_matrix(5) [-4 0] @@ -603,10 +601,8 @@ def __richcmp__(self, other, op): EXAMPLES:: sage: J0(37).homology().decomposition() # indirect doctest - [ - Submodule of rank 2 of Integral Homology of Abelian variety J0(37) of dimension 2, - Submodule of rank 2 of Integral Homology of Abelian variety J0(37) of dimension 2 - ] + [Submodule of rank 2 of Integral Homology of Abelian variety J0(37) of dimension 2, + Submodule of rank 2 of Integral Homology of Abelian variety J0(37) of dimension 2] """ if not isinstance(other, Homology_submodule): return NotImplemented @@ -626,10 +622,8 @@ def ambient_hecke_module(self): sage: H = J0(48).homology(); H Integral Homology of Abelian variety J0(48) of dimension 3 sage: d = H.decomposition(); d - [ - Submodule of rank 2 of Integral Homology of Abelian variety J0(48) of dimension 3, - Submodule of rank 4 of Integral Homology of Abelian variety J0(48) of dimension 3 - ] + [Submodule of rank 2 of Integral Homology of Abelian variety J0(48) of dimension 3, + Submodule of rank 4 of Integral Homology of Abelian variety J0(48) of dimension 3] sage: d[0].ambient_hecke_module() Integral Homology of Abelian variety J0(48) of dimension 3 """ @@ -662,10 +656,8 @@ def hecke_bound(self): EXAMPLES:: sage: d = J0(43).homology().decomposition(2); d - [ - Submodule of rank 2 of Integral Homology of Abelian variety J0(43) of dimension 3, - Submodule of rank 4 of Integral Homology of Abelian variety J0(43) of dimension 3 - ] + [Submodule of rank 2 of Integral Homology of Abelian variety J0(43) of dimension 3, + Submodule of rank 4 of Integral Homology of Abelian variety J0(43) of dimension 3] Because the first factor has dimension 2 it corresponds to an elliptic curve, so we have a Hecke bound of 1. @@ -690,14 +682,9 @@ def hecke_matrix(self, n): EXAMPLES:: sage: d = J0(125).homology(GF(17)).decomposition(2); d - [ - Submodule of rank 4 of Homology with coefficients in Finite Field of size 17 - of Abelian variety J0(125) of dimension 8, - Submodule of rank 4 of Homology with coefficients in Finite Field of size 17 - of Abelian variety J0(125) of dimension 8, - Submodule of rank 8 of Homology with coefficients in Finite Field of size 17 - of Abelian variety J0(125) of dimension 8 - ] + [Submodule of rank 4 of Homology with coefficients in Finite Field of size 17 of Abelian variety J0(125) of dimension 8, + Submodule of rank 4 of Homology with coefficients in Finite Field of size 17 of Abelian variety J0(125) of dimension 8, + Submodule of rank 8 of Homology with coefficients in Finite Field of size 17 of Abelian variety J0(125) of dimension 8] sage: t = d[0].hecke_matrix(17); t [16 15 15 0] [ 0 5 0 2] diff --git a/src/sage/modular/abvar/homspace.py b/src/sage/modular/abvar/homspace.py index 30ad76f3601..97200d8a6bc 100644 --- a/src/sage/modular/abvar/homspace.py +++ b/src/sage/modular/abvar/homspace.py @@ -12,10 +12,8 @@ sage: J = J0(37) sage: D = J.decomposition() ; D - [ - Simple abelian subvariety 37a(1,37) of dimension 1 of J0(37), - Simple abelian subvariety 37b(1,37) of dimension 1 of J0(37) - ] + [Simple abelian subvariety 37a(1,37) of dimension 1 of J0(37), + Simple abelian subvariety 37b(1,37) of dimension 1 of J0(37)] sage: D[0].intersection(D[1]) (Finite subgroup with invariants [2, 2] over QQ of Simple abelian subvariety 37a(1,37) of dimension 1 of J0(37), @@ -101,11 +99,9 @@ sage: J = J0(33) sage: D = J.decomposition() sage: D - [ - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), - Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33), + Simple abelian subvariety 33a(1,33) of dimension 1 of J0(33)] sage: Hom(D[0],D[1]).gens() (Abelian variety morphism: From: Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33) @@ -122,10 +118,8 @@ :: sage: DD = J.decomposition(simple=False) ; DD - [ - Abelian subvariety of dimension 2 of J0(33), - Abelian subvariety of dimension 1 of J0(33) - ] + [Abelian subvariety of dimension 2 of J0(33), + Abelian subvariety of dimension 1 of J0(33)] sage: A, B = DD sage: A == D[0] + D[1] True @@ -670,12 +664,10 @@ def _calculate_simple_gens(self): [1 1] ] sage: J = J0(11) * J0(33) ; J.decomposition() - [ - Simple abelian subvariety 11a(1,11) of dimension 1 of J0(11) x J0(33), - Simple abelian subvariety 11a(1,33) of dimension 1 of J0(11) x J0(33), - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(11) x J0(33), - Simple abelian subvariety 33a(1,33) of dimension 1 of J0(11) x J0(33) - ] + [Simple abelian subvariety 11a(1,11) of dimension 1 of J0(11) x J0(33), + Simple abelian subvariety 11a(1,33) of dimension 1 of J0(11) x J0(33), + Simple abelian subvariety 11a(3,33) of dimension 1 of J0(11) x J0(33), + Simple abelian subvariety 33a(1,33) of dimension 1 of J0(11) x J0(33)] sage: J[0].Hom(J[1])._calculate_simple_gens() [ [ 0 -1] @@ -700,9 +692,7 @@ def _calculate_simple_gens(self): :: sage: J = J0(23) ; J.decomposition() - [ - Simple abelian variety J0(23) of dimension 2 - ] + [Simple abelian variety J0(23) of dimension 2] sage: J[0].Hom(J[0])._calculate_simple_gens() [ [1 0 0 0] [ 0 1 -1 0] diff --git a/src/sage/modular/abvar/morphism.py b/src/sage/modular/abvar/morphism.py index ccf87e302e7..14cdfbd1b33 100644 --- a/src/sage/modular/abvar/morphism.py +++ b/src/sage/modular/abvar/morphism.py @@ -405,9 +405,7 @@ def __call__(self, X): sage: t3(E11a0) Abelian subvariety of dimension 1 of J0(33) sage: t3(E11a0).decomposition() - [ - Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33) - ] + [Simple abelian subvariety 11a(3,33) of dimension 1 of J0(33)] sage: t3(E11a0) == E11a1 True sage: t2(E11a0) == E11a0 diff --git a/src/sage/modular/abvar/torsion_subgroup.py b/src/sage/modular/abvar/torsion_subgroup.py index 6ae7bff58c7..310ff5419e6 100644 --- a/src/sage/modular/abvar/torsion_subgroup.py +++ b/src/sage/modular/abvar/torsion_subgroup.py @@ -30,10 +30,8 @@ sage: T.invariants() [15] sage: d = J.decomposition(); d - [ - Simple abelian subvariety 50a(1,50) of dimension 1 of J0(50), - Simple abelian subvariety 50b(1,50) of dimension 1 of J0(50) - ] + [Simple abelian subvariety 50a(1,50) of dimension 1 of J0(50), + Simple abelian subvariety 50b(1,50) of dimension 1 of J0(50)] sage: d[0].rational_torsion_subgroup().order() 3 sage: d[1].rational_torsion_subgroup().order() diff --git a/src/sage/modular/arithgroup/arithgroup_perm.py b/src/sage/modular/arithgroup/arithgroup_perm.py index 4238875048b..05d8b6059df 100644 --- a/src/sage/modular/arithgroup/arithgroup_perm.py +++ b/src/sage/modular/arithgroup/arithgroup_perm.py @@ -2587,16 +2587,22 @@ def odd_subgroups(self): A projective congruence subgroup may have noncongruence liftings, as the example of `\bar{\Gamma}_0(6)` illustrates (see [KSV2011]_):: sage: X = Gamma0(6).as_permutation_group().odd_subgroups(); Sequence([[u.S2(), u.S3()] for u in X],cr=True) - [ - [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), (1,2,3,13,14,15)(4,5,6,16,17,18)(7,8,9,19,20,21)(10,11,12,22,23,24)], - [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), (1,14,15,13,2,3)(4,5,6,16,17,18)(7,8,9,19,20,21)(10,11,12,22,23,24)], - [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), (1,2,3,13,14,15)(4,17,6,16,5,18)(7,8,9,19,20,21)(10,11,12,22,23,24)], - [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), (1,14,15,13,2,3)(4,17,6,16,5,18)(7,8,9,19,20,21)(10,11,12,22,23,24)], - [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), (1,2,3,13,14,15)(4,5,6,16,17,18)(7,20,9,19,8,21)(10,11,12,22,23,24)], - [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), (1,14,15,13,2,3)(4,5,6,16,17,18)(7,20,9,19,8,21)(10,11,12,22,23,24)], - [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), (1,2,3,13,14,15)(4,17,6,16,5,18)(7,20,9,19,8,21)(10,11,12,22,23,24)], - [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), (1,14,15,13,2,3)(4,17,6,16,5,18)(7,20,9,19,8,21)(10,11,12,22,23,24)] - ] + [[(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), + (1,2,3,13,14,15)(4,5,6,16,17,18)(7,8,9,19,20,21)(10,11,12,22,23,24)], + [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), + (1,14,15,13,2,3)(4,5,6,16,17,18)(7,8,9,19,20,21)(10,11,12,22,23,24)], + [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), + (1,2,3,13,14,15)(4,17,6,16,5,18)(7,8,9,19,20,21)(10,11,12,22,23,24)], + [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), + (1,14,15,13,2,3)(4,17,6,16,5,18)(7,8,9,19,20,21)(10,11,12,22,23,24)], + [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), + (1,2,3,13,14,15)(4,5,6,16,17,18)(7,20,9,19,8,21)(10,11,12,22,23,24)], + [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), + (1,14,15,13,2,3)(4,5,6,16,17,18)(7,20,9,19,8,21)(10,11,12,22,23,24)], + [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), + (1,2,3,13,14,15)(4,17,6,16,5,18)(7,20,9,19,8,21)(10,11,12,22,23,24)], + [(1,3,13,15)(2,4,14,16)(5,7,17,19)(6,10,18,22)(8,12,20,24)(9,11,21,23), + (1,14,15,13,2,3)(4,17,6,16,5,18)(7,20,9,19,8,21)(10,11,12,22,23,24)]] sage: [u.is_congruence() for u in X] [True, False, False, True, True, False, False, True] """ diff --git a/src/sage/modular/arithgroup/congroup.pyx b/src/sage/modular/arithgroup/congroup.pyx index d55c0c0ce7c..4972b39f435 100644 --- a/src/sage/modular/arithgroup/congroup.pyx +++ b/src/sage/modular/arithgroup/congroup.pyx @@ -31,7 +31,7 @@ from sage.rings.integer_ring import ZZ Mat2Z = MatrixSpace(ZZ, 2) cdef Matrix_integer_dense genS, genT, genI -genS = Matrix_integer_dense(Mat2Z, [0,-1, 1, 0], True, True) +genS = Matrix_integer_dense(Mat2Z, [0, -1, 1, 0], True, True) genT = Matrix_integer_dense(Mat2Z, [1, 1, 0, 1], True, True) genI = Matrix_integer_dense(Mat2Z, [1, 0, 0, 1], True, True) @@ -123,7 +123,7 @@ def degeneracy_coset_representatives_gamma0(int N, int M, int t): # try to find another coset representative. cc = M*random.randrange(-halfmax, halfmax+1) dd = random.randrange(-halfmax, halfmax+1) - g = arith_int.c_xgcd_int(-cc,dd,&bb,&aa) + g = arith_int.c_xgcd_int(-cc, dd, &bb, &aa) if g == 0: continue cc = cc // g @@ -297,22 +297,24 @@ def generators_helper(coset_reps, level): [21 5], [ 7 -1], [-7 1] ] """ - cdef Matrix_integer_dense x,y,z,v,vSmod,vTmod + cdef Matrix_integer_dense x, y, z, v, vSmod, vTmod crs = coset_reps.list() try: - reps = [Matrix_integer_dense(Mat2Z,lift_to_sl2z(c, d, level),False,True) for c,d in crs] + reps = [Matrix_integer_dense(Mat2Z, lift_to_sl2z(c, d, level), + False, True) for c, d in crs] except Exception: raise ArithmeticError("Error lifting to SL2Z: level=%s crs=%s" % (level, crs)) ans = [] cdef Py_ssize_t i for i in range(len(crs)): x = reps[i] - v = Matrix_integer_dense(Mat2Z,[crs[i][0],crs[i][1],0,0],False,True) + v = Matrix_integer_dense(Mat2Z, [crs[i][0], crs[i][1], 0, 0], + False, True) vSmod = (v*genS) vTmod = (v*genT) - y_index = coset_reps.normalize(vSmod[0,0],vSmod[0,1]) - z_index = coset_reps.normalize(vTmod[0,0],vTmod[0,1]) + y_index = coset_reps.normalize(vSmod[0, 0], vSmod[0, 1]) + z_index = coset_reps.normalize(vTmod[0, 0], vTmod[0, 1]) y_index = crs.index(y_index) z_index = crs.index(z_index) y = reps[y_index] diff --git a/src/sage/modular/arithgroup/congroup_generic.py b/src/sage/modular/arithgroup/congroup_generic.py index b94568522f6..48ec86783e1 100644 --- a/src/sage/modular/arithgroup/congroup_generic.py +++ b/src/sage/modular/arithgroup/congroup_generic.py @@ -464,7 +464,7 @@ def __init__(self, *args, **kwds): sage: sage.modular.arithgroup.congroup_generic.CongruenceSubgroup(5) # indirect doctest Generic congruence subgroup of level 5 """ - return CongruenceSubgroupBase.__init__(self, *args, **kwds) + CongruenceSubgroupBase.__init__(self, *args, **kwds) def _repr_(self): """ diff --git a/src/sage/modular/arithgroup/farey_symbol.pyx b/src/sage/modular/arithgroup/farey_symbol.pyx index c965015b41d..af81a0f61fc 100644 --- a/src/sage/modular/arithgroup/farey_symbol.pyx +++ b/src/sage/modular/arithgroup/farey_symbol.pyx @@ -13,15 +13,15 @@ based on the *KFarey* package by Chris Kurth. Implemented as C++ module for speed. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2011 Hartmut Monien # # 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 cpython.object cimport PyObject_RichCompare from itertools import groupby @@ -206,11 +206,11 @@ cdef class Farey: self.this_ptr = new cpp_farey(data) sig_off() return - ## to accelerate the calculation of the FareySymbol - ## we implement the tests for the standard congruence groups - ## in the c++ module. For a general group the test if an element - ## of SL2Z is in the group the python __contains__ attribute - ## of the group is called + # to accelerate the calculation of the FareySymbol + # we implement the tests for the standard congruence groups + # in the c++ module. For a general group the test if an element + # of SL2Z is in the group the python __contains__ attribute + # of the group is called cdef int p if hasattr(group, "level"): p = group.level() @@ -285,19 +285,19 @@ cdef class Farey: a, b, c, d = pm.matrix().list() newval = gens_dict.get(SL2Z([a, b, c, d])) if newval is not None: - ans.append((newval,1)) + ans.append((newval, 1)) continue newval = gens_dict.get(SL2Z([-a, -b, -c, -d])) if newval is not None: - ans.append((newval,-1)) + ans.append((newval, -1)) continue newval = gens_dict.get(SL2Z([d, -b, -c, a])) if newval is not None: - ans.append((-newval,1)) + ans.append((-newval, 1)) continue newval = gens_dict.get(SL2Z([-d, b, c, -a])) if newval is not None: - ans.append((-newval,-1)) + ans.append((-newval, -1)) continue raise RuntimeError("This should have not happened") return ans @@ -453,7 +453,7 @@ cdef class Farey: result = self.this_ptr.word_problem(a.value, b.value, c.value, d.value, cpp_beta) sig_off() beta = convert_to_SL2Z(cpp_beta[0])**-1 - mbeta = SL2Z([-beta.a(),-beta.b(),-beta.c(),-beta.d()]) + mbeta = SL2Z([-beta.a(), -beta.b(), -beta.c(), -beta.d()]) V = self.pairing_matrices_to_tietze_index() sgn = 1 tietze = [] @@ -500,7 +500,7 @@ cdef class Farey: tietze.reverse() gens = self.generators() if check: - tmp = SL2Z([1,0,0,1]) + tmp = SL2Z([1, 0, 0, 1]) for i in range(len(tietze)): t = tietze[i] tmp = tmp * gens[t-1] if t > 0 else tmp * gens[-t-1]**-1 @@ -1009,7 +1009,7 @@ cdef class Farey: fill=options['fill'], linestyle=options['linestyle'], thickness=options['thickness']) - ## show pairings + # show pairings p = self.pairings() x = self.fractions() if options['show_pairing']: @@ -1033,7 +1033,7 @@ cdef class Farey: return g -#--- conversions ------------------------------------------------------------ +# ----- conversions --------------------------------- cdef public long convert_to_long(n) noexcept: cdef long m = n diff --git a/src/sage/modular/arithgroup/meson.build b/src/sage/modular/arithgroup/meson.build index c4a68af3217..52475097b34 100644 --- a/src/sage/modular/arithgroup/meson.build +++ b/src/sage/modular/arithgroup/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'arithgroup_generic.py', 'arithgroup_perm.py', diff --git a/src/sage/modular/cusps.py b/src/sage/modular/cusps.py index 7a4a2628096..1dc3a2aaa22 100644 --- a/src/sage/modular/cusps.py +++ b/src/sage/modular/cusps.py @@ -27,6 +27,7 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.misc.cachefunc import cached_method from sage.misc.fast_methods import Singleton from sage.modular.modsym.p1list import lift_to_sl2z_llong from sage.rings.infinity import Infinity, InfinityRing @@ -195,7 +196,7 @@ def __init__(self, a, b=None, parent=None, check=True): self.__a = r.numer() self.__b = r.denom() except (ValueError, TypeError): - raise TypeError("unable to convert %r to a cusp" % a) + raise TypeError(f"unable to convert {a} to a cusp") else: try: r = QQ(a) @@ -364,6 +365,7 @@ def denominator(self): """ return self.__b + @cached_method def _rational_(self): """ Coerce to a rational number. @@ -379,15 +381,9 @@ def _rational_(self): sage: Cusp(11,2)._rational_() 11/2 """ - try: - return self.__rational - except AttributeError: - pass - if not self.__b: raise TypeError("cusp %s is not a rational number" % self) - self.__rational = self.__a / self.__b - return self.__rational + return self.__a / self.__b def _integer_(self, ZZ=None): """ diff --git a/src/sage/modular/cusps_nf.py b/src/sage/modular/cusps_nf.py index 4d120c075da..2fdfc7cdc02 100644 --- a/src/sage/modular/cusps_nf.py +++ b/src/sage/modular/cusps_nf.py @@ -488,8 +488,8 @@ def __init__(self, number_field, a, b=None, parent=None, lreps=None): self.__b = R(r.denominator()) self.__a = R(r * self.__b) except (ValueError, TypeError): - raise TypeError("unable to convert %r to a cusp " - "of the number field" % a) + raise TypeError(f"unable to convert {a} to a cusp " + "of the number field") else: try: r = number_field(a) diff --git a/src/sage/modular/dims.py b/src/sage/modular/dims.py index 7eef7392e76..423ed5a0c96 100644 --- a/src/sage/modular/dims.py +++ b/src/sage/modular/dims.py @@ -54,7 +54,7 @@ from sage.rings.integer import Integer from sage.rings.rational_field import frac -from . import dirichlet +from sage.modular import dirichlet ########################################################################## # Helper functions for calculating dimensions of spaces of modular forms diff --git a/src/sage/modular/dirichlet.py b/src/sage/modular/dirichlet.py index c261a84e8de..f93984335bd 100644 --- a/src/sage/modular/dirichlet.py +++ b/src/sage/modular/dirichlet.py @@ -999,10 +999,8 @@ def fixed_field_polynomial(self, algorithm='pari'): v += s m.append(v) - m = matrix(m) - xx = S.gen() - return m.charpoly(xx) + return matrix(m).charpoly(xx) elif algorithm == "pari": # Use pari @@ -1264,11 +1262,9 @@ def galois_orbit(self, sort=True): sage: G = DirichletGroup(13) sage: G.galois_orbits() - [ - [Dirichlet character modulo 13 of conductor 1 mapping 2 |--> 1], - ..., - [Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -1] - ] + [[Dirichlet character modulo 13 of conductor 1 mapping 2 |--> 1], + ..., + [Dirichlet character modulo 13 of conductor 13 mapping 2 |--> -1]] sage: e = G.0 sage: e Dirichlet character modulo 13 of conductor 13 mapping 2 |--> zeta12 @@ -2950,15 +2946,11 @@ def decomposition(self): EXAMPLES:: sage: DirichletGroup(20).decomposition() - [ - Group of Dirichlet characters modulo 4 with values in Cyclotomic Field of order 4 and degree 2, - Group of Dirichlet characters modulo 5 with values in Cyclotomic Field of order 4 and degree 2 - ] + [Group of Dirichlet characters modulo 4 with values in Cyclotomic Field of order 4 and degree 2, + Group of Dirichlet characters modulo 5 with values in Cyclotomic Field of order 4 and degree 2] sage: DirichletGroup(20,GF(5)).decomposition() - [ - Group of Dirichlet characters modulo 4 with values in Finite Field of size 5, - Group of Dirichlet characters modulo 5 with values in Finite Field of size 5 - ] + [Group of Dirichlet characters modulo 4 with values in Finite Field of size 5, + Group of Dirichlet characters modulo 5 with values in Finite Field of size 5] """ R = self.base_ring() return Sequence([DirichletGroup(p**r, R) @@ -3047,11 +3039,7 @@ def galois_orbits(self, v=None, reps_only=False, sort=True, check=True): EXAMPLES:: sage: DirichletGroup(20).galois_orbits() - [ - [Dirichlet character modulo 20 of conductor 20 mapping 11 |--> -1, 17 |--> -1], - ..., - [Dirichlet character modulo 20 of conductor 1 mapping 11 |--> 1, 17 |--> 1] - ] + [[Dirichlet character modulo 20 of conductor 20 mapping ...]] sage: DirichletGroup(17, Integers(6), zeta=Integers(6)(5)).galois_orbits() Traceback (most recent call last): ... diff --git a/src/sage/modular/drinfeld_modform/ring.py b/src/sage/modular/drinfeld_modform/ring.py index 43c41058fe2..b027edc08ca 100644 --- a/src/sage/modular/drinfeld_modform/ring.py +++ b/src/sage/modular/drinfeld_modform/ring.py @@ -36,7 +36,7 @@ from sage.rings.fraction_field import FractionField_generic from sage.rings.polynomial.ore_polynomial_ring import OrePolynomialRing from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.term_order import TermOrder from sage.rings.integer_ring import ZZ @@ -265,7 +265,7 @@ def __classcall_private__(cls, base_ring, rank=None, group=None, if not isinstance(base_ring, FractionField_generic): raise TypeError("base ring must be a fraction field of a " "polynomial ring") - if not isinstance(base_ring.base(), PolynomialRing_general): + if not isinstance(base_ring.base(), PolynomialRing_generic): raise NotImplementedError("Drinfeld modular forms are currently " "only implemented for A = Fq[T]") if not base_ring.characteristic(): diff --git a/src/sage/modular/etaproducts.py b/src/sage/modular/etaproducts.py index a063255c6a6..eedb7da940e 100644 --- a/src/sage/modular/etaproducts.py +++ b/src/sage/modular/etaproducts.py @@ -31,6 +31,7 @@ # https://www.gnu.org/licenses/ # *************************************************************************** from __future__ import annotations +from typing import Any from sage.arith.misc import divisors, prime_divisors, euler_phi, is_square, gcd from sage.categories.groups import Groups @@ -52,7 +53,7 @@ import weakref -_cache = {} +_cache: dict[int, Any] = {} def EtaGroup(level): @@ -107,10 +108,10 @@ def __init__(self, parent, rdict): if rdict == 1: rdict = {} + # Check Ligozat criteria sumR = sumDR = sumNoverDr = 0 prod = 1 - for d in list(rdict): if N % d: raise ValueError("%s does not divide %s" % (d, N)) @@ -120,7 +121,7 @@ def __init__(self, parent, rdict): continue sumR += rdict[d] sumDR += rdict[d] * d - sumNoverDr += rdict[d] * N / d + sumNoverDr += rdict[d] * (N // d) prod *= (N // d)**rdict[d] if sumR != 0: @@ -202,7 +203,7 @@ def is_one(self) -> bool: """ return not self._rdict - def _richcmp_(self, other, op): + def _richcmp_(self, other, op) -> bool: r""" Compare ``self`` to ``other``. @@ -541,8 +542,8 @@ def basis(self, reduce=True) -> list: for di in divs: # generate a row of relation matrix row = [Mod(di, 24) - Mod(N, 24), Mod(N // di, 24) - Mod(1, 24)] - for p in primedivs: - row.append(Mod(12 * (N // di).valuation(p), 24)) + row.extend(Mod(12 * (N // di).valuation(p), 24) + for p in primedivs) rows.append(row) M = matrix(IntegerModRing(24), rows) @@ -556,7 +557,7 @@ def basis(self, reduce=True) -> list: good_vects.append((vect * 24 / gcd(nf, 24)).list()) for v in good_vects: v.append(-sum(list(v))) - dicts = [] + dicts: list[dict] = [] for v in good_vects: dicts.append({}) for i in range(s): @@ -717,8 +718,8 @@ def AllCusps(N) -> list: if n == 1: c.append(CuspFamily(N, d)) elif n > 1: - for i in range(n): - c.append(CuspFamily(N, d, label=str(i + 1))) + c.extend(CuspFamily(N, d, label=str(i + 1)) + for i in range(n)) return c @@ -1036,9 +1037,7 @@ def _eta_relations_helper(eta1, eta2, degree, qexp_terms, labels, verbose): if verbose: print("Trying all coefficients from q^%s to q^%s inclusive" % (-pole_at_infinity, -pole_at_infinity + qexp_terms - 1)) - rows = [] - for j in range(qexp_terms): - rows.append([]) + rows: list[list] = [[] for _ in range(qexp_terms)] for i in indices: func = (eta1**i[0] * eta2**i[1]).qexp(qexp_terms) for j in range(qexp_terms): diff --git a/src/sage/modular/hecke/algebra.py b/src/sage/modular/hecke/algebra.py index 383a4e0c035..7c209d146b6 100644 --- a/src/sage/modular/hecke/algebra.py +++ b/src/sage/modular/hecke/algebra.py @@ -91,7 +91,6 @@ def _heckebasis(M): MM = MatrixSpace(QQ, d) S = [] Denom = [] - B = [] B1 = [] for i in range(1, M.hecke_bound() + 1): v = M.hecke_operator(i).matrix() @@ -99,11 +98,9 @@ def _heckebasis(M): Denom.append(den) S.append(v) den = lcm(Denom) - for m in S: - B.append(WW((den * m).list())) + B = [WW((den * m).list()) for m in S] UU = WW.submodule(B) - B = UU.basis() - for u in B: + for u in UU.basis(): u1 = u.list() m1 = M.hecke_algebra()(MM(u1), check=False) B1.append((1 / den) * m1) diff --git a/src/sage/modular/hecke/ambient_module.py b/src/sage/modular/hecke/ambient_module.py index 3ce44fa63ce..5f0cec78f20 100644 --- a/src/sage/modular/hecke/ambient_module.py +++ b/src/sage/modular/hecke/ambient_module.py @@ -242,10 +242,8 @@ def decomposition_matrix(self): try: return self.__decomposition_matrix_cache except AttributeError: - rows = [] - for A in self.decomposition(): - for x in A.basis(): - rows.append(x.list()) + rows = [x.list() for A in self.decomposition() + for x in A.basis()] A = matrix_space.MatrixSpace(self.base_ring(), self.rank())(rows) self.__decomposition_matrix_cache = A return self.__decomposition_matrix_cache @@ -347,14 +345,8 @@ def degeneracy_map(self, codomain, t=1): sage: D = ModularSymbols(10,4).cuspidal_submodule().decomposition() sage: D - [ - Modular Symbols subspace of dimension 2 of - Modular Symbols space of dimension 10 for - Gamma_0(10) of weight 4 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 4 of - Modular Symbols space of dimension 10 for - Gamma_0(10) of weight 4 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 10 for Gamma_0(10) of weight 4 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 10 for Gamma_0(10) of weight 4 with sign 0 over Rational Field] sage: D[1].degeneracy_map(5) Hecke module morphism defined by the matrix [ 0 0 -1 1] diff --git a/src/sage/modular/hecke/hecke_operator.py b/src/sage/modular/hecke/hecke_operator.py index c7d39270f63..fddf20f75ee 100644 --- a/src/sage/modular/hecke/hecke_operator.py +++ b/src/sage/modular/hecke/hecke_operator.py @@ -295,20 +295,16 @@ def decomposition(self): sage: M = ModularSymbols(11) sage: t2 = M.hecke_operator(2) sage: t2.decomposition() - [ - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(11) of weight 2 with sign 0 over Rational Field] :: sage: M = ModularSymbols(33, sign=1).new_submodule() sage: T = M.hecke_operator(2) sage: T.decomposition() - [ - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field, - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field - ] + [Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field, + Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field] """ try: return self.__decomposition diff --git a/src/sage/modular/hecke/module.py b/src/sage/modular/hecke/module.py index bbc76fd1cbc..bd5e3be5733 100644 --- a/src/sage/modular/hecke/module.py +++ b/src/sage/modular/hecke/module.py @@ -582,20 +582,15 @@ def _eigen_nonzero(self): sage: M._eigen_nonzero() 0 sage: M.dual_free_module().basis() - [ - (1, 0, 0, 0, 0), - (0, 1, 0, 0, 0), - (0, 0, 1, 0, 0), - (0, 0, 0, 1, 0), - (0, 0, 0, 0, 1) - ] + [(1, 0, 0, 0, 0), + (0, 1, 0, 0, 0), + (0, 0, 1, 0, 0), + (0, 0, 0, 1, 0), + (0, 0, 0, 0, 1)] sage: M.cuspidal_submodule().minus_submodule()._eigen_nonzero() 1 sage: M.cuspidal_submodule().minus_submodule().dual_free_module().basis() - [ - (0, 1, 0, 0, 0), - (0, 0, 1, 0, 0) - ] + [(0, 1, 0, 0, 0), (0, 0, 1, 0, 0)] """ try: return self.__eigen_nonzero @@ -944,40 +939,32 @@ def decomposition(self, bound=None, anemic=True, height_guess=1, EXAMPLES:: sage: ModularSymbols(17,2).decomposition() - [ - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(17) of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(17) of weight 2 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(17) of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 3 for Gamma_0(17) of weight 2 with sign 0 over Rational Field] sage: ModularSymbols(Gamma1(10),4).decomposition() - [ - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 18 for Gamma_1(10) of weight 4 with sign 0 over Rational Field] sage: ModularSymbols(GammaH(12, [11])).decomposition() - [ - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 5 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 5 of Modular Symbols space of dimension 9 for Congruence Subgroup Gamma_H(12) with H generated by [11] of weight 2 with sign 0 over Rational Field] TESTS:: sage: M = ModularSymbols(1000,2,sign=1).new_subspace().cuspidal_subspace() sage: M.decomposition(3, sort_by_basis = True) - [ - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field - ] + [Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 154 for Gamma_0(1000) of weight 2 with sign 1 over Rational Field] """ if not isinstance(anemic, bool): raise TypeError("anemic must be of type bool.") @@ -1610,10 +1597,8 @@ def projection(self): sage: m = ModularSymbols(34); s = m.cuspidal_submodule() sage: d = s.decomposition(7) sage: d - [ - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(34) of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 9 for Gamma_0(34) of weight 2 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(34) of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 9 for Gamma_0(34) of weight 2 with sign 0 over Rational Field] sage: a = d[0]; a Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(34) of weight 2 with sign 0 over Rational Field sage: pi = a.projection() diff --git a/src/sage/modular/hecke/submodule.py b/src/sage/modular/hecke/submodule.py index c542d095339..d0a28b31319 100644 --- a/src/sage/modular/hecke/submodule.py +++ b/src/sage/modular/hecke/submodule.py @@ -425,10 +425,8 @@ def degeneracy_map(self, level, t=1): EXAMPLES:: sage: D = ModularSymbols(10,4).cuspidal_submodule().decomposition(); D - [ - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 10 for Gamma_0(10) of weight 4 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 10 for Gamma_0(10) of weight 4 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 10 for Gamma_0(10) of weight 4 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 10 for Gamma_0(10) of weight 4 with sign 0 over Rational Field] sage: d = D[1].degeneracy_map(5); d Hecke module morphism defined by the matrix [ 0 0 -1 1] @@ -776,10 +774,7 @@ def linear_combination_of_basis(self, v): sage: S = M.cuspidal_submodule() sage: S.basis() - [ - q + 252*q^3 - 2048*q^4 + 4830*q^5 + O(q^6), - q^2 - 24*q^4 + O(q^6) - ] + [q + 252*q^3 - 2048*q^4 + 4830*q^5 + O(q^6), q^2 - 24*q^4 + O(q^6)] sage: S.linear_combination_of_basis([3, 10]) 3*q + 10*q^2 + 756*q^3 - 6384*q^4 + 14490*q^5 + O(q^6) """ diff --git a/src/sage/modular/hypergeometric_motive.py b/src/sage/modular/hypergeometric_motive.py index 5418a1fff58..4bf214d7e23 100644 --- a/src/sage/modular/hypergeometric_motive.py +++ b/src/sage/modular/hypergeometric_motive.py @@ -355,16 +355,16 @@ def cyclotomic_to_gamma(cyclo_up, cyclo_down) -> dict: sage: cyclotomic_to_gamma([6], [1]) {2: -1, 3: -1, 6: 1} """ - dico = defaultdict(int) + dico: dict[int, int] = defaultdict(int) for d in cyclo_up: dico[d] += 1 for d in cyclo_down: dico[d] -= 1 - resu = defaultdict(int) + resu: dict[int, int] = defaultdict(int) for n in dico: for d in divisors(n): - resu[d] += moebius(n / d) * dico[n] + resu[d] += moebius(n // d) * dico[n] return {d: resu[d] for d in resu if resu[d]} @@ -399,7 +399,7 @@ def gamma_list_to_cyclotomic(galist): sage: gamma_list_to_cyclotomic([8, 2, 2, 2, -6, -4, -3, -1]) ([2, 2, 8], [3, 3, 6]) """ - resu = defaultdict(int) + resu: dict[int, int] = defaultdict(int) for n in galist: eps = sgn(n) for d in divisors(abs(n)): @@ -685,7 +685,7 @@ def zigzag(self, x, flip_beta=False): Count ``alpha``'s at most ``x`` minus ``beta``'s at most ``x``. This function is used to compute the weight and the Hodge numbers. - With `flip_beta` set to ``True``, replace each `b` in `\beta` + With ``flip_beta`` set to ``True``, replace each `b` in `\beta` with `1-b`. .. SEEALSO:: @@ -824,7 +824,7 @@ def hodge_numbers(self) -> list: alpha = [(x, 'a') for x in self._alpha] beta = [(x, 'b') for x in self._beta] height = 0 - hodge = defaultdict(int) + hodge: dict[int, int] = defaultdict(int) for x, letter in sorted(alpha + beta): if letter == 'a': hodge[height] += 1 @@ -1317,7 +1317,7 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): If left unspecified, `prec` is set to the minimum `p`-adic precision needed to recover the Euler factor. - If `cache_p` is ``True``, then the function caches an intermediate + If ``cache_p`` is ``True``, then the function caches an intermediate result which depends only on `p` and `f`. This leads to a significant speedup when iterating over `t`. @@ -1423,7 +1423,7 @@ def padic_H_value(self, p, f, t, prec=None, cache_p=False): if q > 2 ** 31: raise ValueError("p^f cannot exceed 2^31") - m = defaultdict(int) + m: dict[int, int] = defaultdict(int) for b in beta: u = b * (q - 1) if u.is_integer(): @@ -1933,13 +1933,13 @@ def euler_factor(self, t, p, deg=None, cache_p=False): P = PolynomialRing(ZZ, 'T') if t.numerator() % p == 0 or t.denominator() % p == 0: ans = P.one() - for m in set(j for i in self.cyclotomic_data() for j in i): + for m in {j for i in self.cyclotomic_data() for j in i}: ans *= self.euler_factor_tame_contribution(t, p, m, deg) if deg is not None: ans = ans.truncate(deg + 1) return ans # now p is good, or p is tame and t is a p-adic unit - elif (t-1) % p == 0: + elif (t - 1) % p == 0: typ = "mult" d = self.degree() - 1 if d % 2: diff --git a/src/sage/modular/local_comp/local_comp.py b/src/sage/modular/local_comp/local_comp.py index 349c1e407e1..dc303ae9e00 100644 --- a/src/sage/modular/local_comp/local_comp.py +++ b/src/sage/modular/local_comp/local_comp.py @@ -82,12 +82,8 @@ def LocalComponent(f, p, twist_factor=None): sage: Pi.species() 'Supercuspidal' sage: Pi.characters() - [ - Character of unramified extension Q_7(s)* (s^2 + 6*s + 3 = 0), - of level 1, mapping s |--> -d, 7 |--> 1, - Character of unramified extension Q_7(s)* (s^2 + 6*s + 3 = 0), - of level 1, mapping s |--> d, 7 |--> 1 - ] + [Character of unramified extension Q_7(s)* (s^2 + 6*s + 3 = 0), of level 1, mapping s |--> -d, 7 |--> 1, + Character of unramified extension Q_7(s)* (s^2 + 6*s + 3 = 0), of level 1, mapping s |--> d, 7 |--> 1] """ p = ZZ(p) if not p.is_prime(): @@ -455,15 +451,11 @@ def characters(self): EXAMPLES:: sage: LocalComponent(Newform('11a'), 17).characters() - [ - Character of Q_17*, of level 0, mapping 17 |--> d, - Character of Q_17*, of level 0, mapping 17 |--> -d - 2 - ] + [Character of Q_17*, of level 0, mapping 17 |--> d, + Character of Q_17*, of level 0, mapping 17 |--> -d - 2] sage: LocalComponent(Newforms(Gamma1(5), 6, names='a')[1], 3).characters() - [ - Character of Q_3*, of level 0, mapping 3 |--> -3/2*a1 + 12, - Character of Q_3*, of level 0, mapping 3 |--> -3/2*a1 - 12 - ] + [Character of Q_3*, of level 0, mapping 3 |--> -3/2*a1 + 12, + Character of Q_3*, of level 0, mapping 3 |--> -3/2*a1 - 12] """ f = self.satake_polynomial() if not f.is_irreducible(): @@ -495,10 +487,8 @@ def characters(self): EXAMPLES:: sage: LocalComponent(Newforms(Gamma1(13), 2, names='a')[0], 13).characters() - [ - Character of Q_13*, of level 0, mapping 13 |--> 3*a0 + 2, - Character of Q_13*, of level 1, mapping 2 |--> a0 + 2, 13 |--> -3*a0 - 7 - ] + [Character of Q_13*, of level 0, mapping 13 |--> 3*a0 + 2, + Character of Q_13*, of level 1, mapping 2 |--> a0 + 2, 13 |--> -3*a0 - 7] """ G = SmoothCharacterGroupQp(self.prime(), self.coefficient_field()) t = ZZ((self.newform().weight() - 2 - self.twist_factor()) / 2) @@ -653,12 +643,8 @@ def characters(self): sage: f = Newform('50a') sage: Pi = LocalComponent(f, 5) sage: chars = Pi.characters(); chars - [ - Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), - of level 1, mapping s |--> -d - 1, 5 |--> 1, - Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), - of level 1, mapping s |--> d, 5 |--> 1 - ] + [Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -d - 1, 5 |--> 1, + Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> d, 5 |--> 1] sage: chars[0].base_ring() Number Field in d with defining polynomial x^2 + x + 1 @@ -673,12 +659,8 @@ def characters(self): q + j0*q^2 + 1/3*j0^3*q^3 - 1/3*j0^2*q^4 + O(q^6) sage: Pi = LocalComponent(f, 5) sage: Pi.characters() - [ - Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), - of level 1, mapping s |--> 1/3*j0^2*d - 1/3*j0^3, 5 |--> 5, - Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), - of level 1, mapping s |--> -1/3*j0^2*d, 5 |--> 5 - ] + [Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> 1/3*j0^2*d - 1/3*j0^3, 5 |--> 5, + Character of unramified extension Q_5(s)* (s^2 + 4*s + 2 = 0), of level 1, mapping s |--> -1/3*j0^2*d, 5 |--> 5] sage: Pi.characters()[0].base_ring() Number Field in d with defining polynomial x^2 - j0*x + 1/3*j0^2 over its base field @@ -694,29 +676,17 @@ def characters(self): sage: f = Newform('81a', names='j'); f q + j0*q^2 + q^4 - j0*q^5 + O(q^6) sage: LocalComponent(f, 3).characters() # long time (12s on sage.math, 2012) - [ - Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), - of level 2, mapping -2*s |--> -2*d + j0, 4 |--> 1, 3*s + 1 |--> -j0*d + 1, 3 |--> 1, - Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), - of level 2, mapping -2*s |--> 2*d - j0, 4 |--> 1, 3*s + 1 |--> j0*d - 2, 3 |--> 1 - ] + [Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 2, mapping -2*s |--> -2*d + j0, 4 |--> 1, 3*s + 1 |--> -j0*d + 1, 3 |--> 1, + Character of unramified extension Q_3(s)* (s^2 + 2*s + 2 = 0), of level 2, mapping -2*s |--> 2*d - j0, 4 |--> 1, 3*s + 1 |--> j0*d - 2, 3 |--> 1] Some ramified examples:: sage: Newform('27a').local_component(3).characters() - [ - Character of ramified extension Q_3(s)* (s^2 - 6 = 0), - of level 2, mapping 2 |--> 1, s + 1 |--> -d, s |--> -1, - Character of ramified extension Q_3(s)* (s^2 - 6 = 0), - of level 2, mapping 2 |--> 1, s + 1 |--> d - 1, s |--> -1 - ] + [Character of ramified extension Q_3(s)* (s^2 - 6 = 0), of level 2, mapping 2 |--> 1, s + 1 |--> -d, s |--> -1, + Character of ramified extension Q_3(s)* (s^2 - 6 = 0), of level 2, mapping 2 |--> 1, s + 1 |--> d - 1, s |--> -1] sage: LocalComponent(Newform('54a'), 3, twist_factor=4).characters() - [ - Character of ramified extension Q_3(s)* (s^2 - 3 = 0), - of level 2, mapping 2 |--> 1, s + 1 |--> -1/9*d, s |--> -9, - Character of ramified extension Q_3(s)* (s^2 - 3 = 0), - of level 2, mapping 2 |--> 1, s + 1 |--> 1/9*d - 1, s |--> -9 - ] + [Character of ramified extension Q_3(s)* (s^2 - 3 = 0), of level 2, mapping 2 |--> 1, s + 1 |--> -1/9*d, s |--> -9, + Character of ramified extension Q_3(s)* (s^2 - 3 = 0), of level 2, mapping 2 |--> 1, s + 1 |--> 1/9*d - 1, s |--> -9] A 2-adic non-example:: @@ -736,12 +706,8 @@ def characters(self): mapping s |--> 1, 2*s + 1 |--> 1/2*a0, 4*s + 1 |--> -1, -1 |--> 1, 2 |--> 1 ] sage: Newform('243a',names='a').local_component(3).characters() # long time - [ - Character of ramified extension Q_3(s)* (s^2 - 6 = 0), of level 4, - mapping -2*s - 1 |--> -d - 1, 4 |--> 1, 3*s + 1 |--> -d - 1, s |--> 1, - Character of ramified extension Q_3(s)* (s^2 - 6 = 0), of level 4, - mapping -2*s - 1 |--> d, 4 |--> 1, 3*s + 1 |--> d, s |--> 1 - ] + [Character of ramified extension Q_3(s)* (s^2 - 6 = 0), of level 4, mapping -2*s - 1 |--> -d - 1, 4 |--> 1, 3*s + 1 |--> -d - 1, s |--> 1, + Character of ramified extension Q_3(s)* (s^2 - 6 = 0), of level 4, mapping -2*s - 1 |--> d, 4 |--> 1, 3*s + 1 |--> d, s |--> 1] """ T = self.type_space() p = self.prime() @@ -1067,10 +1033,8 @@ def characters(self): sage: f = [f for f in Newforms(63, 4, names='a') if f[2] == 1][0] sage: f.local_component(3).characters() - [ - Character of Q_3*, of level 1, mapping 2 |--> -1, 3 |--> d, - Character of Q_3*, of level 1, mapping 2 |--> -1, 3 |--> -d - 2 - ] + [Character of Q_3*, of level 1, mapping 2 |--> -1, 3 |--> d, + Character of Q_3*, of level 1, mapping 2 |--> -1, 3 |--> -d - 2] """ minchars = self._min_twist.characters() G = minchars[0].parent() diff --git a/src/sage/modular/meson.build b/src/sage/modular/meson.build index d334cf975c8..8b7e48c94aa 100644 --- a/src/sage/modular/meson.build +++ b/src/sage/modular/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'buzzard.py', 'congroup.py', diff --git a/src/sage/modular/modform/ambient.py b/src/sage/modular/modform/ambient.py index bf67263db8c..95e414bcb37 100644 --- a/src/sage/modular/modform/ambient.py +++ b/src/sage/modular/modform/ambient.py @@ -20,27 +20,23 @@ Compute a basis:: sage: n.basis() - [ - 1 + O(q^6), - q + O(q^6), - q^2 + O(q^6), - q^3 + O(q^6), - q^4 + O(q^6), - q^5 + O(q^6) - ] + [1 + O(q^6), + q + O(q^6), + q^2 + O(q^6), + q^3 + O(q^6), + q^4 + O(q^6), + q^5 + O(q^6)] Compute the same basis but to higher precision:: sage: n.set_precision(20) sage: n.basis() - [ - 1 + 10*q^10 + 20*q^15 + O(q^20), - q + 5*q^6 + q^9 + 12*q^11 - 3*q^14 + 17*q^16 + 8*q^19 + O(q^20), - q^2 + 4*q^7 - q^8 + 8*q^12 + 2*q^13 + 10*q^17 - 5*q^18 + O(q^20), - q^3 + q^7 + 3*q^8 - q^12 + 5*q^13 + 3*q^17 + 6*q^18 + O(q^20), - q^4 - q^6 + 2*q^9 + 3*q^14 - 2*q^16 + 4*q^19 + O(q^20), - q^5 + q^10 + 2*q^15 + O(q^20) - ] + [1 + 10*q^10 + 20*q^15 + O(q^20), + q + 5*q^6 + q^9 + 12*q^11 - 3*q^14 + 17*q^16 + 8*q^19 + O(q^20), + q^2 + 4*q^7 - q^8 + 8*q^12 + 2*q^13 + 10*q^17 - 5*q^18 + O(q^20), + q^3 + q^7 + 3*q^8 - q^12 + 5*q^13 + 3*q^17 + 6*q^18 + O(q^20), + q^4 - q^6 + 2*q^9 + 3*q^14 - 2*q^16 + 4*q^19 + O(q^20), + q^5 + q^10 + 2*q^15 + O(q^20)] TESTS:: @@ -165,11 +161,9 @@ def change_ring(self, base_ring): sage: M = ModularForms(Gamma0(37),2) sage: M.basis() - [ - q + q^3 - 2*q^4 + O(q^6), - q^2 + 2*q^3 - 2*q^4 + q^5 + O(q^6), - 1 + 2/3*q + 2*q^2 + 8/3*q^3 + 14/3*q^4 + 4*q^5 + O(q^6) - ] + [q + q^3 - 2*q^4 + O(q^6), + q^2 + 2*q^3 - 2*q^4 + q^5 + O(q^6), + 1 + 2/3*q + 2*q^2 + 8/3*q^3 + 14/3*q^4 + 4*q^5 + O(q^6)] The basis after changing the base ring is the reduction modulo `3` of an integral basis. @@ -178,11 +172,9 @@ def change_ring(self, base_ring): sage: M3 = M.change_ring(GF(3)) sage: M3.basis() - [ - q + q^3 + q^4 + O(q^6), - q^2 + 2*q^3 + q^4 + q^5 + O(q^6), - 1 + q^3 + q^4 + 2*q^5 + O(q^6) - ] + [q + q^3 + q^4 + O(q^6), + q^2 + 2*q^3 + q^4 + q^5 + O(q^6), + 1 + q^3 + q^4 + 2*q^5 + O(q^6)] """ from . import constructor M = constructor.ModularForms(self.group(), self.weight(), base_ring, prec=self.prec(), eis_only=self._eis_only) @@ -376,20 +368,15 @@ def prec(self, new_prec=None): :: sage: M.basis() - [ - q - 24*q^2 + O(q^3), - 1 + 65520/691*q + 134250480/691*q^2 + O(q^3) - ] + [q - 24*q^2 + O(q^3), 1 + 65520/691*q + 134250480/691*q^2 + O(q^3)] :: sage: M.prec(5) 5 sage: M.basis() - [ - q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5), - 1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + O(q^5) - ] + [q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5), + 1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + O(q^5)] """ if new_prec: self.__prec = new_prec @@ -408,18 +395,14 @@ def set_precision(self, n): sage: m = ModularForms(Gamma1(5),2) sage: m.set_precision(10) sage: m.basis() - [ - 1 + 60*q^3 - 120*q^4 + 240*q^5 - 300*q^6 + 300*q^7 - 180*q^9 + O(q^10), - q + 6*q^3 - 9*q^4 + 27*q^5 - 28*q^6 + 30*q^7 - 11*q^9 + O(q^10), - q^2 - 4*q^3 + 12*q^4 - 22*q^5 + 30*q^6 - 24*q^7 + 5*q^8 + 18*q^9 + O(q^10) - ] + [1 + 60*q^3 - 120*q^4 + 240*q^5 - 300*q^6 + 300*q^7 - 180*q^9 + O(q^10), + q + 6*q^3 - 9*q^4 + 27*q^5 - 28*q^6 + 30*q^7 - 11*q^9 + O(q^10), + q^2 - 4*q^3 + 12*q^4 - 22*q^5 + 30*q^6 - 24*q^7 + 5*q^8 + 18*q^9 + O(q^10)] sage: m.set_precision(5) sage: m.basis() - [ - 1 + 60*q^3 - 120*q^4 + O(q^5), - q + 6*q^3 - 9*q^4 + O(q^5), - q^2 - 4*q^3 + 12*q^4 + O(q^5) - ] + [1 + 60*q^3 - 120*q^4 + O(q^5), + q + 6*q^3 - 9*q^4 + O(q^5), + q^2 - 4*q^3 + 12*q^4 + O(q^5)] """ if n < 0: raise ValueError("n (=%s) must be >= 0" % n) @@ -480,12 +463,10 @@ def new_submodule(self, p=None): sage: N = M.new_subspace(); N Modular Forms subspace of dimension 4 of Modular Forms space of dimension 6 for Congruence Subgroup Gamma0(17) of weight 4 over Rational Field sage: N.basis() - [ - q + 2*q^5 + O(q^6), - q^2 - 3/2*q^5 + O(q^6), - q^3 + O(q^6), - q^4 - 1/2*q^5 + O(q^6) - ] + [q + 2*q^5 + O(q^6), + q^2 - 3/2*q^5 + O(q^6), + q^3 + O(q^6), + q^4 - 1/2*q^5 + O(q^6)] :: @@ -529,11 +510,9 @@ def _q_expansion(self, element, prec): sage: m = ModularForms(Gamma0(23),2); m Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(23) of weight 2 over Rational Field sage: m.basis() - [ - q - q^3 - q^4 + O(q^6), - q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6), - 1 + 12/11*q + 36/11*q^2 + 48/11*q^3 + 84/11*q^4 + 72/11*q^5 + O(q^6) - ] + [q - q^3 - q^4 + O(q^6), + q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6), + 1 + 12/11*q + 36/11*q^2 + 48/11*q^3 + 84/11*q^4 + 72/11*q^5 + O(q^6)] sage: m._q_expansion([1,2,0], 5) q + 2*q^2 - 5*q^3 - 3*q^4 + O(q^5) """ @@ -699,32 +678,26 @@ def eisenstein_series(self): :: sage: ModularForms(27,2).eisenstein_series() - [ - q^3 + O(q^6), - q - 3*q^2 + 7*q^4 - 6*q^5 + O(q^6), - 1/12 + q + 3*q^2 + q^3 + 7*q^4 + 6*q^5 + O(q^6), - 1/3 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6), - 13/12 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6) - ] + [q^3 + O(q^6), + q - 3*q^2 + 7*q^4 - 6*q^5 + O(q^6), + 1/12 + q + 3*q^2 + q^3 + 7*q^4 + 6*q^5 + O(q^6), + 1/3 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6), + 13/12 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6)] :: sage: ModularForms(Gamma1(5),3).eisenstein_series() - [ - -1/5*zeta4 - 2/5 + q + (4*zeta4 + 1)*q^2 + (-9*zeta4 + 1)*q^3 + (4*zeta4 - 15)*q^4 + q^5 + O(q^6), - q + (zeta4 + 4)*q^2 + (-zeta4 + 9)*q^3 + (4*zeta4 + 15)*q^4 + 25*q^5 + O(q^6), - 1/5*zeta4 - 2/5 + q + (-4*zeta4 + 1)*q^2 + (9*zeta4 + 1)*q^3 + (-4*zeta4 - 15)*q^4 + q^5 + O(q^6), - q + (-zeta4 + 4)*q^2 + (zeta4 + 9)*q^3 + (-4*zeta4 + 15)*q^4 + 25*q^5 + O(q^6) - ] + [-1/5*zeta4 - 2/5 + q + (4*zeta4 + 1)*q^2 + (-9*zeta4 + 1)*q^3 + (4*zeta4 - 15)*q^4 + q^5 + O(q^6), + q + (zeta4 + 4)*q^2 + (-zeta4 + 9)*q^3 + (4*zeta4 + 15)*q^4 + 25*q^5 + O(q^6), + 1/5*zeta4 - 2/5 + q + (-4*zeta4 + 1)*q^2 + (9*zeta4 + 1)*q^3 + (-4*zeta4 - 15)*q^4 + q^5 + O(q^6), + q + (-zeta4 + 4)*q^2 + (zeta4 + 9)*q^3 + (-4*zeta4 + 15)*q^4 + 25*q^5 + O(q^6)] :: sage: eps = DirichletGroup(13).0^2 sage: ModularForms(eps,2).eisenstein_series() - [ - -7/13*zeta6 - 11/13 + q + (2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + (6*zeta6 - 3)*q^4 - 4*q^5 + O(q^6), - q + (zeta6 + 2)*q^2 + (-zeta6 + 3)*q^3 + (3*zeta6 + 3)*q^4 + 4*q^5 + O(q^6) - ] + [-7/13*zeta6 - 11/13 + q + (2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + (6*zeta6 - 3)*q^4 - 4*q^5 + O(q^6), + q + (zeta6 + 2)*q^2 + (-zeta6 + 3)*q^3 + (3*zeta6 + 3)*q^4 + 4*q^5 + O(q^6)] """ return self.eisenstein_submodule().eisenstein_series() diff --git a/src/sage/modular/modform/ambient_eps.py b/src/sage/modular/modform/ambient_eps.py index ddd4ed467bc..6d6d8a1c575 100644 --- a/src/sage/modular/modform/ambient_eps.py +++ b/src/sage/modular/modform/ambient_eps.py @@ -288,3 +288,18 @@ def hecke_module_of_level(self, N): return constructor.ModularForms(self.character().restrict(N), self.weight(), self.base_ring(), prec=self.prec()) else: raise ValueError("N (=%s) must be a divisor or a multiple of the level of self (=%s)" % (N, self.level())) + + def _pari_init_(self): + """ + Conversion to Pari. + + EXAMPLES:: + + sage: m = ModularForms(DirichletGroup(17).0^2, 2) + sage: pari.mfdim(m) + 3 + sage: pari.mfparams(m) + [17, 2, Mod(9, 17), 4, t^4 + 1] + """ + from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight(), self.character()], 4) diff --git a/src/sage/modular/modform/ambient_g1.py b/src/sage/modular/modform/ambient_g1.py index 31db01bd081..043823c0238 100644 --- a/src/sage/modular/modform/ambient_g1.py +++ b/src/sage/modular/modform/ambient_g1.py @@ -8,18 +8,13 @@ sage: S = M.cuspidal_submodule(); S Cuspidal subspace of dimension 2 of Modular Forms space of dimension 13 for Congruence Subgroup Gamma1(13) of weight 2 over Rational Field sage: S.basis() - [ - q - 4*q^3 - q^4 + 3*q^5 + O(q^6), - q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6) - ] + [q - 4*q^3 - q^4 + 3*q^5 + O(q^6), q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6)] sage: M = ModularForms(GammaH(11, [3])); M Modular Forms space of dimension 2 for Congruence Subgroup Gamma_H(11) with H generated by [3] of weight 2 over Rational Field sage: M.q_expansion_basis(8) - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 + O(q^8), - 1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + 144/5*q^6 + 96/5*q^7 + O(q^8) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 + O(q^8), + 1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + 144/5*q^6 + 96/5*q^7 + O(q^8)] TESTS:: diff --git a/src/sage/modular/modform/constructor.py b/src/sage/modular/modform/constructor.py index 425015535c6..5877288f896 100644 --- a/src/sage/modular/modform/constructor.py +++ b/src/sage/modular/modform/constructor.py @@ -9,14 +9,12 @@ Modular Forms space of dimension 6 for Congruence Subgroup Gamma1(4) of weight 11 over Rational Field sage: m.basis() - [ - q - 134*q^5 + O(q^6), - q^2 + 80*q^5 + O(q^6), - q^3 + 16*q^5 + O(q^6), - q^4 - 4*q^5 + O(q^6), - 1 + 4092/50521*q^2 + 472384/50521*q^3 + 4194300/50521*q^4 + O(q^6), - q + 1024*q^2 + 59048*q^3 + 1048576*q^4 + 9765626*q^5 + O(q^6) - ] + [q - 134*q^5 + O(q^6), + q^2 + 80*q^5 + O(q^6), + q^3 + 16*q^5 + O(q^6), + q^4 - 4*q^5 + O(q^6), + 1 + 4092/50521*q^2 + 472384/50521*q^3 + 4194300/50521*q^4 + O(q^6), + q + 1024*q^2 + 59048*q^3 + 1048576*q^4 + 9765626*q^5 + O(q^6)] """ # **************************************************************************** @@ -270,16 +268,13 @@ def ModularForms(group=1, Modular Forms space of dimension 5 for Congruence Subgroup Gamma1(11) of weight 1 over Rational Field sage: M.basis() - [ - 1 + 22*q^5 + O(q^6), - q + 4*q^5 + O(q^6), - q^2 - 4*q^5 + O(q^6), - q^3 - 5*q^5 + O(q^6), - q^4 - 3*q^5 + O(q^6) - ] + [1 + 22*q^5 + O(q^6), + q + 4*q^5 + O(q^6), + q^2 - 4*q^5 + O(q^6), + q^3 - 5*q^5 + O(q^6), + q^4 - 3*q^5 + O(q^6)] sage: M.cuspidal_subspace().basis() - [ - ] + [] sage: M == M.eisenstein_subspace() True @@ -290,10 +285,7 @@ def ModularForms(group=1, Modular Forms space of dimension 38 for Congruence Subgroup Gamma1(57) of weight 1 over Rational Field sage: M.cuspidal_submodule().basis() # long time - [ - q - q^4 + O(q^6), - q^3 - q^4 + O(q^6) - ] + [q - q^4 + O(q^6), q^3 - q^4 + O(q^6)] The Eisenstein subspace in weight 1 can be computed quickly, without triggering the expensive computation of the cuspidal part:: diff --git a/src/sage/modular/modform/cuspidal_submodule.py b/src/sage/modular/modform/cuspidal_submodule.py index 5de0805b386..3be7a3c61c0 100644 --- a/src/sage/modular/modform/cuspidal_submodule.py +++ b/src/sage/modular/modform/cuspidal_submodule.py @@ -8,27 +8,19 @@ Cuspidal subspace of dimension 1 of Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field sage: S.basis() - [ - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) - ] + [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)] sage: S = CuspForms(Gamma0(33),2); S Cuspidal subspace of dimension 3 of Modular Forms space of dimension 6 for Congruence Subgroup Gamma0(33) of weight 2 over Rational Field sage: S.basis() - [ - q - q^5 + O(q^6), - q^2 - q^4 - q^5 + O(q^6), - q^3 + O(q^6) - ] + [q - q^5 + O(q^6), q^2 - q^4 - q^5 + O(q^6), q^3 + O(q^6)] sage: S = CuspForms(Gamma1(3),6); S Cuspidal subspace of dimension 1 of Modular Forms space of dimension 3 for Congruence Subgroup Gamma1(3) of weight 6 over Rational Field sage: S.basis() - [ - q - 6*q^2 + 9*q^3 + 4*q^4 + 6*q^5 + O(q^6) - ] + [q - 6*q^2 + 9*q^3 + 4*q^4 + 6*q^5 + O(q^6)] """ ######################################################################### @@ -67,27 +59,19 @@ def __init__(self, ambient_space): Cuspidal subspace of dimension 1 of Modular Forms space of dimension 2 for Modular Group SL(2,Z) of weight 12 over Rational Field sage: S.basis() - [ - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) - ] + [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)] sage: S = CuspForms(Gamma0(33),2); S Cuspidal subspace of dimension 3 of Modular Forms space of dimension 6 for Congruence Subgroup Gamma0(33) of weight 2 over Rational Field sage: S.basis() - [ - q - q^5 + O(q^6), - q^2 - q^4 - q^5 + O(q^6), - q^3 + O(q^6) - ] + [q - q^5 + O(q^6), q^2 - q^4 - q^5 + O(q^6), q^3 + O(q^6)] sage: S = CuspForms(Gamma1(3),6); S Cuspidal subspace of dimension 1 of Modular Forms space of dimension 3 for Congruence Subgroup Gamma1(3) of weight 6 over Rational Field sage: S.basis() - [ - q - 6*q^2 + 9*q^3 + 4*q^4 + 6*q^5 + O(q^6) - ] + [q - 6*q^2 + 9*q^3 + 4*q^4 + 6*q^5 + O(q^6)] sage: S == loads(dumps(S)) True """ @@ -223,10 +207,7 @@ def _compute_q_expansion_basis(self, prec): sage: # needs sage.rings.number_field sage: CuspForms(Gamma1(13), 2, base_ring=QuadraticField(-7, 'a')).q_expansion_basis() # indirect doctest - [ - q - 4*q^3 - q^4 + 3*q^5 + O(q^6), - q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6) - ] + [q - 4*q^3 - q^4 + 3*q^5 + O(q^6), q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6)] """ return ModularFormsSubmodule._compute_q_expansion_basis(self, prec) @@ -242,9 +223,7 @@ def _compute_q_expansion_basis(self, prec=None): EXAMPLES:: sage: sage.modular.modform.cuspidal_submodule.CuspidalSubmodule_modsym_qexp(ModularForms(11,2))._compute_q_expansion_basis() - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)] """ if prec is None: prec = self.prec() @@ -327,9 +306,7 @@ def _compute_q_expansion_basis(self, prec=None): EXAMPLES:: sage: sage.modular.modform.cuspidal_submodule.CuspidalSubmodule_level1_Q(ModularForms(1,12))._compute_q_expansion_basis() - [ - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) - ] + [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)] """ if prec is None: prec = self.prec() @@ -365,9 +342,7 @@ def _compute_q_expansion_basis(self, prec=None): EXAMPLES:: sage: CuspForms(DirichletGroup(23, QQ).0, 1).q_echelon_basis() # indirect doctest - [ - q - q^2 - q^3 + O(q^6) - ] + [q - q^2 - q^3 + O(q^6)] """ if prec is None: prec = self.prec() @@ -377,6 +352,21 @@ def _compute_q_expansion_basis(self, prec=None): return [weight1.modular_ratio_to_prec(chi, f, prec) for f in weight1.hecke_stable_subspace(chi)] + def _pari_init_(self): + """ + Conversion to Pari. + + EXAMPLES:: + + sage: A = CuspForms(DirichletGroup(23, QQ).0, 1) + sage: pari.mfparams(A) + [23, 1, -23, 1, t + 1] + sage: pari.mfdim(A) + 1 + """ + from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight(), self.character()], 1) + class CuspidalSubmodule_wt1_gH(CuspidalSubmodule): r""" @@ -390,20 +380,13 @@ def _compute_q_expansion_basis(self, prec=None): EXAMPLES:: sage: CuspForms(GammaH(31, [7]), 1).q_expansion_basis() # indirect doctest - [ - q - q^2 - q^5 + O(q^6) - ] + [q - q^2 - q^5 + O(q^6)] A more elaborate example (two Galois-conjugate characters each giving a 2-dimensional space):: sage: CuspForms(GammaH(124, [85]), 1).q_expansion_basis() # long time - [ - q - q^4 - q^6 + O(q^7), - q^2 + O(q^7), - q^3 + O(q^7), - q^5 - q^6 + O(q^7) - ] + [q - q^4 - q^6 + O(q^7), q^2 + O(q^7), q^3 + O(q^7), q^5 - q^6 + O(q^7)] """ if prec is None: prec = self.prec() @@ -646,9 +629,7 @@ class CuspidalSubmodule_eps(CuspidalSubmodule_modsym_qexp): character [zeta4] and weight 5 over Cyclotomic Field of order 4 and degree 2 sage: S.basis() - [ - q + (-zeta4 - 1)*q^2 + (6*zeta4 - 6)*q^3 - 14*zeta4*q^4 + (15*zeta4 + 20)*q^5 + O(q^6) - ] + [q + (-zeta4 - 1)*q^2 + (6*zeta4 - 6)*q^3 - 14*zeta4*q^4 + (15*zeta4 + 20)*q^5 + O(q^6)] sage: f = S.0 sage: f.qexp() q + (-zeta4 - 1)*q^2 + (6*zeta4 - 6)*q^3 - 14*zeta4*q^4 + (15*zeta4 + 20)*q^5 + O(q^6) diff --git a/src/sage/modular/modform/eisenstein_submodule.py b/src/sage/modular/modform/eisenstein_submodule.py index fbbe2e06da3..278985d884d 100644 --- a/src/sage/modular/modform/eisenstein_submodule.py +++ b/src/sage/modular/modform/eisenstein_submodule.py @@ -178,11 +178,7 @@ def new_submodule(self, p=None): Modular Forms subspace of dimension 3 of Modular Forms space of dimension 42 for Congruence Subgroup Gamma0(225) of weight 2 over Rational Field sage: e.basis() - [ - q + O(q^6), - q^2 + O(q^6), - q^4 + O(q^6) - ] + [q + O(q^6), q^2 + O(q^6), q^4 + O(q^6)] """ if p is not None: @@ -210,24 +206,12 @@ def change_ring(self, base_ring): Eisenstein subspace of dimension 5 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(12) of weight 2 over Rational Field sage: E.basis() - [ - 1 + O(q^6), - q + 6*q^5 + O(q^6), - q^2 + O(q^6), - q^3 + O(q^6), - q^4 + O(q^6) - ] + [1 + O(q^6), q + 6*q^5 + O(q^6), q^2 + O(q^6), q^3 + O(q^6), q^4 + O(q^6)] sage: E.change_ring(GF(5)) Eisenstein subspace of dimension 5 of Modular Forms space of dimension 5 for Congruence Subgroup Gamma0(12) of weight 2 over Finite Field of size 5 sage: E.change_ring(GF(5)).basis() - [ - 1 + O(q^6), - q + q^5 + O(q^6), - q^2 + O(q^6), - q^3 + O(q^6), - q^4 + O(q^6) - ] + [1 + O(q^6), q + q^5 + O(q^6), q^2 + O(q^6), q^3 + O(q^6), q^4 + O(q^6)] """ if base_ring == self.base_ring(): return self @@ -243,71 +227,48 @@ def eisenstein_series(self): EXAMPLES:: sage: EisensteinForms(11,2).eisenstein_series() - [ - 5/12 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6) - ] + [5/12 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6)] sage: EisensteinForms(1,4).eisenstein_series() - [ - 1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6) - ] + [1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6)] sage: EisensteinForms(1,24).eisenstein_series() - [ - 236364091/131040 + q + 8388609*q^2 + 94143178828*q^3 - + 70368752566273*q^4 + 11920928955078126*q^5 + O(q^6) - ] + [236364091/131040 + q + 8388609*q^2 + 94143178828*q^3 + 70368752566273*q^4 + 11920928955078126*q^5 + O(q^6)] sage: EisensteinForms(5,4).eisenstein_series() - [ - 1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6), - 1/240 + q^5 + O(q^6) - ] + [1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6), 1/240 + q^5 + O(q^6)] sage: EisensteinForms(13,2).eisenstein_series() - [ - 1/2 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6) - ] + [1/2 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6)] sage: E = EisensteinForms(Gamma1(7),2) sage: E.set_precision(4) sage: E.eisenstein_series() - [ - 1/4 + q + 3*q^2 + 4*q^3 + O(q^4), - 1/7*zeta6 - 3/7 + q + (-2*zeta6 + 1)*q^2 + (3*zeta6 - 2)*q^3 + O(q^4), - q + (-zeta6 + 2)*q^2 + (zeta6 + 2)*q^3 + O(q^4), - -1/7*zeta6 - 2/7 + q + (2*zeta6 - 1)*q^2 + (-3*zeta6 + 1)*q^3 + O(q^4), - q + (zeta6 + 1)*q^2 + (-zeta6 + 3)*q^3 + O(q^4) - ] + [1/4 + q + 3*q^2 + 4*q^3 + O(q^4), + 1/7*zeta6 - 3/7 + q + (-2*zeta6 + 1)*q^2 + (3*zeta6 - 2)*q^3 + O(q^4), + q + (-zeta6 + 2)*q^2 + (zeta6 + 2)*q^3 + O(q^4), + -1/7*zeta6 - 2/7 + q + (2*zeta6 - 1)*q^2 + (-3*zeta6 + 1)*q^3 + O(q^4), + q + (zeta6 + 1)*q^2 + (-zeta6 + 3)*q^3 + O(q^4)] sage: eps = DirichletGroup(13).0^2 sage: ModularForms(eps,2).eisenstein_series() - [ - -7/13*zeta6 - 11/13 + q + (2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 - + (6*zeta6 - 3)*q^4 - 4*q^5 + O(q^6), - q + (zeta6 + 2)*q^2 + (-zeta6 + 3)*q^3 + (3*zeta6 + 3)*q^4 + 4*q^5 + O(q^6) - ] + [-7/13*zeta6 - 11/13 + q + (2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + (6*zeta6 - 3)*q^4 - 4*q^5 + O(q^6), + q + (zeta6 + 2)*q^2 + (-zeta6 + 3)*q^3 + (3*zeta6 + 3)*q^4 + 4*q^5 + O(q^6)] sage: M = ModularForms(19,3).eisenstein_subspace() sage: M.eisenstein_series() - [ - ] + [] sage: M = ModularForms(DirichletGroup(13).0, 1) sage: M.eisenstein_series() - [ - -1/13*zeta12^3 + 6/13*zeta12^2 + 4/13*zeta12 + 2/13 + q + (zeta12 + 1)*q^2 - + zeta12^2*q^3 + (zeta12^2 + zeta12 + 1)*q^4 + (-zeta12^3 + 1)*q^5 + O(q^6) - ] + [-1/13*zeta12^3 + 6/13*zeta12^2 + 4/13*zeta12 + 2/13 + q + (zeta12 + 1)*q^2 + zeta12^2*q^3 + (zeta12^2 + zeta12 + 1)*q^4 + (-zeta12^3 + 1)*q^5 + O(q^6)] sage: M = ModularForms(GammaH(15, [4]), 4) sage: M.eisenstein_series() - [ - 1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6), - 1/240 + q^3 + O(q^6), - 1/240 + q^5 + O(q^6), - 1/240 + O(q^6), - 1 + q - 7*q^2 - 26*q^3 + 57*q^4 + q^5 + O(q^6), - 1 + q^3 + O(q^6), - q + 7*q^2 + 26*q^3 + 57*q^4 + 125*q^5 + O(q^6), - q^3 + O(q^6) - ] + [1/240 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6), + 1/240 + q^3 + O(q^6), + 1/240 + q^5 + O(q^6), + 1/240 + O(q^6), + 1 + q - 7*q^2 - 26*q^3 + 57*q^4 + q^5 + O(q^6), + 1 + q^3 + O(q^6), + q + 7*q^2 + 26*q^3 + 57*q^4 + 125*q^5 + O(q^6), + q^3 + O(q^6)] """ P = self.parameters() E = Sequence([element.EisensteinSeries(self.change_ring(chi.base_ring()), @@ -562,30 +523,41 @@ class EisensteinSubmodule_eps(EisensteinSubmodule_params): 6 sage: M.eisenstein_series() - [ - -1/3*zeta6 - 1/3 + q + (2*zeta6 - 1)*q^2 + q^3 - + (-2*zeta6 - 1)*q^4 + (-5*zeta6 + 1)*q^5 + O(q^6), - -1/3*zeta6 - 1/3 + q^3 + O(q^6), - q + (-2*zeta6 + 1)*q^2 + (-2*zeta6 - 1)*q^4 + (5*zeta6 - 1)*q^5 + O(q^6), - q + (zeta6 + 1)*q^2 + 3*q^3 + (zeta6 + 2)*q^4 + (-zeta6 + 5)*q^5 + O(q^6), - q^3 + O(q^6), - q + (-zeta6 - 1)*q^2 + (zeta6 + 2)*q^4 + (zeta6 - 5)*q^5 + O(q^6) - ] + [-1/3*zeta6 - 1/3 + q + (2*zeta6 - 1)*q^2 + q^3 + (-2*zeta6 - 1)*q^4 + (-5*zeta6 + 1)*q^5 + O(q^6), + -1/3*zeta6 - 1/3 + q^3 + O(q^6), + q + (-2*zeta6 + 1)*q^2 + (-2*zeta6 - 1)*q^4 + (5*zeta6 - 1)*q^5 + O(q^6), + q + (zeta6 + 1)*q^2 + 3*q^3 + (zeta6 + 2)*q^4 + (-zeta6 + 5)*q^5 + O(q^6), + q^3 + O(q^6), + q + (-zeta6 - 1)*q^2 + (zeta6 + 2)*q^4 + (zeta6 - 5)*q^5 + O(q^6)] sage: M.eisenstein_subspace().T(2).matrix().fcp() (x + 2*zeta3 + 1) * (x + zeta3 + 2) * (x - zeta3 - 2)^2 * (x - 2*zeta3 - 1)^2 sage: ModularSymbols(e,2).eisenstein_subspace().T(2).matrix().fcp() (x + 2*zeta3 + 1) * (x + zeta3 + 2) * (x - zeta3 - 2)^2 * (x - 2*zeta3 - 1)^2 sage: M.basis() - [ - 1 - 3*zeta3*q^6 + (-2*zeta3 + 2)*q^9 + O(q^10), - q + (5*zeta3 + 5)*q^7 + O(q^10), - q^2 - 2*zeta3*q^8 + O(q^10), - q^3 + (zeta3 + 2)*q^6 + 3*q^9 + O(q^10), - q^4 - 2*zeta3*q^7 + O(q^10), - q^5 + (zeta3 + 1)*q^8 + O(q^10) - ] + [1 - 3*zeta3*q^6 + (-2*zeta3 + 2)*q^9 + O(q^10), + q + (5*zeta3 + 5)*q^7 + O(q^10), + q^2 - 2*zeta3*q^8 + O(q^10), + q^3 + (zeta3 + 2)*q^6 + 3*q^9 + O(q^10), + q^4 - 2*zeta3*q^7 + O(q^10), + q^5 + (zeta3 + 1)*q^8 + O(q^10)] """ + def _pari_init_(self): + """ + Conversion to Pari. + + EXAMPLES:: + + sage: e = DirichletGroup(27,CyclotomicField(3)).0**2 + sage: M = ModularForms(e,2,prec=10).eisenstein_subspace() + sage: pari.mfdim(M) + 6 + sage: pari.mfparams(M) + [27, 2, Mod(10, 27), 3, t^2 + t + 1] + """ + from sage.libs.pari import pari + return pari.mfinit([self.level(), self.weight(), self.character()], 3) + # TODO # def _compute_q_expansion_basis(self, prec): # B = EisensteinSubmodule_params._compute_q_expansion_basis(self, prec) diff --git a/src/sage/modular/modform/element.py b/src/sage/modular/modform/element.py index 6ce83f0372e..3fdabbfed7b 100644 --- a/src/sage/modular/modform/element.py +++ b/src/sage/modular/modform/element.py @@ -219,6 +219,38 @@ def _repr_(self): """ return str(self.q_expansion()) + def _pari_init_(self): + """ + Conversion to Pari. + + TESTS:: + + sage: M = EisensteinForms(96, 2) + sage: M.6 + O(q^6) + sage: M.7 + O(q^6) + sage: pari(M.6) == pari(M.7) + False + sage: pari(M.6).mfcoefs(10) + [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0] + + sage: M = ModularForms(DirichletGroup(17).0^2, 2) + sage: pari(M.0).mfcoefs(5) + [0, 1, Mod(-t^3 + t^2 - 1, t^4 + 1), Mod(t^3 - t^2 - t - 1, t^4 + 1), Mod(2*t^3 - t^2 + 2*t, t^4 + 1), Mod(-t^3 - t^2, t^4 + 1)] + sage: M.0.qexp(5) + q + (-zeta8^3 + zeta8^2 - 1)*q^2 + (zeta8^3 - zeta8^2 - zeta8 - 1)*q^3 + (2*zeta8^3 - zeta8^2 + 2*zeta8)*q^4 + O(q^5) + """ + from sage.libs.pari import pari + from sage.rings.number_field.number_field_element import NumberFieldElement + M = pari(self.parent()) + f = self.qexp(self.parent().sturm_bound()) + coefficients = [ + x.__pari__('t') if isinstance(x, NumberFieldElement) else x + for x in f] + # we cannot compute pari(f) directly because we need to set the variable name as t + return M.mflinear(M.mftobasis(coefficients + [0] * (f.prec() - len(coefficients)))) + def __call__(self, x, prec=None): """ Evaluate the `q`-expansion of this modular form at x. @@ -233,9 +265,150 @@ def __call__(self, x, prec=None): sage: f(0) 0 - """ + + Evaluate numerically:: + + sage: f = ModularForms(1, 12).0 + sage: f(0.3) # rel tol 1e-12 + 2.34524576548591e-6 + sage: f = EisensteinForms(1, 4).0 + sage: f(0.9) # rel tol 1e-12 + 1.26475942209241e7 + + TESTS:: + + sage: f = ModularForms(96, 2).0 + sage: f(0.3) # rel tol 1e-12 + 0.299999997396191 + sage: f(0.0+0.0*I) + 0 + + For simplicity, ``float`` or ``complex`` input are converted to ``CC``, except for + input ``0`` where exact result is returned:: + + sage: result = f(0.3r); result # rel tol 1e-12 + 0.299999997396191 + sage: result.parent() + Complex Field with 53 bits of precision + sage: result = f(0.3r + 0.3jr); result # rel tol 1e-12 + 0.299999359878484 + 0.299999359878484*I + sage: result.parent() + Complex Field with 53 bits of precision + + Symbolic numerical values use precision of ``CC`` by default:: + + sage: f(sqrt(1/2)) # rel tol 1e-12 + 0.700041406692037 + sage: f(sqrt(1/2)*QQbar.zeta(8)) # rel tol 1e-12 + 0.496956554651376 + 0.496956554651376*I + + Higher precision:: + + sage: f(ComplexField(128)(0.3)) # rel tol 1e-36 + 0.29999999739619131029285166058750164058 + sage: f(ComplexField(128)(1+2*I)/3) # rel tol 1e-36 + 0.32165384572356882556790532669389900691 + 0.67061244638367586302820790711257777390*I + + Confirm numerical evaluation matches the q-expansion:: + + sage: f = EisensteinForms(1, 4).0 + sage: f(0.3) # rel tol 1e-12 + 741.741819297986 + sage: f.qexp(50).polynomial()(0.3) # rel tol 1e-12 + 741.741819297986 + + With a nontrivial character:: + + sage: M = ModularForms(DirichletGroup(17).0^2, 2) + sage: M.0(0.5) # rel tol 1e-12 + 0.166916655031616 + 0.0111529051752428*I + sage: M.0.qexp(60).polynomial()(0.5) # rel tol 1e-12 + 0.166916655031616 + 0.0111529051752428*I + + Higher precision:: + + sage: f(ComplexField(128)(1+2*I)/3) # rel tol 1e-36 + 429.19994832206294278688085399056359632 - 786.15736284188243351153830824852974995*I + sage: f.qexp(400).polynomial()(ComplexField(128)(1+2*I)/3) # rel tol 1e-36 + 429.19994832206294278688085399056359631 - 786.15736284188243351153830824852974999*I + + Check ``SR`` does not make the result lose precision:: + + sage: f(ComplexField(128)(1+2*I)/3 + x - x) # rel tol 1e-36 + 429.19994832206294278688085399056359632 - 786.15736284188243351153830824852974995*I + """ + from sage.rings.integer import Integer + from sage.misc.functional import log + from sage.structure.element import parent + from sage.rings.complex_mpfr import ComplexNumber + from sage.rings.cc import CC + from sage.rings.real_mpfr import RealNumber + from sage.symbolic.constants import pi + from sage.rings.imaginary_unit import I # import from here instead of sage.symbolic.constants to avoid cast to SR + from sage.symbolic.expression import Expression + if isinstance(x, Expression): + try: + x = x.pyobject() + except TypeError: + pass + if x in CC: + if x == 0: + return self.qexp(1)[0] + if not isinstance(x, (RealNumber, ComplexNumber)): + x = CC(x) # might lose precision if this is done unconditionally (TODO what about interval and ball types?) + if isinstance(x, (RealNumber, ComplexNumber)): + return self.eval_at_tau(log(x)/(2*parent(x)(pi)*I)) # cast to parent(x) to force numerical evaluation of pi return self.q_expansion(prec)(x) + def eval_at_tau(self, tau): + r""" + Evaluate this modular form at the half-period ratio `\tau`. + This is related to `q` by `q = e^{2\pi i \tau}`. + + EXAMPLES:: + + sage: f = ModularForms(1, 12).0 + sage: f.eval_at_tau(0.3 * I) # rel tol 1e-12 + 0.00150904633897550 + + TESTS: + + Symbolic numerical values use precision of ``CC`` by default:: + + sage: f.eval_at_tau(sqrt(1/5)*I) # rel tol 1e-12 + 0.0123633234207127 + sage: f.eval_at_tau(sqrt(1/2)*QQbar.zeta(8)) # rel tol 1e-12 + -0.114263670441098 + + For simplicity, ``complex`` input are converted to ``CC``:: + + sage: result = f.eval_at_tau(0.3jr); result # rel tol 1e-12 + 0.00150904633897550 + sage: result.parent() + Complex Field with 53 bits of precision + + Check ``SR`` does not make the result lose precision:: + + sage: f = EisensteinForms(1, 4).0 + sage: f.eval_at_tau(ComplexField(128)(1+2*I)/3 + x - x) # rel tol 1e-36 + -1.0451570582202060056197878314286036966 + 2.7225112098519803098203933583286590274*I + """ + from sage.libs.pari.convert_sage import gen_to_sage + from sage.libs.pari import pari + from sage.rings.cc import CC + from sage.rings.complex_mpfr import ComplexNumber, ComplexField + from sage.rings.real_mpfr import RealNumber + from sage.symbolic.expression import Expression + if isinstance(tau, Expression): + try: + tau = tau.pyobject() + except TypeError: + pass + if not isinstance(tau, (RealNumber, ComplexNumber)): + tau = CC(tau) + precision = tau.prec() + return ComplexField(precision)(pari.mfeval(self.parent(), self, tau, precision=precision)) + @cached_method def valuation(self): """ @@ -1712,10 +1885,8 @@ def _defining_modular_symbols(self): [Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 4 for Gamma_0(43) of weight 2 with sign 1 over Rational Field, Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 for Gamma_0(43) of weight 2 with sign 1 over Rational Field] sage: ModularSymbols(43,2,sign=1).cuspidal_subspace().new_subspace().decomposition() - [ - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 4 for Gamma_0(43) of weight 2 with sign 1 over Rational Field, - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 for Gamma_0(43) of weight 2 with sign 1 over Rational Field - ] + [Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 4 for Gamma_0(43) of weight 2 with sign 1 over Rational Field, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 for Gamma_0(43) of weight 2 with sign 1 over Rational Field] """ return self.__modsym_space @@ -2850,24 +3021,18 @@ class EisensteinSeries(ModularFormElement): sage: E = EisensteinForms(1,12) sage: E.eisenstein_series() - [ - 691/65520 + q + 2049*q^2 + 177148*q^3 + 4196353*q^4 + 48828126*q^5 + O(q^6) - ] + [691/65520 + q + 2049*q^2 + 177148*q^3 + 4196353*q^4 + 48828126*q^5 + O(q^6)] sage: E = EisensteinForms(11,2) sage: E.eisenstein_series() - [ - 5/12 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6) - ] + [5/12 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6)] sage: E = EisensteinForms(Gamma1(7),2) sage: E.set_precision(4) sage: E.eisenstein_series() - [ - 1/4 + q + 3*q^2 + 4*q^3 + O(q^4), - 1/7*zeta6 - 3/7 + q + (-2*zeta6 + 1)*q^2 + (3*zeta6 - 2)*q^3 + O(q^4), - q + (-zeta6 + 2)*q^2 + (zeta6 + 2)*q^3 + O(q^4), - -1/7*zeta6 - 2/7 + q + (2*zeta6 - 1)*q^2 + (-3*zeta6 + 1)*q^3 + O(q^4), - q + (zeta6 + 1)*q^2 + (-zeta6 + 3)*q^3 + O(q^4) - ] + [1/4 + q + 3*q^2 + 4*q^3 + O(q^4), + 1/7*zeta6 - 3/7 + q + (-2*zeta6 + 1)*q^2 + (3*zeta6 - 2)*q^3 + O(q^4), + q + (-zeta6 + 2)*q^2 + (zeta6 + 2)*q^3 + O(q^4), + -1/7*zeta6 - 2/7 + q + (2*zeta6 - 1)*q^2 + (-3*zeta6 + 1)*q^3 + O(q^4), + q + (zeta6 + 1)*q^2 + (-zeta6 + 3)*q^3 + O(q^4)] """ def __init__(self, parent, vector, t, chi, psi): """ @@ -2877,24 +3042,18 @@ def __init__(self, parent, vector, t, chi, psi): sage: E = EisensteinForms(1,12) # indirect doctest sage: E.eisenstein_series() - [ - 691/65520 + q + 2049*q^2 + 177148*q^3 + 4196353*q^4 + 48828126*q^5 + O(q^6) - ] + [691/65520 + q + 2049*q^2 + 177148*q^3 + 4196353*q^4 + 48828126*q^5 + O(q^6)] sage: E = EisensteinForms(11,2) sage: E.eisenstein_series() - [ - 5/12 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6) - ] + [5/12 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6)] sage: E = EisensteinForms(Gamma1(7),2) sage: E.set_precision(4) sage: E.eisenstein_series() - [ - 1/4 + q + 3*q^2 + 4*q^3 + O(q^4), - 1/7*zeta6 - 3/7 + q + (-2*zeta6 + 1)*q^2 + (3*zeta6 - 2)*q^3 + O(q^4), - q + (-zeta6 + 2)*q^2 + (zeta6 + 2)*q^3 + O(q^4), - -1/7*zeta6 - 2/7 + q + (2*zeta6 - 1)*q^2 + (-3*zeta6 + 1)*q^3 + O(q^4), - q + (zeta6 + 1)*q^2 + (-zeta6 + 3)*q^3 + O(q^4) - ] + [1/4 + q + 3*q^2 + 4*q^3 + O(q^4), + 1/7*zeta6 - 3/7 + q + (-2*zeta6 + 1)*q^2 + (3*zeta6 - 2)*q^3 + O(q^4), + q + (-zeta6 + 2)*q^2 + (zeta6 + 2)*q^3 + O(q^4), + -1/7*zeta6 - 2/7 + q + (2*zeta6 - 1)*q^2 + (-3*zeta6 + 1)*q^3 + O(q^4), + q + (zeta6 + 1)*q^2 + (-zeta6 + 3)*q^3 + O(q^4)] """ N = parent.level() K = parent.base_ring() @@ -3120,10 +3279,8 @@ def character(self): sage: chi = DirichletGroup(7)[4] sage: E = EisensteinForms(chi).eisenstein_series() ; E - [ - -1/7*zeta6 - 2/7 + q + (2*zeta6 - 1)*q^2 + (-3*zeta6 + 1)*q^3 + (-2*zeta6 - 1)*q^4 + (5*zeta6 - 4)*q^5 + O(q^6), - q + (zeta6 + 1)*q^2 + (-zeta6 + 3)*q^3 + (zeta6 + 2)*q^4 + (zeta6 + 4)*q^5 + O(q^6) - ] + [-1/7*zeta6 - 2/7 + q + (2*zeta6 - 1)*q^2 + (-3*zeta6 + 1)*q^3 + (-2*zeta6 - 1)*q^4 + (5*zeta6 - 4)*q^5 + O(q^6), + q + (zeta6 + 1)*q^2 + (-zeta6 + 3)*q^3 + (zeta6 + 2)*q^4 + (zeta6 + 4)*q^5 + O(q^6)] sage: E[0].character() == chi True sage: E[1].character() == chi diff --git a/src/sage/modular/modform/hecke_operator_on_qexp.py b/src/sage/modular/modform/hecke_operator_on_qexp.py index 5133c7612c9..6693efbdd3a 100644 --- a/src/sage/modular/modform/hecke_operator_on_qexp.py +++ b/src/sage/modular/modform/hecke_operator_on_qexp.py @@ -187,11 +187,8 @@ def hecke_operator_on_basis(B, n, k, eps=None, already_echelonized=False): sage: sage.modular.modform.constructor.ModularForms_clear_cache() sage: ModularForms(1,12).q_expansion_basis() - [ - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6), - 1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 - + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6) - ] + [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6), + 1 + 65520/691*q + 134250480/691*q^2 + 11606736960/691*q^3 + 274945048560/691*q^4 + 3199218815520/691*q^5 + O(q^6)] sage: hecke_operator_on_basis(ModularForms(1,12).q_expansion_basis(), 3, 12) Traceback (most recent call last): ... diff --git a/src/sage/modular/modform/meson.build b/src/sage/modular/modform/meson.build index 7276059448d..541227d9511 100644 --- a/src/sage/modular/modform/meson.build +++ b/src/sage/modular/modform/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'ambient.py', 'ambient_R.py', diff --git a/src/sage/modular/modform/numerical.py b/src/sage/modular/modform/numerical.py index dd14ff15995..403289b678b 100644 --- a/src/sage/modular/modform/numerical.py +++ b/src/sage/modular/modform/numerical.py @@ -76,17 +76,13 @@ class NumericalEigenforms(SageObject): sage: n.ap(2) # abs tol 1e-12 [3.0, -1.6180339887498947, 0.6180339887498968] sage: n.systems_of_eigenvalues(7) # abs tol 2e-12 - [ - [-1.6180339887498947, 2.2360679774997894, -3.2360679774997894], - [0.6180339887498968, -2.236067977499788, 1.2360679774997936], - [3.0, 4.0, 6.0] - ] + [[-1.6180339887498947, 2.23606797749979, -3.2360679774997894], + [0.618033988749895, -2.236067977499788, 1.23606797749979], + [3.0, 4.0, 6.0]] sage: n.systems_of_abs(7) # abs tol 2e-12 - [ - [0.6180339887498943, 2.2360679774997894, 1.2360679774997887], - [1.6180339887498947, 2.23606797749979, 3.2360679774997894], - [3.0, 4.0, 6.0] - ] + [[0.618033988749895, 2.236067977499788, 1.23606797749979], + [1.6180339887498947, 2.23606797749979, 3.2360679774997894], + [3.0, 4.0, 6.0]] sage: n.eigenvalues([2,3,5]) # rel tol 2e-12 [[3.0, -1.6180339887498947, 0.6180339887498968], [4.0, 2.2360679774997894, -2.236067977499788], @@ -443,13 +439,20 @@ def systems_of_eigenvalues(self, bound): EXAMPLES:: sage: numerical_eigenforms(61).systems_of_eigenvalues(10) # rel tol 1e-9 - [ - [-1.4811943040920152, 0.8060634335253695, 3.1563251746586642, 0.6751308705666477], - [-1.0, -2.0000000000000027, -3.000000000000003, 1.0000000000000044], - [0.3111078174659775, 2.903211925911551, -2.525427560843529, -3.214319743377552], - [2.170086486626034, -1.7092753594369208, -1.63089761381512, -0.46081112718908984], - [3.0, 4.0, 6.0, 8.0] - ] + [[-1.481194304092014, + 0.8060634335253706, + 3.156325174658664, + 0.6751308705666462], + [-1.0, -2.0, -3.0, 1.0], + [0.311107817465981, + 2.903211925911551, + -2.5254275608435184, + -3.214319743377534], + [2.1700864866260323, + -1.7092753594369237, + -1.6308976138151459, + -0.460811127189112], + [3.0, 4.0, 6.0, 8.0]] """ P = prime_range(bound) e = self.eigenvalues(P) @@ -470,13 +473,17 @@ def systems_of_abs(self, bound): EXAMPLES:: sage: numerical_eigenforms(61).systems_of_abs(10) # rel tol 1e-9 - [ - [0.3111078174659775, 2.903211925911551, 2.525427560843529, 3.214319743377552], - [1.0, 2.0000000000000027, 3.000000000000003, 1.0000000000000044], - [1.4811943040920152, 0.8060634335253695, 3.1563251746586642, 0.6751308705666477], - [2.170086486626034, 1.7092753594369208, 1.63089761381512, 0.46081112718908984], - [3.0, 4.0, 6.0, 8.0] - ] + [[0.311107817465981, 2.903211925911551, 2.5254275608435184, 3.214319743377534], + [1.0, 2.0, 3.0, 1.0], + [1.481194304092014, + 0.8060634335253706, + 3.156325174658664, + 0.6751308705666462], + [2.1700864866260323, + 1.7092753594369237, + 1.6308976138151459, + 0.460811127189112], + [3.0, 4.0, 6.0, 8.0]] """ P = prime_range(bound) e = self.eigenvalues(P) diff --git a/src/sage/modular/modform/ring.py b/src/sage/modular/modform/ring.py index dacfda54bae..dca6c86f125 100644 --- a/src/sage/modular/modform/ring.py +++ b/src/sage/modular/modform/ring.py @@ -89,11 +89,9 @@ def _span_of_forms_in_weight(forms, weight, prec, stop_dim=None, use_random=Fals [ 0 1 0 195660 12080128] [ 0 0 1 -48 1080] sage: ModularForms(1, 24).q_echelon_basis(prec=5) - [ - 1 + 52416000*q^3 + 39007332000*q^4 + O(q^5), - q + 195660*q^3 + 12080128*q^4 + O(q^5), - q^2 - 48*q^3 + 1080*q^4 + O(q^5) - ] + [1 + 52416000*q^3 + 39007332000*q^4 + O(q^5), + q + 195660*q^3 + 12080128*q^4 + O(q^5), + q^2 - 48*q^3 + 1080*q^4 + O(q^5)] Test the alternative randomized algorithm:: diff --git a/src/sage/modular/modform/space.py b/src/sage/modular/modform/space.py index 202ea687953..4405c38f764 100644 --- a/src/sage/modular/modform/space.py +++ b/src/sage/modular/modform/space.py @@ -174,15 +174,11 @@ def prec(self, new_prec=None): sage: S.prec() 6 sage: S.basis() - [ - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) - ] + [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)] sage: S.prec(8) 8 sage: S.basis() - [ - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8) - ] + [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8)] """ return self.ambient().prec(new_prec) @@ -201,19 +197,14 @@ def set_precision(self, new_prec): sage: M.set_precision(10) sage: S = M.cuspidal_subspace() sage: S.basis() - [ - q + q^3 - 2*q^4 - q^7 - 2*q^9 + O(q^10), - q^2 + 2*q^3 - 2*q^4 + q^5 - 3*q^6 - 4*q^9 + O(q^10) - ] + [q + q^3 - 2*q^4 - q^7 - 2*q^9 + O(q^10), + q^2 + 2*q^3 - 2*q^4 + q^5 - 3*q^6 - 4*q^9 + O(q^10)] :: sage: S.set_precision(0) sage: S.basis() - [ - O(q^0), - O(q^0) - ] + [O(q^0), O(q^0)] The precision of subspaces is the same as the precision of the ambient space. @@ -222,11 +213,7 @@ def set_precision(self, new_prec): sage: S.set_precision(2) sage: M.basis() - [ - q + O(q^2), - O(q^2), - 1 + 2/3*q + O(q^2) - ] + [q + O(q^2), O(q^2), 1 + 2/3*q + O(q^2)] The precision must be nonnegative:: @@ -427,35 +414,27 @@ def echelon_form(self): sage: M = ModularForms(11) sage: M.basis() - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6), - 1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6), + 1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6)] sage: M.echelon_form().basis() - [ - 1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6), - q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6) - ] + [1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6), + q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)] :: sage: M = ModularForms(Gamma1(6),4) sage: M.basis() - [ - q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6), - 1 + O(q^6), - q - 8*q^4 + 126*q^5 + O(q^6), - q^2 + 9*q^4 + O(q^6), - q^3 + O(q^6) - ] + [q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6), + 1 + O(q^6), + q - 8*q^4 + 126*q^5 + O(q^6), + q^2 + 9*q^4 + O(q^6), + q^3 + O(q^6)] sage: M.echelon_form().basis() - [ - 1 + O(q^6), - q + 94*q^5 + O(q^6), - q^2 + 36*q^5 + O(q^6), - q^3 + O(q^6), - q^4 - 4*q^5 + O(q^6) - ] + [1 + O(q^6), + q + 94*q^5 + O(q^6), + q^2 + 36*q^5 + O(q^6), + q^3 + O(q^6), + q^4 - 4*q^5 + O(q^6)] We create a space with a funny basis then compute the corresponding echelon form. @@ -464,22 +443,16 @@ def echelon_form(self): sage: M = ModularForms(11,4) sage: M.basis() - [ - q + 3*q^3 - 6*q^4 - 7*q^5 + O(q^6), - q^2 - 4*q^3 + 2*q^4 + 8*q^5 + O(q^6), - 1 + O(q^6), - q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6) - ] + [q + 3*q^3 - 6*q^4 - 7*q^5 + O(q^6), + q^2 - 4*q^3 + 2*q^4 + 8*q^5 + O(q^6), + 1 + O(q^6), + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6)] sage: F = M.span_of_basis([M.0 + 1/3*M.1, M.2 + M.3]); F.basis() - [ - q + 1/3*q^2 + 5/3*q^3 - 16/3*q^4 - 13/3*q^5 + O(q^6), - 1 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6) - ] + [q + 1/3*q^2 + 5/3*q^3 - 16/3*q^4 - 13/3*q^5 + O(q^6), + 1 + q + 9*q^2 + 28*q^3 + 73*q^4 + 126*q^5 + O(q^6)] sage: E = F.echelon_form(); E.basis() - [ - 1 + 26/3*q^2 + 79/3*q^3 + 235/3*q^4 + 391/3*q^5 + O(q^6), - q + 1/3*q^2 + 5/3*q^3 - 16/3*q^4 - 13/3*q^5 + O(q^6) - ] + [1 + 26/3*q^2 + 79/3*q^3 + 235/3*q^4 + 391/3*q^5 + O(q^6), + q + 1/3*q^2 + 5/3*q^3 - 16/3*q^4 - 13/3*q^5 + O(q^6)] """ return self.span_of_basis(self.echelon_basis()) @@ -495,37 +468,28 @@ def echelon_basis(self): sage: M = ModularForms(Gamma0(11),4) sage: M.echelon_basis() - [ - 1 + O(q^6), - q - 9*q^4 - 10*q^5 + O(q^6), - q^2 + 6*q^4 + 12*q^5 + O(q^6), - q^3 + q^4 + q^5 + O(q^6) - ] + [1 + O(q^6), + q - 9*q^4 - 10*q^5 + O(q^6), + q^2 + 6*q^4 + 12*q^5 + O(q^6), + q^3 + q^4 + q^5 + O(q^6)] sage: M.cuspidal_subspace().echelon_basis() - [ - q + 3*q^3 - 6*q^4 - 7*q^5 + O(q^6), - q^2 - 4*q^3 + 2*q^4 + 8*q^5 + O(q^6) - ] + [q + 3*q^3 - 6*q^4 - 7*q^5 + O(q^6), q^2 - 4*q^3 + 2*q^4 + 8*q^5 + O(q^6)] :: sage: M = ModularForms(SL2Z, 12) sage: M.echelon_basis() - [ - 1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6), - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) - ] + [1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6), + q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)] :: sage: M = CuspForms(Gamma0(17),4, prec=10) sage: M.echelon_basis() - [ - q + 2*q^5 - 8*q^7 - 8*q^8 + 7*q^9 + O(q^10), - q^2 - 3/2*q^5 - 7/2*q^6 + 9/2*q^7 + q^8 - 4*q^9 + O(q^10), - q^3 - 2*q^6 + q^7 - 4*q^8 - 2*q^9 + O(q^10), - q^4 - 1/2*q^5 - 5/2*q^6 + 3/2*q^7 + 2*q^9 + O(q^10) - ] + [q + 2*q^5 - 8*q^7 - 8*q^8 + 7*q^9 + O(q^10), + q^2 - 3/2*q^5 - 7/2*q^6 + 9/2*q^7 + q^8 - 4*q^9 + O(q^10), + q^3 - 2*q^6 + q^7 - 4*q^8 - 2*q^9 + O(q^10), + q^4 - 1/2*q^5 - 5/2*q^6 + 3/2*q^7 + 2*q^9 + O(q^10)] """ F = self.free_module() W = self._q_expansion_module() @@ -548,62 +512,52 @@ def integral_basis(self): sage: m = ModularForms(97,2,prec=10) sage: s = m.cuspidal_subspace() sage: s.integral_basis() - [ - q + 2*q^7 + 4*q^8 - 2*q^9 + O(q^10), - q^2 + q^4 + q^7 + 3*q^8 - 3*q^9 + O(q^10), - q^3 + q^4 - 3*q^8 + q^9 + O(q^10), - 2*q^4 - 2*q^8 + O(q^10), - q^5 - 2*q^8 + 2*q^9 + O(q^10), - q^6 + 2*q^7 + 5*q^8 - 5*q^9 + O(q^10), - 3*q^7 + 6*q^8 - 4*q^9 + O(q^10) - ] + [q + 2*q^7 + 4*q^8 - 2*q^9 + O(q^10), + q^2 + q^4 + q^7 + 3*q^8 - 3*q^9 + O(q^10), + q^3 + q^4 - 3*q^8 + q^9 + O(q^10), + 2*q^4 - 2*q^8 + O(q^10), + q^5 - 2*q^8 + 2*q^9 + O(q^10), + q^6 + 2*q^7 + 5*q^8 - 5*q^9 + O(q^10), + 3*q^7 + 6*q^8 - 4*q^9 + O(q^10)] sage: s.echelon_basis() - [ - q + 2/3*q^9 + O(q^10), - q^2 + 2*q^8 - 5/3*q^9 + O(q^10), - q^3 - 2*q^8 + q^9 + O(q^10), - q^4 - q^8 + O(q^10), - q^5 - 2*q^8 + 2*q^9 + O(q^10), - q^6 + q^8 - 7/3*q^9 + O(q^10), - q^7 + 2*q^8 - 4/3*q^9 + O(q^10) - ] + [q + 2/3*q^9 + O(q^10), + q^2 + 2*q^8 - 5/3*q^9 + O(q^10), + q^3 - 2*q^8 + q^9 + O(q^10), + q^4 - q^8 + O(q^10), + q^5 - 2*q^8 + 2*q^9 + O(q^10), + q^6 + q^8 - 7/3*q^9 + O(q^10), + q^7 + 2*q^8 - 4/3*q^9 + O(q^10)] Here's another example where there is a big gap in the valuations:: sage: m = CuspForms(64,2) sage: m.integral_basis() - [ - q + O(q^6), - q^2 + O(q^6), - q^5 + O(q^6) - ] + [q + O(q^6), q^2 + O(q^6), q^5 + O(q^6)] TESTS:: sage: m = CuspForms(11*2^4,2, prec=13); m Cuspidal subspace of dimension 19 of Modular Forms space of dimension 30 for Congruence Subgroup Gamma0(176) of weight 2 over Rational Field sage: m.integral_basis() # takes a long time (3 or 4 seconds) - [ - q + O(q^13), - q^2 + O(q^13), - q^3 + O(q^13), - q^4 + O(q^13), - q^5 + O(q^13), - q^6 + O(q^13), - q^7 + O(q^13), - q^8 + O(q^13), - q^9 + O(q^13), - q^10 + O(q^13), - q^11 + O(q^13), - q^12 + O(q^13), - O(q^13), - O(q^13), - O(q^13), - O(q^13), - O(q^13), - O(q^13), - O(q^13) - ] + [q + O(q^13), + q^2 + O(q^13), + q^3 + O(q^13), + q^4 + O(q^13), + q^5 + O(q^13), + q^6 + O(q^13), + q^7 + O(q^13), + q^8 + O(q^13), + q^9 + O(q^13), + q^10 + O(q^13), + q^11 + O(q^13), + q^12 + O(q^13), + O(q^13), + O(q^13), + O(q^13), + O(q^13), + O(q^13), + O(q^13), + O(q^13)] """ W = self._q_expansion_module() pr = W.degree() @@ -658,35 +612,27 @@ def q_expansion_basis(self, prec=None): sage: S = ModularForms(11,2).cuspidal_submodule() sage: S.q_expansion_basis() - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)] sage: S.q_expansion_basis(5) - [ - q - 2*q^2 - q^3 + 2*q^4 + O(q^5) - ] + [q - 2*q^2 - q^3 + 2*q^4 + O(q^5)] sage: S = ModularForms(1,24).cuspidal_submodule() sage: S.q_expansion_basis(8) - [ - q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 - 982499328*q^6 - 147247240*q^7 + O(q^8), - q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + 143820*q^6 - 985824*q^7 + O(q^8) - ] + [q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 - 982499328*q^6 - 147247240*q^7 + O(q^8), + q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + 143820*q^6 - 985824*q^7 + O(q^8)] An example which used to be buggy:: sage: M = CuspForms(128, 2, prec=3) sage: M.q_expansion_basis() - [ - q - q^17 + O(q^22), - q^2 - 3*q^18 + O(q^22), - q^3 - q^11 + q^19 + O(q^22), - q^4 - 2*q^20 + O(q^22), - q^5 - 3*q^21 + O(q^22), - q^7 - q^15 + O(q^22), - q^9 - q^17 + O(q^22), - q^10 + O(q^22), - q^13 - q^21 + O(q^22) - ] + [q - q^17 + O(q^22), + q^2 - 3*q^18 + O(q^22), + q^3 - q^11 + q^19 + O(q^22), + q^4 - 2*q^20 + O(q^22), + q^5 - 3*q^21 + O(q^22), + q^7 - q^15 + O(q^22), + q^9 - q^17 + O(q^22), + q^10 + O(q^22), + q^13 - q^21 + O(q^22)] """ if prec is None: try: # don't care about precision -- just must be big enough to determine forms @@ -755,18 +701,14 @@ def q_echelon_basis(self, prec=None): sage: M = ModularForms(11,2) sage: M.q_expansion_basis() - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6), - 1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6), + 1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6)] :: sage: M.q_echelon_basis() - [ - 1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6), - q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6) - ] + [1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + O(q^6), + q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6)] """ prec = self.__normalize_prec(prec) if prec == 0: @@ -810,9 +752,7 @@ def q_integral_basis(self, prec=None): sage: S = CuspForms(11,2) sage: S.q_integral_basis(5) - [ - q - 2*q^2 - q^3 + 2*q^4 + O(q^5) - ] + [q - 2*q^2 - q^3 + 2*q^4 + O(q^5)] """ if not self.base_ring() == QQ: raise TypeError("the base ring must be Q") @@ -883,11 +823,9 @@ def _q_expansion(self, element, prec): sage: m = ModularForms(Gamma0(23),2); m Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(23) of weight 2 over Rational Field sage: m.basis() - [ - q - q^3 - q^4 + O(q^6), - q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6), - 1 + 12/11*q + 36/11*q^2 + 48/11*q^3 + 84/11*q^4 + 72/11*q^5 + O(q^6) - ] + [q - q^3 - q^4 + O(q^6), + q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6), + 1 + 12/11*q + 36/11*q^2 + 48/11*q^3 + 84/11*q^4 + 72/11*q^5 + O(q^6)] sage: m._q_expansion([1,2,0], 5) q + 2*q^2 - 5*q^3 - 3*q^4 + O(q^5) """ @@ -1377,10 +1315,8 @@ def basis(self): sage: MM = ModularForms(11,2) sage: MM.basis() - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6), - 1 + 12/5*q + 36/5*q^2 + 48/5*q^3 + 84/5*q^4 + 72/5*q^5 + O(q^6) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + O(q^6), + 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()], @@ -1394,13 +1330,11 @@ def gen(self, n): sage: N = ModularForms(6,4) sage: N.basis() - [ - q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6), - 1 + O(q^6), - q - 8*q^4 + 126*q^5 + O(q^6), - q^2 + 9*q^4 + O(q^6), - q^3 + O(q^6) - ] + [q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6), + 1 + O(q^6), + q - 8*q^4 + 126*q^5 + O(q^6), + q^2 + 9*q^4 + O(q^6), + q^3 + O(q^6)] :: @@ -1432,13 +1366,11 @@ def gens(self): sage: N = ModularForms(6,4) sage: N.gens() - [ - q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6), - 1 + O(q^6), - q - 8*q^4 + 126*q^5 + O(q^6), - q^2 + 9*q^4 + O(q^6), - q^3 + O(q^6) - ] + [q - 2*q^2 - 3*q^3 + 4*q^4 + 6*q^5 + O(q^6), + 1 + O(q^6), + q - 8*q^4 + 126*q^5 + O(q^6), + q^2 + 9*q^4 + O(q^6), + q^3 + O(q^6)] """ return self.basis() diff --git a/src/sage/modular/modform/vm_basis.py b/src/sage/modular/modform/vm_basis.py index 58f36fd0f1a..737da840eea 100644 --- a/src/sage/modular/modform/vm_basis.py +++ b/src/sage/modular/modform/vm_basis.py @@ -68,52 +68,34 @@ def victor_miller_basis(k, prec=10, cusp_only=False, var='q'): sage: victor_miller_basis(1, 6) [] sage: victor_miller_basis(0, 6) - [ - 1 + O(q^6) - ] + [1 + O(q^6)] sage: victor_miller_basis(2, 6) [] sage: victor_miller_basis(4, 6) - [ - 1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6) - ] + [1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)] sage: victor_miller_basis(6, 6, var='w') - [ - 1 - 504*w - 16632*w^2 - 122976*w^3 - 532728*w^4 - 1575504*w^5 + O(w^6) - ] + [1 - 504*w - 16632*w^2 - 122976*w^3 - 532728*w^4 - 1575504*w^5 + O(w^6)] sage: victor_miller_basis(6, 6) - [ - 1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6) - ] + [1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)] sage: victor_miller_basis(12, 6) - [ - 1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6), - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) - ] + [1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6), + q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)] sage: victor_miller_basis(12, 6, cusp_only=True) - [ - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6) - ] + [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)] sage: victor_miller_basis(24, 6, cusp_only=True) - [ - q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), - q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) - ] + [q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), + q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6)] sage: victor_miller_basis(24, 6) - [ - 1 + 52416000*q^3 + 39007332000*q^4 + 6609020221440*q^5 + O(q^6), - q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), - q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6) - ] + [1 + 52416000*q^3 + 39007332000*q^4 + 6609020221440*q^5 + O(q^6), + q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6), + q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6)] sage: victor_miller_basis(32, 6) - [ - 1 + 2611200*q^3 + 19524758400*q^4 + 19715347537920*q^5 + O(q^6), - q + 50220*q^3 + 87866368*q^4 + 18647219790*q^5 + O(q^6), - q^2 + 432*q^3 + 39960*q^4 - 1418560*q^5 + O(q^6) - ] + [1 + 2611200*q^3 + 19524758400*q^4 + 19715347537920*q^5 + O(q^6), + q + 50220*q^3 + 87866368*q^4 + 18647219790*q^5 + O(q^6), + q^2 + 432*q^3 + 39960*q^4 - 1418560*q^5 + O(q^6)] sage: victor_miller_basis(40,200)[1:] == victor_miller_basis(40,200,cusp_only=True) True diff --git a/src/sage/modular/modform_hecketriangle/abstract_space.py b/src/sage/modular/modform_hecketriangle/abstract_space.py index 79352b97ffe..8c9a5db1aac 100644 --- a/src/sage/modular/modform_hecketriangle/abstract_space.py +++ b/src/sage/modular/modform_hecketriangle/abstract_space.py @@ -23,7 +23,7 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.laurent_series_ring import LaurentSeriesRing -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.power_series_ring import PowerSeriesRing_generic from sage.rings.rational_field import QQ from sage.structure.element import parent @@ -1707,7 +1707,7 @@ def construct_form(self, laurent_series, order_1=ZZ.zero(), check=True, rational """ base_ring = laurent_series.base_ring() - if isinstance(base_ring.base(), PolynomialRing_general): + if isinstance(base_ring.base(), PolynomialRing_generic): if not (self.coeff_ring().has_coerce_map_from(base_ring)): raise ValueError("The Laurent coefficients don't coerce into the coefficient ring of self!") elif rationalize: @@ -2001,7 +2001,7 @@ def construct_quasi_form(self, laurent_series, order_1=ZZ.zero(), check=True, ra """ base_ring = laurent_series.base_ring() - if isinstance(base_ring.base(), PolynomialRing_general): + if isinstance(base_ring.base(), PolynomialRing_generic): if not (self.coeff_ring().has_coerce_map_from(base_ring)): raise ValueError("The Laurent coefficients don't coerce into the coefficient ring of self!") elif rationalize: @@ -2269,7 +2269,7 @@ def rationalize_series(self, laurent_series, coeff_bound=1e-10, denom_factor=ZZ( # If the coefficients already coerce to our coefficient ring # and are in polynomial form we simply return the Laurent series - if (isinstance(base_ring.base(), PolynomialRing_general)): + if (isinstance(base_ring.base(), PolynomialRing_generic)): if (self.coeff_ring().has_coerce_map_from(base_ring)): return laurent_series else: diff --git a/src/sage/modular/modform_hecketriangle/functors.py b/src/sage/modular/modform_hecketriangle/functors.py index b50d618c3c4..20397eebfb5 100644 --- a/src/sage/modular/modform_hecketriangle/functors.py +++ b/src/sage/modular/modform_hecketriangle/functors.py @@ -79,7 +79,7 @@ def _get_base_ring(ring, var_name='d'): """ # from sage.rings.fraction_field import FractionField_generic - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.categories.pushout import FractionField as FractionFieldFunctor base_ring = ring @@ -87,7 +87,7 @@ def _get_base_ring(ring, var_name='d'): # base_ring = base_ring.base() if (base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor()): base_ring = base_ring.construction()[1] - if (isinstance(base_ring, PolynomialRing_general) and base_ring.ngens() == 1 and base_ring.variable_name() == var_name): + if (isinstance(base_ring, PolynomialRing_generic) and base_ring.ngens() == 1 and base_ring.variable_name() == var_name): base_ring = base_ring.base() if (base_ring.construction() and base_ring.construction()[0] == FractionFieldFunctor()): base_ring = base_ring.construction()[1] diff --git a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py index 6aedcba881c..f4a4c3a892b 100644 --- a/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py +++ b/src/sage/modular/modform_hecketriangle/hecke_triangle_groups.py @@ -1383,7 +1383,7 @@ def rational_period_functions(self, k, D): The method assumes that ``D > 0``. - Also see the element method `rational_period_function` for more information. + Also see the element method ``rational_period_function`` for more information. - ``k`` -- even integer, the desired weight of the rational period functions diff --git a/src/sage/modular/modsym/ambient.py b/src/sage/modular/modsym/ambient.py index beb8509af0f..56e01e8c106 100644 --- a/src/sage/modular/modsym/ambient.py +++ b/src/sage/modular/modsym/ambient.py @@ -1761,9 +1761,9 @@ def factorization(self): else: A._is_simple = True D.append((A, n)) - # The eisenstein part - for E in self.eisenstein_submodule().decomposition(anemic=True): - D.append((E, 1)) + # The Eisenstein part + D.extend((E, 1) for E in + self.eisenstein_submodule().decomposition(anemic=True)) r = self.dimension() s = sum(A.rank() * mult for A, mult in D) diff --git a/src/sage/modular/modsym/boundary.py b/src/sage/modular/modsym/boundary.py index 16241c843aa..89e0e6b0aef 100644 --- a/src/sage/modular/modsym/boundary.py +++ b/src/sage/modular/modsym/boundary.py @@ -89,20 +89,16 @@ # **************************************************************************** -from sage.misc.repr import repr_lincomb -from sage.structure.richcmp import richcmp_method, richcmp - -import sage.modules.free_module as free_module -from sage.modules.free_module_element import FreeModuleElement - import sage.modular.arithgroup.all as arithgroup -import sage.modular.cusps as cusps -import sage.modular.dirichlet as dirichlet import sage.modular.hecke.all as hecke +from sage.categories.rings import Rings +from sage.misc.repr import repr_lincomb +from sage.modular import cusps, dirichlet from sage.modular.modsym.manin_symbol import ManinSymbol - +from sage.modules import free_module +from sage.modules.free_module_element import FreeModuleElement from sage.rings.rational_field import Q as QQ -from sage.categories.rings import Rings +from sage.structure.richcmp import richcmp, richcmp_method from . import element @@ -299,7 +295,7 @@ def __init__(self, - ``sign`` -- integer; either -1, 0, or 1 - - ``base_ring`` -- rings.Ring (defaults to the rational numbers) + - ``base_ring`` -- commutative ring (defaults to the rational numbers) EXAMPLES:: @@ -431,7 +427,9 @@ def gen(self, i=0): sage: B.gen(0) Traceback (most recent call last): ... - ValueError: only 0 generators known for Space of Boundary Modular Symbols for Congruence Subgroup Gamma0(24) of weight 4 over Rational Field + ValueError: only 0 generators known for + Space of Boundary Modular Symbols for + Congruence Subgroup Gamma0(24) of weight 4 over Rational Field sage: B(Cusp(1/3)) [1/3] sage: B.gen(0) diff --git a/src/sage/modular/modsym/heilbronn.pyx b/src/sage/modular/modsym/heilbronn.pyx index 82adf9efa20..598e8ccfff9 100644 --- a/src/sage/modular/modsym/heilbronn.pyx +++ b/src/sage/modular/modsym/heilbronn.pyx @@ -202,8 +202,8 @@ cdef class Heilbronn: b[i] = (u * self.list.v[4*i+1]) % N + (v * self.list.v[4*i+3]) % N else: for i in range(self.length): - a[i] = llong_prod_mod(u,self.list.v[4*i],N) + llong_prod_mod(v,self.list.v[4*i+2], N) - b[i] = llong_prod_mod(u,self.list.v[4*i+1],N) + llong_prod_mod(v,self.list.v[4*i+3], N) + a[i] = llong_prod_mod(u, self.list.v[4*i], N) + llong_prod_mod(v, self.list.v[4*i+2], N) + b[i] = llong_prod_mod(u, self.list.v[4*i+1], N) + llong_prod_mod(v, self.list.v[4*i+3], N) sig_off() cdef apply_to_polypart(self, fmpz_poly_t* ans, int i, int k): @@ -283,8 +283,8 @@ cdef class Heilbronn: else: for i in range(self.length): sig_check() - a = llong_prod_mod(u,self.list.v[4*i],N) + llong_prod_mod(v,self.list.v[4*i+2], N) - b = llong_prod_mod(u,self.list.v[4*i+1],N) + llong_prod_mod(v,self.list.v[4*i+3], N) + a = llong_prod_mod(u, self.list.v[4*i], N) + llong_prod_mod(v, self.list.v[4*i+2], N) + b = llong_prod_mod(u, self.list.v[4*i+1], N) + llong_prod_mod(v, self.list.v[4*i+3], N) export.c_p1_normalize_llong(N, a, b, &c, &d, &s, 0) X = (c, d) if X in M: @@ -368,15 +368,15 @@ cdef class HeilbronnCremona(Heilbronn): L = &self.list p = self.p - list_append4(L, 1,0,0,p) + list_append4(L, 1, 0, 0, p) # When p==2, then Heilbronn matrices are # [[1,0,0,2], [2,0,0,1], [2,1,0,1], [1,0,1,2]] # which are not given by the algorithm below. if p == 2: - list_append4(L, 2,0,0,1) - list_append4(L, 2,1,0,1) - list_append4(L, 1,0,1,2) + list_append4(L, 2, 0, 0, 1) + list_append4(L, 2, 1, 0, 1) + list_append4(L, 1, 0, 1, 2) self.length = 4 return @@ -489,20 +489,20 @@ cdef class HeilbronnMerel(Heilbronn): sig_on() for a in range(1, n+1): - ## We have ad-bc=n so c=0 and ad=n, or b=(ad-n)/c - ## Must have ad - n >= 0, so d must be >= Ceiling(n/a). + # We have ad-bc=n so c=0 and ad=n, or b=(ad-n)/c + # Must have ad - n >= 0, so d must be >= Ceiling(n/a). q = n // a if q*a == n: d = q for b in range(a): - list_append4(L, a,b,0,d) + list_append4(L, a, b, 0, d) for c in range(1, d): - list_append4(L, a,0,c,d) + list_append4(L, a, 0, c, d) for d in range(q+1, n+1): bc = (a) * (d) - (n) - ## Divisor c of bc must satisfy Floor(bc/c) lt a and c lt d. - ## c ge (bc div a + 1) <=> Floor(bc/c) lt a (for integers) - ## c le d - 1 <=> c lt d + # Divisor c of bc must satisfy Floor(bc/c) lt a and c lt d. + # c ge (bc div a + 1) <=> Floor(bc/c) lt a (for integers) + # c le d - 1 <=> c lt d for c in range(bc // a + 1, d): if bc % c == 0: list_append4(L, a, bc // c, c, d) @@ -569,7 +569,7 @@ def hecke_images_gamma0_weight2(int u, int v, int N, indices, R): cdef Heilbronn H t = verbose("computing non-reduced images of symbol under Hecke operators", - level=1, caller_name='hecke_images_gamma0_weight2') + level=1, caller_name='hecke_images_gamma0_weight2') for i, n in enumerate(indices): # List the Heilbronn matrices of determinant n defined by Cremona or Merel H = HeilbronnCremona(n) if is_prime(n) else HeilbronnMerel(n) @@ -601,25 +601,25 @@ def hecke_images_gamma0_weight2(int u, int v, int N, indices, R): sig_free(b) t = verbose("finished computing non-reduced images", - t, level=1, caller_name='hecke_images_gamma0_weight2') + t, level=1, caller_name='hecke_images_gamma0_weight2') t = verbose("Now reducing images of symbol", - level=1, caller_name='hecke_images_gamma0_weight2') + level=1, caller_name='hecke_images_gamma0_weight2') # Return the product T * R, whose rows are the image of (u,v) under # the Hecke operators T_n for n in indices. if max(indices) <= 30: # In this case T tends to be very sparse ans = T.sparse_matrix()._matrix_times_matrix_dense(R) verbose("did reduction using sparse multiplication", - t, level=1, caller_name='hecke_images_gamma0_weight2') + t, level=1, caller_name='hecke_images_gamma0_weight2') elif R.is_sparse(): ans = T * R.dense_matrix() verbose("did reduction using dense multiplication", - t, level=1, caller_name='hecke_images_gamma0_weight2') + t, level=1, caller_name='hecke_images_gamma0_weight2') else: ans = T * R verbose("did reduction using dense multiplication", - t, level=1, caller_name='hecke_images_gamma0_weight2') + t, level=1, caller_name='hecke_images_gamma0_weight2') if original_base_ring != QQ: ans = ans.change_ring(original_base_ring) @@ -700,7 +700,7 @@ def hecke_images_nonquad_character_weight2(int u, int v, int N, indices, chi, R) cdef Heilbronn H t = verbose("computing non-reduced images of symbol under Hecke operators", - level=1, caller_name='hecke_images_character_weight2') + level=1, caller_name='hecke_images_character_weight2') # Make a matrix over the rational numbers each of whose columns # are the values of the character chi. diff --git a/src/sage/modular/modsym/manin_symbol.pyx b/src/sage/modular/modsym/manin_symbol.pyx index 726f78c55a6..0a7feaffb5b 100644 --- a/src/sage/modular/modsym/manin_symbol.pyx +++ b/src/sage/modular/modsym/manin_symbol.pyx @@ -401,7 +401,7 @@ cdef class ManinSymbol(Element): N=int(N) if N < 1: raise ArithmeticError("N must be positive") - a,b,c,d = self.lift_to_sl2z() + a, b, c, d = self.lift_to_sl2z() return Cusp(b, d), Cusp(a, c) def weight(self): @@ -453,8 +453,7 @@ cdef class ManinSymbol(Element): # TODO: It would likely be much better to do this slightly more directly from sage.modular.modsym.modular_symbols import ModularSymbol x = ModularSymbol(self.parent(), self.i, 0, Infinity) - a,b,c,d = self.lift_to_sl2z() - return x.apply([a,b,c,d]) + return x.apply(self.lift_to_sl2z()) def _print_polypart(i, j): diff --git a/src/sage/modular/modsym/meson.build b/src/sage/modular/modsym/meson.build index f05d0776246..15851710402 100644 --- a/src/sage/modular/modsym/meson.build +++ b/src/sage/modular/modsym/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'ambient.py', 'apply.pxd', diff --git a/src/sage/modular/modsym/modsym.py b/src/sage/modular/modsym/modsym.py index fb46d0edafa..fc6a3a2d712 100644 --- a/src/sage/modular/modsym/modsym.py +++ b/src/sage/modular/modsym/modsym.py @@ -24,12 +24,8 @@ sage: M.T(2).charpoly('x').factor() (x - 3) * (x^2 + x - 1)^2 sage: M.decomposition(2) - [ - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 5 - for Gamma_0(23) of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 5 - for Gamma_0(23) of weight 2 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Rational Field] :: @@ -38,17 +34,9 @@ sage: M.T(2).charpoly('x').factor() (x - 3) * (x - 1/2*sqrt5 + 1/2)^2 * (x + 1/2*sqrt5 + 1/2)^2 sage: M.decomposition(2) - [ - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 5 - for Gamma_0(23) of weight 2 with sign 0 over Number Field in sqrt5 - with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?, - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 - for Gamma_0(23) of weight 2 with sign 0 over Number Field in sqrt5 - with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?, - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 - for Gamma_0(23) of weight 2 with sign 0 over Number Field in sqrt5 - with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790? - ] + [Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?, + Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Gamma_0(23) of weight 2 with sign 0 over Number Field in sqrt5 with defining polynomial x^2 - 5 with sqrt5 = 2.236067977499790?] We compute some Hecke operators and do a consistency check:: @@ -263,14 +251,8 @@ def ModularSymbols(group=1, sage: G = GammaH(15,[4,13]) sage: M = ModularSymbols(G,2) sage: M.decomposition() - [ - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 - for Congruence Subgroup Gamma_H(15) with H generated by [4, 7] - of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 5 - for Congruence Subgroup Gamma_H(15) with H generated by [4, 7] - of weight 2 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 5 for Congruence Subgroup Gamma_H(15) with H generated by [4, 7] of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 5 for Congruence Subgroup Gamma_H(15) with H generated by [4, 7] of weight 2 with sign 0 over Rational Field] We create a space with character:: @@ -369,7 +351,7 @@ def ModularSymbols(group=1, {} sage: M = ModularSymbols(11,use_cache=True) sage: sage.modular.modsym.modsym._cache - {(Congruence Subgroup Gamma0(11), 2, 0, Rational Field): } + {(Congruence Subgroup Gamma0(11), 2, 0, Rational Field): } sage: M is ModularSymbols(11,use_cache=True) True sage: M is ModularSymbols(11,use_cache=False) diff --git a/src/sage/modular/modsym/p1list.pxd b/src/sage/modular/modsym/p1list.pxd index b66f28b8ad6..b559922411c 100644 --- a/src/sage/modular/modsym/p1list.pxd +++ b/src/sage/modular/modsym/p1list.pxd @@ -6,8 +6,8 @@ cdef class export: int compute_s) except -1 cdef int c_p1_normalize_llong(self, int N, int u, int v, - int* uu, int* vv, int* ss, - int compute_s) except -1 + int* uu, int* vv, int* ss, + int compute_s) except -1 cdef class P1List: @@ -22,7 +22,7 @@ cdef class P1List: # for normalizing an element does not need to be used # every time the user calls the normalize function. cdef int (*_normalize)(int N, int u, int v, - int* uu, int* vv, int* ss, - int compute_s) except -1 + int* uu, int* vv, int* ss, + int compute_s) except -1 cpdef index(self, int u, int v) cdef index_and_scalar(self, int u, int v, int* i, int* s) diff --git a/src/sage/modular/modsym/p1list.pyx b/src/sage/modular/modsym/p1list.pyx index 7ceda12d5c8..f7d5f4b209b 100644 --- a/src/sage/modular/modsym/p1list.pyx +++ b/src/sage/modular/modsym/p1list.pyx @@ -75,7 +75,7 @@ cdef int c_p1_normalize_int(int N, int u, int v, v += N if u == 0: uu[0] = 0 - if arith_int.c_gcd_int(v,N) == 1: + if arith_int.c_gcd_int(v, N) == 1: vv[0] = 1 else: vv[0] = 0 @@ -96,7 +96,7 @@ cdef int c_p1_normalize_int(int N, int u, int v, # Adjust s modulo N/g so it is coprime to N. if g != 1: d = N // g - while arith_int.c_gcd_int(s,N) != 1: + while arith_int.c_gcd_int(s, N) != 1: s = (s+d) % N # Multiply [u,v] by s; then [s*u,s*v] = [g,s*v] (mod N) @@ -112,7 +112,7 @@ cdef int c_p1_normalize_int(int N, int u, int v, for k in range(2, g + 1): v = (v + vNg) % N t = (t + Ng) % N - if v N - #if N<=0 or N >= 2**31: - # raise OverflowError("Modulus is too large (must be < 46340)") - # return -1 + # if N <= 0 or N >= 2**31: + # raise OverflowError("Modulus is too large (must be < 46340)") + # return -1 u = u % N v = v % N @@ -333,14 +333,14 @@ cdef int c_p1_normalize_llong(int N, int u, int v, v += N if u == 0: uu[0] = 0 - if arith_int.c_gcd_int(v,N) == 1: + if arith_int.c_gcd_int(v, N) == 1: vv[0] = 1 else: vv[0] = 0 ss[0] = v return 0 - #g = xgcd_int_llong(u, N, &s, &t) + # g = xgcd_int_llong(u, N, &s, &t) g = arith_llong.c_xgcd_longlong(u, N, &ll_s, &ll_t) s = (ll_s % ll_N) t = (ll_t % ll_N) @@ -357,7 +357,7 @@ cdef int c_p1_normalize_llong(int N, int u, int v, # Adjust s modulo N/g so it is coprime to N. if g != 1: d = N // g - while arith_int.c_gcd_int(s,N) != 1: + while arith_int.c_gcd_int(s, N) != 1: s = (s+d) % N # Multiply [u,v] by s; then [s*u,s*v] = [g,s*v] (mod N) @@ -466,7 +466,7 @@ def p1list_llong(int N): if N == 1: return [(0, 0)] - lst = [(0,1)] + lst = [(0, 1)] c = 1 for d in range(N): lst.append((c, d)) @@ -720,7 +720,7 @@ cdef class P1List(): else: raise OverflowError("p1list not defined for such large N.") self.__list.sort() - self.__end_hash = dict([(x,i) for i, x in enumerate(self.__list[N+1:])]) + self.__end_hash = {x: i for i, x in enumerate(self.__list[N+1:])} # Allocate memory for xgcd table. self.g = NULL @@ -870,7 +870,7 @@ cdef class P1List(): cdef int c, d, N if self.__N == 1: - return [1,0,0,1] + return [1, 0, 0, 1] c, d = self.__list[i] N = self.__N @@ -909,9 +909,9 @@ cdef class P1List(): True """ cdef int u, v, uu, vv, ss - u,v = self.__list[i] + u, v = self.__list[i] self._normalize(self.__N, -u, v, &uu, &vv, &ss, 0) - _, j = search(self.__list, (uu,vv)) + _, j = search(self.__list, (uu, vv)) return j def apply_S(self, int i): @@ -941,9 +941,9 @@ cdef class P1List(): True """ cdef int u, v, uu, vv, ss - u,v = self.__list[i] + u, v = self.__list[i] self._normalize(self.__N, -v, u, &uu, &vv, &ss, 0) - _, j = search(self.__list, (uu,vv)) + _, j = search(self.__list, (uu, vv)) return j def apply_T(self, int i): @@ -973,9 +973,9 @@ cdef class P1List(): True """ cdef int u, v, uu, vv, ss - u,v = self.__list[i] + u, v = self.__list[i] self._normalize(self.__N, v, -u-v, &uu, &vv, &ss, 0) - _, j = search(self.__list, (uu,vv)) + _, j = search(self.__list, (uu, vv)) return j cpdef index(self, int u, int v): @@ -1014,7 +1014,7 @@ cdef class P1List(): return -1 return 0 try: - return self.__end_hash[(uu,vv)] + self.__N + 1 + return self.__end_hash[(uu, vv)] + self.__N + 1 except KeyError: return -1 @@ -1053,7 +1053,7 @@ cdef class P1List(): i[0] = 0 return try: - i[0] = self.__end_hash[(uu,vv)] + self.__N + 1 + i[0] = self.__end_hash[(uu, vv)] + self.__N + 1 return except KeyError: i[0] = -1 @@ -1084,7 +1084,7 @@ cdef class P1List(): sage: all(L.index_of_normalized_pair(L[i][0],L[i][1])==i for i in range(len(L))) True """ - t, i = search(self.__list, (u,v)) + t, i = search(self.__list, (u, v)) if t: return i return -1 @@ -1129,7 +1129,7 @@ cdef class P1List(): """ cdef int uu, vv, ss self._normalize(self.__N, u, v, &uu, &vv, &ss, 0) - return (uu,vv) + return (uu, vv) def normalize_with_scalar(self, int u, int v): r""" @@ -1365,11 +1365,10 @@ def lift_to_sl2z(c, d, N): [1, 0, 0, 1] """ if N <= 46340: - return lift_to_sl2z_int(c,d,N) - elif N <= 2147483647: - return lift_to_sl2z_llong(c,d,N) - else: - raise NotImplementedError("N too large") + return lift_to_sl2z_int(c, d, N) + if N <= 2147483647: + return lift_to_sl2z_llong(c, d, N) + raise NotImplementedError("N too large") def _make_p1list(n): diff --git a/src/sage/modular/modsym/space.py b/src/sage/modular/modsym/space.py index a77d9279a6b..38ca3d684a4 100644 --- a/src/sage/modular/modsym/space.py +++ b/src/sage/modular/modsym/space.py @@ -451,10 +451,8 @@ def is_simple(self): False sage: o = m.old_subspace() sage: o.decomposition() - [ - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field, - Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field - ] + [Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field, + Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 6 for Gamma_0(33) of weight 2 with sign 1 over Rational Field] sage: C = ModularSymbols(1,14,0,GF(5)).cuspidal_submodule(); C Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 2 for Gamma_0(1) of weight 14 with sign 0 over Finite Field of size 5 sage: C.is_simple() @@ -545,9 +543,7 @@ def default_prec(self): sage: M = ModularSymbols(15) sage: M.cuspidal_submodule().q_expansion_basis() - [ - q - q^2 - q^3 - q^4 + q^5 + q^6 + O(q^8) - ] + [q - q^2 - q^3 - q^4 + q^5 + q^6 + O(q^8)] sage: M.set_default_prec(20) Notice that setting the default precision of the ambient space @@ -556,9 +552,7 @@ def default_prec(self): :: sage: M.cuspidal_submodule().q_expansion_basis() - [ - q - q^2 - q^3 - q^4 + q^5 + q^6 + 3*q^8 + q^9 - q^10 - 4*q^11 + q^12 - 2*q^13 - q^15 - q^16 + 2*q^17 - q^18 + 4*q^19 + O(q^20) - ] + [q - q^2 - q^3 - q^4 + q^5 + q^6 + 3*q^8 + q^9 - q^10 - 4*q^11 + q^12 - 2*q^13 - q^15 - q^16 + 2*q^17 - q^18 + 4*q^19 + O(q^20)] sage: M.cuspidal_submodule().default_prec() 20 """ @@ -581,10 +575,7 @@ def set_default_prec(self, prec): sage: M = ModularSymbols(Gamma1(13),2) sage: M.set_default_prec(5) sage: M.cuspidal_submodule().q_expansion_basis() - [ - q - 4*q^3 - q^4 + O(q^5), - q^2 - 2*q^3 - q^4 + O(q^5) - ] + [q - 4*q^3 - q^4 + O(q^5), q^2 - 2*q^3 - q^4 + O(q^5)] """ if not self.is_ambient(): return self.ambient_hecke_module().set_default_prec(prec) @@ -599,14 +590,10 @@ def set_precision(self, prec): sage: M = ModularSymbols(17,2) sage: M.cuspidal_submodule().q_expansion_basis() - [ - q - q^2 - q^4 - 2*q^5 + 4*q^7 + O(q^8) - ] + [q - q^2 - q^4 - 2*q^5 + 4*q^7 + O(q^8)] sage: M.set_precision(10) sage: M.cuspidal_submodule().q_expansion_basis() - [ - q - q^2 - q^4 - 2*q^5 + 4*q^7 + 3*q^8 - 3*q^9 + O(q^10) - ] + [q - q^2 - q^4 - 2*q^5 + 4*q^7 + 3*q^8 - 3*q^9 + O(q^10)] """ self.set_default_prec(prec) @@ -646,42 +633,32 @@ def q_expansion_basis(self, prec=None, algorithm='default'): sage: M = ModularSymbols(1, 12).cuspidal_submodule() sage: M.q_expansion_basis(8) - [ - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8) - ] + [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8)] :: sage: M.q_expansion_basis(8, algorithm='eigen') - [ - q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8) - ] + [q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + O(q^8)] :: sage: M = ModularSymbols(1, 24).cuspidal_submodule() sage: M.q_expansion_basis(8, algorithm='eigen') - [ - q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 - 982499328*q^6 - 147247240*q^7 + O(q^8), - q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + 143820*q^6 - 985824*q^7 + O(q^8) - ] + [q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 - 982499328*q^6 - 147247240*q^7 + O(q^8), + q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + 143820*q^6 - 985824*q^7 + O(q^8)] :: sage: M = ModularSymbols(11, 2, sign=-1).cuspidal_submodule() sage: M.q_expansion_basis(8, algorithm='eigen') - [ - q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 + O(q^8) - ] + [q - 2*q^2 - q^3 + 2*q^4 + q^5 + 2*q^6 - 2*q^7 + O(q^8)] :: sage: M = ModularSymbols(Gamma1(13), 2, sign=1).cuspidal_submodule() sage: M.q_expansion_basis(8, algorithm='eigen') - [ - q - 4*q^3 - q^4 + 3*q^5 + 6*q^6 + O(q^8), - q^2 - 2*q^3 - q^4 + 2*q^5 + 2*q^6 + O(q^8) - ] + [q - 4*q^3 - q^4 + 3*q^5 + 6*q^6 + O(q^8), + q^2 - 2*q^3 - q^4 + 2*q^5 + 2*q^6 + O(q^8)] :: @@ -693,9 +670,7 @@ def q_expansion_basis(self, prec=None, algorithm='default'): sage: M = ModularSymbols(Gamma1(7), 3, sign=-1).cuspidal_submodule() sage: M.q_expansion_basis(8) - [ - q - 3*q^2 + 5*q^4 - 7*q^7 + O(q^8) - ] + [q - 3*q^2 + 5*q^4 - 7*q^7 + O(q^8)] :: @@ -703,16 +678,11 @@ def q_expansion_basis(self, prec=None, algorithm='default'): sage: M[0] Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 7 for Gamma_0(43) of weight 2 with sign 0 over Rational Field sage: M[0].q_expansion_basis() - [ - q - 2*q^2 - 2*q^3 + 2*q^4 - 4*q^5 + 4*q^6 + O(q^8) - ] + [q - 2*q^2 - 2*q^3 + 2*q^4 - 4*q^5 + 4*q^6 + O(q^8)] sage: M[1] Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 7 for Gamma_0(43) of weight 2 with sign 0 over Rational Field sage: M[1].q_expansion_basis() - [ - q + 2*q^5 - 2*q^6 - 2*q^7 + O(q^8), - q^2 - q^3 - q^5 + q^7 + O(q^8) - ] + [q + 2*q^5 - 2*q^6 - 2*q^7 + O(q^8), q^2 - q^3 - q^5 + q^7 + O(q^8)] """ if prec is None: prec = self.default_prec() @@ -851,10 +821,8 @@ def q_expansion_module(self, prec=None, R=None): sage: k. = NumberField(x^2-5) sage: M = ModularSymbols(23, base_ring=k, sign=1).cuspidal_submodule() sage: D = M.decomposition(); D - [ - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(23) of weight 2 with sign 1 over Number Field in a with defining polynomial x^2 - 5, - Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(23) of weight 2 with sign 1 over Number Field in a with defining polynomial x^2 - 5 - ] + [Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(23) of weight 2 with sign 1 over Number Field in a with defining polynomial x^2 - 5, + Modular Symbols subspace of dimension 1 of Modular Symbols space of dimension 3 for Gamma_0(23) of weight 2 with sign 1 over Number Field in a with defining polynomial x^2 - 5] sage: M.q_expansion_module(8, QQ) Vector space of degree 8 and dimension 2 over Rational Field Basis matrix: @@ -870,9 +838,7 @@ def q_expansion_module(self, prec=None, R=None): sage: M = ModularSymbols(eps,2,sign=1).cuspidal_submodule(); M Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 and level 25, weight 2, character [zeta10], sign 1, over Cyclotomic Field of order 10 and degree 4 sage: D = M.decomposition(); D - [ - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 and level 25, weight 2, character [zeta10], sign 1, over Cyclotomic Field of order 10 and degree 4 - ] + [Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 4 and level 25, weight 2, character [zeta10], sign 1, over Cyclotomic Field of order 10 and degree 4] sage: D[0].q_eigenform(4, 'mu') q + mu*q^2 + ((zeta10^3 + zeta10 - 1)*mu + zeta10^2 - 1)*q^3 + O(q^4) sage: D[0].q_expansion_module(11, QQ) @@ -1545,10 +1511,8 @@ def star_decomposition(self): EXAMPLES:: sage: ModularSymbols(Gamma1(19), 2).cuspidal_submodule().star_decomposition() - [ - Modular Symbols subspace of dimension 7 of Modular Symbols space of dimension 31 for Gamma_1(19) of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 7 of Modular Symbols space of dimension 31 for Gamma_1(19) of weight 2 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 7 of Modular Symbols space of dimension 31 for Gamma_1(19) of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 7 of Modular Symbols space of dimension 31 for Gamma_1(19) of weight 2 with sign 0 over Rational Field] """ S = self.star_involution() return S.decomposition() diff --git a/src/sage/modular/multiple_zeta.py b/src/sage/modular/multiple_zeta.py index 8bcbb1101de..239bc0b1ead 100644 --- a/src/sage/modular/multiple_zeta.py +++ b/src/sage/modular/multiple_zeta.py @@ -202,13 +202,17 @@ # using the following convention # (3, 5) <---> (sign) * [1,0,0,1,0,0,0,0] # taken from the Maple implementation by F. Brown -B_data = [[], [], [(2,)], [(3,)], [], [(5,)], [], [(7,)], [(3, 5)], [(9,)], - [(3, 7)], [(11,), (3, 3, 5)], [(5, 7), (5, 3, 2, 2)], - [(13,), (3, 5, 5), (3, 3, 7)], [(5, 9), (3, 11), (3, 3, 3, 5)], - [(15,), (3, 5, 7), (3, 3, 9), (5, 3, 3, 2, 2)], - [(11, 5), (13, 3), (5, 5, 3, 3), (7, 3, 3, 3), (7, 5, 2, 2)], - [(17,), (7, 5, 5), (9, 3, 5), (9, 5, 3), (11, 3, 3), - (5, 3, 3, 3, 3), (5, 5, 3, 2, 2)]] +B_data: list[list[tuple]] = [[], [], [(2,)], [(3,)], [], [(5,)], [], + [(7,)], [(3, 5)], [(9,)], + [(3, 7)], [(11,), (3, 3, 5)], + [(5, 7), (5, 3, 2, 2)], + [(13,), (3, 5, 5), (3, 3, 7)], + [(5, 9), (3, 11), (3, 3, 3, 5)], + [(15,), (3, 5, 7), (3, 3, 9), (5, 3, 3, 2, 2)], + [(11, 5), (13, 3), (5, 5, 3, 3), + (7, 3, 3, 3), (7, 5, 2, 2)], + [(17,), (7, 5, 5), (9, 3, 5), (9, 5, 3), + (11, 3, 3), (5, 3, 3, 3, 3), (5, 5, 3, 2, 2)]] Words10 = Words((1, 0), infinite=False) @@ -1050,7 +1054,7 @@ def basis_filtration(self, d, reverse=False): dim = len(self((d,)).phi_as_vector()) V = VectorSpace(QQ, dim) U = V.subspace([]) - basis = [] + basis: list = [] k = 1 while len(basis) < dim: for c in Compositions(d, length=k): diff --git a/src/sage/modular/overconvergent/hecke_series.py b/src/sage/modular/overconvergent/hecke_series.py index f347da9a278..68a4faa47d4 100644 --- a/src/sage/modular/overconvergent/hecke_series.py +++ b/src/sage/modular/overconvergent/hecke_series.py @@ -236,15 +236,11 @@ def low_weight_generators(N, p, m, NN): [q + 116*q^4 + 115*q^5 + 102*q^6 + 121*q^7 + 96*q^8 + 106*q^9 + O(q^10)]], 4) """ M = ModularFormsRing(N, base_ring=Zmod(p)) - b = M.gen_forms(maxweight=8) - - weightbound = max([f.weight() for f in b]) - generators = [] - - for k in range(2, weightbound + 2, 2): - generators.append([f.qexp(NN).change_ring(Zmod(p ** m)) for f in b if f.weight() == k]) - + weightbound = max(f.weight() for f in b) + generators = [[f.qexp(NN).change_ring(Zmod(p ** m)) + for f in b if f.weight() == k] + for k in range(2, weightbound + 2, 2)] return generators, weightbound diff --git a/src/sage/modular/pollack_stevens/dist.pyx b/src/sage/modular/pollack_stevens/dist.pyx index 85cccd3bb11..9ed53a955c9 100644 --- a/src/sage/modular/pollack_stevens/dist.pyx +++ b/src/sage/modular/pollack_stevens/dist.pyx @@ -43,7 +43,7 @@ from sage.rings.rational_field import QQ from sage.structure.element cimport Element from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool -#from sage.libs.flint.ulong_extras cimport * +# from sage.libs.flint.ulong_extras cimport * cdef long overflow = 1 << (4 * sizeof(long) - 1) cdef long underflow = -overflow @@ -360,8 +360,8 @@ cdef class Dist(ModuleElement): raise ValueError("self is zero") v = a.valuation(p) relprec = n - i - v -# verbose("p=%s, n-i=%s\nself.moment=%s, other.moment=%s" % (p, n-i, a, other._unscaled_moment(i)),level=2) -## RP: This code was crashing because other may have too few moments -- so I added this bound with other's relative precision + # verbose("p=%s, n-i=%s\nself.moment=%s, other.moment=%s" % (p, n-i, a, other._unscaled_moment(i)),level=2) + # RP: This code was crashing because other may have too few moments -- so I added this bound with other's relative precision if padic: if i < other_pr: alpha = (other._unscaled_moment(i) / a).add_bigoh(n - i) @@ -373,7 +373,7 @@ cdef class Dist(ModuleElement): else: alpha = 0 verbose("alpha = %s" % alpha, level = 2) -## RP: This code was crashing because other may have too few moments -- so I added this bound with other's relative precision + # RP: This code was crashing because other may have too few moments -- so I added this bound with other's relative precision while i < other_pr - 1: i += 1 verbose("comparing p moment %s" % i, level = 2) @@ -656,11 +656,11 @@ cdef class Dist(ModuleElement): zero = R(0) moments.extend([zero] * (M - k - 1)) mu = V(moments) - #val = mu.valuation() - #if val < 0: - # # This seems unnatural - # print("scaling by ", p, "^", -val, " to keep things integral") - # mu *= p**(-val) + # val = mu.valuation() + # if val < 0: + # # This seems unnatural + # print("scaling by ", p, "^", -val, " to keep things integral") + # mu *= p**(-val) return mu def _is_malformed(self): @@ -1129,7 +1129,7 @@ cdef class Dist_vector(Dist): """ # assert self._moments[0][0]==0, "not total measure zero" # print("result accurate modulo p^",self.moment(0).valuation(self.p) ) - #v=[0 for j in range(0,i)]+[binomial(j,i)*bernoulli(j-i) for j in range(i,M)] + # v=[0 for j in range(0,i)]+[binomial(j,i)*bernoulli(j-i) for j in range(i,M)] M = self.precision_relative() R = self.parent().base_ring() K = R.fraction_field() @@ -1361,7 +1361,7 @@ cdef class WeightKAction_vector(WeightKAction): sage: v * D._act.actor()(g) # indirect doctest (-107, 35, -12, 5) """ - #tim = verbose("Starting") + # tim = verbose("Starting") a, b, c, d = self._adjuster(g) # if g.parent().base_ring().is_exact(): # self._check_mat(a, b, c, d) @@ -1378,17 +1378,17 @@ cdef class WeightKAction_vector(WeightKAction): return B.change_ring(self.codomain().base_ring()) R = PowerSeriesRing(base_ring, 'y', default_prec=M) y = R.gen() - #tim = verbose("Checked, made R",tim) + # tim = verbose("Checked, made R",tim) # special case for small precision, large weight scale = (b + d * y) / (a + c * y) t = (a + c * y) ** k # will already have precision M cdef long row, col - #tim = verbose("Made matrix",tim) + # tim = verbose("Made matrix",tim) for col in range(M): for row in range(M): B.set_unsafe(row, col, t[row]) t *= scale - #verbose("Finished loop",tim) + # verbose("Finished loop",tim) # the changering here is annoying, but otherwise we have to # change ring each time we multiply B = B.change_ring(self.codomain().base_ring()) diff --git a/src/sage/modular/pollack_stevens/distributions.py b/src/sage/modular/pollack_stevens/distributions.py index 80bc25b22d9..cb387ebd8c1 100644 --- a/src/sage/modular/pollack_stevens/distributions.py +++ b/src/sage/modular/pollack_stevens/distributions.py @@ -39,6 +39,7 @@ # https://www.gnu.org/licenses/ # ************************************************************************* +from sage.categories.commutative_rings import CommutativeRings from sage.categories.fields import Fields from sage.categories.modules import Modules from sage.misc.cachefunc import cached_method @@ -46,7 +47,6 @@ from sage.modules.module import Module from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ -from sage.rings.ring import Ring from sage.structure.factory import UniqueFactory from sage.structure.parent import Parent from .sigma0 import _default_adjuster @@ -281,8 +281,8 @@ def __init__(self, k, p=None, prec_cap=None, base=None, character=None, ... ValueError: p must be prime """ - if not isinstance(base, Ring): - raise TypeError("base must be a ring") + if base not in CommutativeRings(): + raise TypeError("base must be a commutative ring") # from sage.rings.padics.pow_computer import PowComputer # should eventually be the PowComputer on ZpCA once that uses longs. Dist, WeightKAction = get_dist_classes(p, prec_cap, base, @@ -649,10 +649,13 @@ def __init__(self, k, base, character, adjuster, act_on_left, dettwist, if hasattr(base, 'prime'): p = base.prime() else: - p = ZZ(0) - OverconvergentDistributions_abstract.__init__(self, k, p, k + 1, base, character, - adjuster, act_on_left, dettwist, - act_padic, implementation) + p = ZZ.zero() + OverconvergentDistributions_abstract.__init__(self, k, p, k + 1, + base, character, + adjuster, act_on_left, + dettwist, + act_padic, + implementation) def _an_element_(self): r""" diff --git a/src/sage/modular/pollack_stevens/meson.build b/src/sage/modular/pollack_stevens/meson.build index d22947db12c..0506a90ac83 100644 --- a/src/sage/modular/pollack_stevens/meson.build +++ b/src/sage/modular/pollack_stevens/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'dist.pxd', 'distributions.py', diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index e91e6950e76..d818e0f8799 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -169,11 +169,9 @@ Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring sage: D = B.decomposition() sage: D - [ - Subspace of dimension 1 of Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring, - Subspace of dimension 1 of Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring, - Subspace of dimension 2 of Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring - ] + [Subspace of dimension 1 of Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring, + Subspace of dimension 1 of Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring, + Subspace of dimension 2 of Brandt module of dimension 4 of level 43 of weight 2 over Integer Ring] sage: D[0].basis() ((0, 0, 1, -1),) sage: D[1].basis() diff --git a/src/sage/modular/ssmod/ssmod.py b/src/sage/modular/ssmod/ssmod.py index 9913e554a02..9422f33ca2e 100644 --- a/src/sage/modular/ssmod/ssmod.py +++ b/src/sage/modular/ssmod/ssmod.py @@ -11,17 +11,18 @@ sage: a = m.change_ring(GF(97)) sage: D = a.decomposition() sage: D[:3] - [ - (Vector space of degree 33 and dimension 1 over Finite Field of size 97 - Basis matrix: - [ 0 0 0 1 96 96 1 0 95 1 1 1 1 95 2 96 0 0 96 0 96 0 96 2 96 96 0 1 0 2 1 95 0], True), - (Vector space of degree 33 and dimension 1 over Finite Field of size 97 - Basis matrix: - [ 0 1 96 16 75 22 81 0 0 17 17 80 80 0 0 74 40 1 16 57 23 96 81 0 74 23 0 24 0 0 73 0 0], True), - (Vector space of degree 33 and dimension 1 over Finite Field of size 97 - Basis matrix: - [ 0 1 96 90 90 7 7 0 0 91 6 6 91 0 0 91 0 13 7 0 6 84 90 0 6 91 0 90 0 0 7 0 0], True) - ] + [(Vector space of degree 33 and dimension 1 over Finite Field of size 97 + Basis matrix: + [ 0 0 0 1 96 96 1 0 95 1 1 1 1 95 2 96 0 0 96 0 96 0 96 2 96 96 0 1 0 2 1 95 0], + True), + (Vector space of degree 33 and dimension 1 over Finite Field of size 97 + Basis matrix: + [ 0 1 96 16 75 22 81 0 0 17 17 80 80 0 0 74 40 1 16 57 23 96 81 0 74 23 0 24 0 0 73 0 0], + True), + (Vector space of degree 33 and dimension 1 over Finite Field of size 97 + Basis matrix: + [ 0 1 96 90 90 7 7 0 0 91 6 6 91 0 0 91 0 13 7 0 6 84 90 0 6 91 0 90 0 0 7 0 0], + True)] sage: len(D) 9 diff --git a/src/sage/modules/fp_graded/all.py b/src/sage/modules/fp_graded/all.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/element.py b/src/sage/modules/fp_graded/element.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/free_element.py b/src/sage/modules/fp_graded/free_element.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/free_homspace.py b/src/sage/modules/fp_graded/free_homspace.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/free_module.py b/src/sage/modules/fp_graded/free_module.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/free_morphism.py b/src/sage/modules/fp_graded/free_morphism.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/homspace.py b/src/sage/modules/fp_graded/homspace.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/module.py b/src/sage/modules/fp_graded/module.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/morphism.py b/src/sage/modules/fp_graded/morphism.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/steenrod/all.py b/src/sage/modules/fp_graded/steenrod/all.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/steenrod/homspace.py b/src/sage/modules/fp_graded/steenrod/homspace.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/steenrod/module.py b/src/sage/modules/fp_graded/steenrod/module.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/steenrod/morphism.py b/src/sage/modules/fp_graded/steenrod/morphism.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/fp_graded/steenrod/profile.py b/src/sage/modules/fp_graded/steenrod/profile.py old mode 100755 new mode 100644 diff --git a/src/sage/modules/free_module.py b/src/sage/modules/free_module.py index 6b407414030..471db14112b 100644 --- a/src/sage/modules/free_module.py +++ b/src/sage/modules/free_module.py @@ -172,7 +172,7 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ ########################################################################### import itertools @@ -185,7 +185,6 @@ import sage.rings.integer import sage.rings.integer_ring import sage.rings.rational_field -from sage.rings.ring import IntegralDomain from sage.categories.commutative_rings import CommutativeRings from sage.categories.fields import Fields from sage.categories.infinite_enumerated_sets import InfiniteEnumeratedSets @@ -296,7 +295,7 @@ def create_object(self, version, key): and base_ring.is_maximal() and base_ring.class_number() == 1): return FreeModule_ambient_pid(base_ring, rank, sparse=sparse) - if isinstance(base_ring, IntegralDomain) or base_ring in IntegralDomains(): + if base_ring in IntegralDomains(): return FreeModule_ambient_domain(base_ring, rank, sparse=sparse) return FreeModule_ambient(base_ring, rank, sparse=sparse) @@ -590,11 +589,7 @@ def VectorSpace(K, dimension_or_basis_keys=None, sparse=False, inner_product_mat sage: V Vector space of dimension 3 over Fraction Field of Univariate Polynomial Ring in x over Integer Ring sage: V.basis() - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] The base must be a field or a :exc:`TypeError` is raised. @@ -825,10 +820,7 @@ def basis_seq(V, vecs): ... ValueError: vector is immutable; please change a copy instead (use copy()) sage: sage.modules.free_module.basis_seq(V, V.gens()) - [ - (1, 0), - (0, 1) - ] + [(1, 0), (0, 1)] """ for z in vecs: z.set_immutable() @@ -898,10 +890,7 @@ class Module_free_ambient(Module): sage: M = S**2 sage: N = M.submodule([vector([x - y, z]), vector([y * z, x * z])]) sage: N.gens() - [ - (x - y, z), - (y*z, x*z) - ] + [(x - y, z), (y*z, x*z)] sage: N.degree() 2 """ @@ -2568,11 +2557,7 @@ def basis(self): EXAMPLES:: sage: FreeModule(Integers(12),3).basis() - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] """ raise NotImplementedError @@ -5012,9 +4997,7 @@ def linear_dependence(self, vectors, zeros='left', check=True): sage: v2 = vector(QQ, [1, 5, 2, -2]) sage: V = QQ^4 sage: V.linear_dependence([v1,v2]) - [ - - ] + [] sage: v3 = v1 + v2 sage: v4 = 3*v1 - 4*v2 @@ -5023,21 +5006,13 @@ def linear_dependence(self, vectors, zeros='left', check=True): sage: relations = V.linear_dependence(L, zeros='left') sage: relations - [ - (1, 0, 0, -1, -2), - (0, 1, 0, -1/2, -3/2), - (0, 0, 1, -3/2, -7/2) - ] + [(1, 0, 0, -1, -2), (0, 1, 0, -1/2, -3/2), (0, 0, 1, -3/2, -7/2)] sage: v2 + (-1/2)*v4 + (-3/2)*v5 (0, 0, 0, 0) sage: relations = V.linear_dependence(L, zeros='right') sage: relations - [ - (-1, -1, 1, 0, 0), - (-3, 4, 0, 1, 0), - (1, -2, 0, 0, 1) - ] + [(-1, -1, 1, 0, 0), (-3, 4, 0, 1, 0), (1, -2, 0, 0, 1)] sage: z = sum([relations[2][i]*L[i] for i in range(len(L))]) sage: z == zero_vector(QQ, 4) True @@ -5049,9 +5024,7 @@ def linear_dependence(self, vectors, zeros='left', check=True): sage: v2 = vector(QQ, [4,1,0]) sage: V = QQ^3 sage: relations = V.linear_dependence([v1, v2]); relations - [ - - ] + [] sage: relations == [] True @@ -5067,19 +5040,13 @@ def linear_dependence(self, vectors, zeros='left', check=True): True sage: L = [v1, v2, v3, 2*v1+v2, 3*v2+6*v3] sage: (F^5).linear_dependence(L) - [ - (1, 0, 16, 8, 3), - (0, 1, 2, 0, 11) - ] + [(1, 0, 16, 8, 3), (0, 1, 2, 0, 11)] sage: v1 + 16*v3 + 8*(2*v1+v2) + 3*(3*v2+6*v3) (0, 0, 0, 0, 0) sage: v2 + 2*v3 + 11*(3*v2+6*v3) (0, 0, 0, 0, 0) sage: (F^5).linear_dependence(L, zeros='right') - [ - (15, 16, 0, 1, 0), - (0, 14, 11, 0, 1) - ] + [(15, 16, 0, 1, 0), (0, 14, 11, 0, 1)] TESTS: @@ -5729,11 +5696,7 @@ def basis(self): EXAMPLES:: sage: A = ZZ^3; B = A.basis(); B - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: B.universe() Ambient free module of rank 3 over the principal ideal domain Integer Ring """ @@ -5757,11 +5720,7 @@ def echelonized_basis(self): EXAMPLES:: sage: A = ZZ^3; A.echelonized_basis() - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] """ return self.basis() @@ -7050,10 +7009,7 @@ def echelon_coordinates(self, v, check=True): sage: M.echelon_coordinates([8,10,12]) [8, -2] sage: B = M.echelonized_basis(); B - [ - (1, 2, 3/7), - (0, 3, -30/7) - ] + [(1, 2, 3/7), (0, 3, -30/7)] sage: 8*B[0] - 2*B[1] (8, 10, 12) @@ -7062,10 +7018,7 @@ def echelon_coordinates(self, v, check=True): sage: V = VectorSpace(QQ,5, sparse=True) sage: W = V.subspace_with_basis([[0,1,2,0,0], [0,-1,0,0,-1/2]]) sage: W.echelonized_basis() - [ - (0, 1, 0, 0, 1/2), - (0, 0, 1, 0, -1/4) - ] + [(0, 1, 0, 0, 1/2), (0, 0, 1, 0, -1/4)] sage: W.echelon_coordinates([0,0,2,0,-1/2]) [0, 2] """ @@ -7101,10 +7054,7 @@ def user_to_echelon_matrix(self): sage: A = ZZ^3 sage: M = A.span_of_basis([[1,2,3],[4,5,6]]) sage: M.echelonized_basis() - [ - (1, 2, 3), - (0, 3, 6) - ] + [(1, 2, 3), (0, 3, 6)] sage: M.user_to_echelon_matrix() [ 1 0] [ 4 -1] @@ -7150,10 +7100,7 @@ def echelon_to_user_matrix(self): sage: V = QQ^3 sage: W = V.span_of_basis([[1,2,3],[4,5,6]]) sage: W.echelonized_basis() - [ - (1, 0, -1), - (0, 1, 2) - ] + [(1, 0, -1), (0, 1, 2)] sage: A = W.echelon_to_user_matrix(); A [-5/3 2/3] [ 4/3 -1/3] @@ -7389,16 +7336,10 @@ def basis(self): sage: V = ZZ^3 sage: V.basis() - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: M = V.span_of_basis([['1/8',2,1]]) sage: M.basis() - [ - (1/8, 2, 1) - ] + [(1/8, 2, 1)] """ return self.__basis @@ -7507,15 +7448,9 @@ def echelonized_basis(self): sage: V = ZZ^3 sage: M = V.span_of_basis([['1/2',3,1], [0,'1/6',0]]) sage: M.basis() - [ - (1/2, 3, 1), - (0, 1/6, 0) - ] + [(1/2, 3, 1), (0, 1/6, 0)] sage: B = M.echelonized_basis(); B - [ - (1/2, 0, 1), - (0, 1/6, 0) - ] + [(1/2, 0, 1), (0, 1/6, 0)] sage: V.span(B) == M True """ @@ -7546,10 +7481,7 @@ def echelon_coordinate_vector(self, v, check=True): sage: V = ZZ^3 sage: M = V.span_of_basis([['1/2',3,1], [0,'1/6',0]]) sage: B = M.echelonized_basis(); B - [ - (1/2, 0, 1), - (0, 1/6, 0) - ] + [(1/2, 0, 1), (0, 1/6, 0)] sage: M.echelon_coordinate_vector(['1/2', 3, 1]) (1, 18) """ diff --git a/src/sage/modules/free_module_element.pxd b/src/sage/modules/free_module_element.pxd index 084423a2714..25585564228 100644 --- a/src/sage/modules/free_module_element.pxd +++ b/src/sage/modules/free_module_element.pxd @@ -19,4 +19,3 @@ cdef class FreeModuleElement_generic_sparse(FreeModuleElement): # cdef'd methods cdef _new_c(self, object v) - diff --git a/src/sage/modules/free_module_element.pyx b/src/sage/modules/free_module_element.pyx index f840143a073..a9d074007f0 100644 --- a/src/sage/modules/free_module_element.pyx +++ b/src/sage/modules/free_module_element.pyx @@ -3451,7 +3451,7 @@ cdef class FreeModuleElement(Vector): # abstract base class The more general :meth:`sage.matrix.matrix2.tensor_product` is an operation on a pair of matrices. If we construct a pair of vectors as a column vector and a row vector, then an outer product and a - tensor product are identical. Thus `tensor_product` is a synonym + tensor product are identical. Thus ``tensor_product`` is a synonym for this method. :: sage: u = vector(QQ, [1/2, 1/3, 1/4, 1/5]) @@ -4047,7 +4047,7 @@ cdef class FreeModuleElement(Vector): # abstract base class Differentiate with respect to var by differentiating each element with respect to var. - .. seealso: + .. SEEALSO:: :meth:`derivative` diff --git a/src/sage/modules/free_module_morphism.py b/src/sage/modules/free_module_morphism.py index efdbc607c09..b08d78e563b 100644 --- a/src/sage/modules/free_module_morphism.py +++ b/src/sage/modules/free_module_morphism.py @@ -542,27 +542,25 @@ def eigenvectors(self, extend=True): sage: V = (QQ^4).subspace([[0,2,1,4], [1,2,5,0], [1,1,1,1]]) sage: H = (V.Hom(V))(matrix(QQ, [[0,1,0], [-1,0,0], [0,0,3]])) sage: H.eigenvectors() - [(3, [ (0, 0, 1, -6/7) ], 1), - (-1*I, [ (1, 1*I, 0, -0.571428571428572? + 2.428571428571429?*I) ], 1), - (1*I, [ (1, -1*I, 0, -0.571428571428572? - 2.428571428571429?*I) ], 1)] + [(3, [(0, 0, 1, -6/7)], 1), + (-1*I, [(1, 1*I, 0, -0.571428571428572? + 2.428571428571429?*I)], 1), + (1*I, [(1, -1*I, 0, -0.571428571428572? - 2.428571428571429?*I)], 1)] sage: H.eigenvectors(extend=False) - [(3, [ (0, 0, 1, -6/7) ], 1)] + [(3, [(0, 0, 1, -6/7)], 1)] sage: H1 = (V.Hom(V))(matrix(QQ, [[2,1,0],[0,2,0],[0,0,3]])) sage: H1.eigenvectors() - [(3, [ (0, 0, 1, -6/7) ], 1), - (2, [ (0, 1, 0, 17/7) ], 2)] + [(3, [(0, 0, 1, -6/7)], 1), (2, [(0, 1, 0, 17/7)], 2)] sage: H1.eigenvectors(extend=False) - [(3, [ (0, 0, 1, -6/7) ], 1), - (2, [ (0, 1, 0, 17/7) ], 2)] + [(3, [(0, 0, 1, -6/7)], 1), (2, [(0, 1, 0, 17/7)], 2)] :: sage: V = QQ^2 sage: m = matrix(2, [1, 1, 0, 1]) sage: V.hom(m, side='right').eigenvectors() # needs sage.rings.number_field - [(1, [ (1, 0) ], 2)] + [(1, [(1, 0)], 2)] sage: V.hom(m).eigenvectors() # needs sage.rings.number_field - [(1, [ (0, 1) ], 2)] + [(1, [(0, 1)], 2)] """ if self.base_ring().is_field(): if self.is_endomorphism(): diff --git a/src/sage/modules/free_quadratic_module.py b/src/sage/modules/free_quadratic_module.py index a209ae79ee4..8e583284823 100644 --- a/src/sage/modules/free_quadratic_module.py +++ b/src/sage/modules/free_quadratic_module.py @@ -69,8 +69,9 @@ from sage.categories.commutative_rings import CommutativeRings from sage.categories.principal_ideal_domains import PrincipalIdealDomains +from sage.categories.integral_domains import IntegralDomains from sage.modules import free_module -from sage.rings.ring import Field, IntegralDomain +from sage.rings.ring import Field import sage.matrix.matrix_space import sage.misc.latex as latex @@ -175,7 +176,7 @@ def FreeQuadraticModule(base_ring, rank, inner_product_matrix, M = FreeQuadraticModule_ambient_pid( base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) - elif isinstance(base_ring, IntegralDomain) or base_ring.is_integral_domain(): + elif base_ring in IntegralDomains(): M = FreeQuadraticModule_ambient_domain( base_ring, rank, sparse=sparse, inner_product_matrix=inner_product_matrix) else: @@ -203,11 +204,7 @@ def QuadraticSpace(K, dimension, inner_product_matrix, sparse=False): [ 0 x - 1 0] [ 0 0 x + 1] sage: V.basis() - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] The base must be a field or a :exc:`TypeError` is raised:: diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index c58f0f3ea1e..3f6a34e778c 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -1556,7 +1556,7 @@ def _fplll_enumerate(self, target=None): gmat = fpylll.IntegerMatrix(dim, dim) for i in range(dim): for j in range(dim): - gmat[i,j] = gram[i,j] + gmat[i, j] = gram[i, j] gso = fpylll.GSO.Mat(gmat, gram=True) ok = gso.update_gso() assert ok @@ -1564,11 +1564,12 @@ def _fplll_enumerate(self, target=None): coord = None if target is not None: coord = basis.solve_left(target) - Mu = 1 + matrix([gso.get_mu(i,j) for j in range(dim)] for i in range(dim)) + Mu = 1 + matrix([gso.get_mu(i, j) for j in range(dim)] + for i in range(dim)) coord *= Mu count = 8 - bound = gso.get_r(dim-1, dim-1) + bound = gso.get_r(dim - 1, dim - 1) seen = set() while True: enum = fpylll.Enumeration(gso, count, fpylll.EvaluatorStrategy.BEST_N_SOLUTIONS) @@ -1579,8 +1580,8 @@ def _fplll_enumerate(self, target=None): if len(combs) < count: bound *= 2 continue - for length,comb in combs: - vec = sum(ZZ(c)*b for c,b in zip(comb,basis)) + for length, comb in combs: + vec = sum(ZZ(c) * b for c, b in zip(comb, basis)) if tuple(vec) not in seen: yield vec seen.add(tuple(vec)) diff --git a/src/sage/modules/matrix_morphism.py b/src/sage/modules/matrix_morphism.py index 175d152f364..f5a067e27ab 100644 --- a/src/sage/modules/matrix_morphism.py +++ b/src/sage/modules/matrix_morphism.py @@ -828,24 +828,20 @@ def decomposition(self, *args, **kwds): sage: V = ZZ^2; phi = V.hom([V.0+V.1, 2*V.1]) sage: phi.decomposition() # needs sage.libs.pari - [ - Free module of degree 2 and rank 1 over Integer Ring - Echelon basis matrix: - [0 1], - Free module of degree 2 and rank 1 over Integer Ring - Echelon basis matrix: - [ 1 -1] - ] + [Free module of degree 2 and rank 1 over Integer Ring + Echelon basis matrix: + [0 1], + Free module of degree 2 and rank 1 over Integer Ring + Echelon basis matrix: + [ 1 -1]] sage: phi2 = V.hom(phi.matrix(), side='right') sage: phi2.decomposition() # needs sage.libs.pari - [ - Free module of degree 2 and rank 1 over Integer Ring - Echelon basis matrix: - [1 1], - Free module of degree 2 and rank 1 over Integer Ring - Echelon basis matrix: - [1 0] - ] + [Free module of degree 2 and rank 1 over Integer Ring + Echelon basis matrix: + [1 1], + Free module of degree 2 and rank 1 over Integer Ring + Echelon basis matrix: + [1 0]] """ if not self.is_endomorphism(): raise ArithmeticError("matrix morphism must be an endomorphism") diff --git a/src/sage/modules/meson.build b/src/sage/modules/meson.build index bc505da9372..a5c78e98633 100644 --- a/src/sage/modules/meson.build +++ b/src/sage/modules/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'complex_double_vector.py', 'diamond_cutting.py', @@ -16,6 +17,7 @@ py.install_sources( 'module.pxd', 'module_functors.py', 'multi_filtered_vector_space.py', + 'numpy_util.pxd', 'quotient_module.py', 'real_double_vector.py', 'submodule.py', @@ -76,7 +78,10 @@ foreach name, pyx : extension_data ) endforeach -extension_data_cpp = {'vector_mod2_dense': files('vector_mod2_dense.pyx')} +extension_data_cpp = { + 'numpy_util' : files('numpy_util.pyx'), + 'vector_mod2_dense': files('vector_mod2_dense.pyx'), +} foreach name, pyx : extension_data_cpp py.extension_module( diff --git a/src/sage/modules/numpy_util.pxd b/src/sage/modules/numpy_util.pxd new file mode 100644 index 00000000000..8bd53e81347 --- /dev/null +++ b/src/sage/modules/numpy_util.pxd @@ -0,0 +1,9 @@ +from libc.stdint cimport uintptr_t +from sage.libs.m4ri cimport * +from sage.matrix.matrix_mod2_dense cimport Matrix_mod2_dense + +cpdef int set_matrix_mod2_from_numpy(Matrix_mod2_dense a, b) except -1 + +cpdef int set_mzd_from_numpy(uintptr_t entries_addr, Py_ssize_t degree, x) except -1 +# Note: we don't actually need ``cimport`` to work, which means this header file is not used in practice +# neither do we need ``cpdef`` (``def`` is sufficient) diff --git a/src/sage/modules/numpy_util.pyx b/src/sage/modules/numpy_util.pyx new file mode 100644 index 00000000000..a20f173a17d --- /dev/null +++ b/src/sage/modules/numpy_util.pyx @@ -0,0 +1,135 @@ +# sage.doctest: optional - numpy +# cython: fast_getattr=False +# https://github.com/cython/cython/issues/6442 +r""" +Utility functions for numpy. +""" + +cimport numpy as np +import numpy as np + + +ctypedef fused numpy_integral: + np.int8_t + np.int32_t + np.int64_t + + +cdef set_mzd_from_numpy_unsafe(mzd_t* entries, np.ndarray[numpy_integral, ndim=1] x): + """ + Internal function. + Caller are responsible for checking the two arrays have the same length. + """ + for i in range(len(x)): + mzd_write_bit(entries, 0, i, x[i] & 1) + + +cpdef int set_mzd_from_numpy(uintptr_t entries_addr, Py_ssize_t degree, x) except -1: + """ + Set the entries in ``entries_addr`` from numpy array ``x``. + + INPUT: + + - ``entries_addr`` -- must be a ``mzd_t*`` casted to ``uintptr_t``; the casting + is necessary to pass it through Python boundary because of lazy import. + Do not pass arbitrary integer value here, will crash the program. + + - ``degree`` -- the length of the array + + - ``x`` -- a numpy array of integers or booleans, or any other object (in which + case this function will return ``False``) + + OUTPUT: ``True`` if successful, ``False`` otherwise. May throw ``ValueError``. + """ + cdef Py_ssize_t i + cdef np.ndarray[np.npy_bool, ndim=1] x_bool + cdef mzd_t* entries = entries_addr + if isinstance(x, np.ndarray): + if x.ndim != 1: + raise ValueError("numpy array must have dimension 1") + if x.shape[0] != degree: + raise ValueError("numpy array must have the right length") + if x.dtype == np.int8: + set_mzd_from_numpy_unsafe(entries, x) + return True + if x.dtype == np.int32: + set_mzd_from_numpy_unsafe(entries, x) + return True + if x.dtype == np.int64: + set_mzd_from_numpy_unsafe(entries, x) + return True + if x.dtype == np.bool_: + x_bool = x + for i in range(degree): + mzd_write_bit(entries, 0, i, x_bool[i]) + return True + return False + + +cpdef int _set_matrix_mod2_from_numpy_helper(Matrix_mod2_dense a, np.ndarray[numpy_integral, ndim=2] b) except -1: + """ + Internal function, helper for :func:`set_matrix_mod2_from_numpy`. + + TESTS:: + + sage: from sage.modules.numpy_util import _set_matrix_mod2_from_numpy_helper + sage: import numpy as np + sage: a = matrix(GF(2), 2, 3) + sage: b = np.array([[1, 0, 1], [0, 1, 0]], dtype=np.int8) + sage: _set_matrix_mod2_from_numpy_helper(a, b) + 1 + sage: a + [1 0 1] + [0 1 0] + sage: _set_matrix_mod2_from_numpy_helper(a, np.array([[1, 0], [0, 1]], dtype=np.int8)) + Traceback (most recent call last): + ... + ValueError: shape mismatch + """ + if not (a.nrows() == b.shape[0] and a.ncols() == b.shape[1]): + raise ValueError("shape mismatch") + for i in range(b.shape[0]): + for j in range(b.shape[1]): + a.set_unsafe_int(i, j, b[i, j] & 1) + return True + + +cpdef int set_matrix_mod2_from_numpy(Matrix_mod2_dense a, b) except -1: + """ + Try to set the entries of a matrix from a numpy array. + + INPUT: + + - ``a`` -- the destination matrix + - ``b`` -- a numpy array, must have dimension 2 and the same shape as ``a`` + + OUTPUT: ``True`` (when used as bool) if successful, ``False`` otherwise. May throw ``ValueError``. + + The exact type of the return value is not guaranteed, in the actual current implementation + it is ``1`` for success and ``0`` for failure. + + TESTS:: + + sage: from sage.modules.numpy_util import set_matrix_mod2_from_numpy + sage: import numpy as np + sage: a = matrix(GF(2), 2, 3) + sage: b = np.array([[1, 0, 1], [0, 1, 0]], dtype=np.int8) + sage: set_matrix_mod2_from_numpy(a, b) + 1 + sage: a + [1 0 1] + [0 1 0] + sage: set_matrix_mod2_from_numpy(a, np.array([[1, 0], [0, 1]], dtype=np.int8)) + Traceback (most recent call last): + ... + ValueError: shape mismatch + sage: # unsupported type (may be supported in the future) + sage: set_matrix_mod2_from_numpy(a, np.array([[1, 1, 0], [0, 1, 0]], dtype=np.float64)) + 0 + sage: set_matrix_mod2_from_numpy(a, np.array([1, 0, 0], dtype=np.int8)) # wrong number of dimensions + 0 + """ + try: + return (_set_matrix_mod2_from_numpy_helper)(a, b) # https://github.com/cython/cython/issues/6588 + except TypeError: + return False diff --git a/src/sage/modules/submodule.py b/src/sage/modules/submodule.py index 12ad915646a..be2868c3dca 100644 --- a/src/sage/modules/submodule.py +++ b/src/sage/modules/submodule.py @@ -214,10 +214,7 @@ def gens(self) -> list: sage: M = S**2 sage: N = M.submodule([vector([x - y, z]), vector([y * z, x * z])]) sage: N.gens() - [ - (x - y, z), - (y*z, x*z) - ] + [(x - y, z), (y*z, x*z)] """ return self.__gens diff --git a/src/sage/modules/vector_mod2_dense.pyx b/src/sage/modules/vector_mod2_dense.pyx index ca14af9b313..c3af2ad51f8 100644 --- a/src/sage/modules/vector_mod2_dense.pyx +++ b/src/sage/modules/vector_mod2_dense.pyx @@ -46,6 +46,7 @@ from sage.rings.rational cimport Rational from sage.structure.element cimport Element, Vector from sage.structure.richcmp cimport rich_to_bool cimport sage.modules.free_module_element as free_module_element +from libc.stdint cimport uintptr_t from sage.libs.m4ri cimport * @@ -192,8 +193,44 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): TypeError: can...t initialize vector from nonzero non-list sage: (GF(2)**0).zero_vector() () + + Check construction from numpy arrays:: + + sage: # needs numpy + sage: import numpy + sage: VS = VectorSpace(GF(2),3) + sage: VS(numpy.array([0,-3,7], dtype=numpy.int8)) + (0, 1, 1) + sage: VS(numpy.array([0,-3,7], dtype=numpy.int32)) + (0, 1, 1) + sage: VS(numpy.array([0,-3,7], dtype=numpy.int64)) + (0, 1, 1) + sage: VS(numpy.array([False,True,False], dtype=bool)) + (0, 1, 0) + sage: VS(numpy.array([[1]])) + Traceback (most recent call last): + ... + ValueError: numpy array must have dimension 1 + sage: VS(numpy.array([1,2,3,4])) + Traceback (most recent call last): + ... + ValueError: numpy array must have the right length + + Make sure it's reasonably fast:: + + sage: # needs numpy + sage: import numpy + sage: VS = VectorSpace(GF(2),2*10^7) + sage: v = VS(numpy.random.randint(0, 1, size=VS.dimension())) # around 300ms """ - cdef Py_ssize_t i + try: + import numpy + except ImportError: + pass + else: + from .numpy_util import set_mzd_from_numpy + if set_mzd_from_numpy(self._entries, self._degree, x): + return if isinstance(x, (list, tuple)): if len(x) != self._degree: raise TypeError("x must be a list of the right length") @@ -381,7 +418,7 @@ cdef class Vector_mod2_dense(free_module_element.FreeModuleElement): cdef IntegerMod_int n cdef Vector_mod2_dense r = right cdef m4ri_word tmp = 0 - n = IntegerMod_int.__new__(IntegerMod_int) + n = IntegerMod_int.__new__(IntegerMod_int) IntegerMod_abstract.__init__(n, self.base_ring()) n.ivalue = 0 cdef m4ri_word *lrow = mzd_row(self._entries, 0) diff --git a/src/sage/modules/vector_modn_dense.pyx b/src/sage/modules/vector_modn_dense.pyx index f129632bd03..936317049b3 100644 --- a/src/sage/modules/vector_modn_dense.pyx +++ b/src/sage/modules/vector_modn_dense.pyx @@ -315,7 +315,7 @@ cdef class Vector_modn_dense(free_module_element.FreeModuleElement): cdef Vector_modn_dense r = right if use_32bit_type(self._p): - n = IntegerMod_int.__new__(IntegerMod_int) + n = IntegerMod_int.__new__(IntegerMod_int) IntegerMod_abstract.__init__(n, self.base_ring()) n.ivalue = 0 for i in range(self._degree): diff --git a/src/sage/modules/with_basis/cell_module.py b/src/sage/modules/with_basis/cell_module.py index 7c61057737c..35528c1407e 100644 --- a/src/sage/modules/with_basis/cell_module.py +++ b/src/sage/modules/with_basis/cell_module.py @@ -348,7 +348,7 @@ def _acted_upon_(self, scalar, self_on_left=False): sage: 1/2 * elt W[[1, 2], [3]] + W[[1, 3], [2]] """ - # Check for elements coercable to the base ring first + # Check for elements coercible to the base ring first ret = CombinatorialFreeModule.Element._acted_upon_(self, scalar, self_on_left) if ret is not None: return ret diff --git a/src/sage/modules/with_basis/meson.build b/src/sage/modules/with_basis/meson.build index 1956c6ac99c..7dc1dda551b 100644 --- a/src/sage/modules/with_basis/meson.build +++ b/src/sage/modules/with_basis/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'cell_module.py', 'indexed_element.pxd', diff --git a/src/sage/modules/with_basis/representation.py b/src/sage/modules/with_basis/representation.py index 5271c7a6b38..61e65409e21 100644 --- a/src/sage/modules/with_basis/representation.py +++ b/src/sage/modules/with_basis/representation.py @@ -21,12 +21,12 @@ from sage.misc.cachefunc import cached_method from sage.structure.element import Element from sage.combinat.free_module import CombinatorialFreeModule, CombinatorialFreeModule_Tensor -from sage.modules.with_basis.subquotient import SubmoduleWithBasis from sage.categories.modules import Modules from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector from sage.modules.with_basis.subquotient import SubmoduleWithBasis, QuotientModuleWithBasis + class Representation_abstract: """ Abstract base class for representations of semigroups. @@ -1894,7 +1894,7 @@ def __init__(self, rep, degree, **options): R = rep.base_ring() dim = rep.dimension() if degree not in ZZ or degree < 0: - raise ValueError(f"the degree must be a nonnegative integer") + raise ValueError("the degree must be a nonnegative integer") self._symalg = PolynomialRing(R, 'e', dim) self._basis_order = list(rep.basis().keys()) G = self._symalg.gens() diff --git a/src/sage/monoids/free_monoid.py b/src/sage/monoids/free_monoid.py index e7a2a9f6532..32196e004dc 100644 --- a/src/sage/monoids/free_monoid.py +++ b/src/sage/monoids/free_monoid.py @@ -241,12 +241,26 @@ def _element_constructor_(self, x, check=True): sage: F(F(w), check=False) a^2*b^2*c*a*b*a*c + + sage: F = FreeMonoid(3, 'a,b,c') + sage: G = FreeMonoid(2, 'a,c') + sage: F(G(Word("ac"))) + a*c """ # There should really be some careful type checking here... - if isinstance(x, FreeMonoidElement) and x.parent() is self: - return x - if isinstance(x, FreeMonoidElement) and x.parent() == self: - return self.element_class(self, x._element_list, check) + if isinstance(x, FreeMonoidElement): + P = x.parent() + if P is self: + return x + elif P == self: + return self.element_class(self, x._element_list, check) + elif all(v in self.variable_names() + for v in P.variable_names()): + reindex = [next(j for j, w in enumerate(self.variable_names()) + if v == w) + for v in P.variable_names()] + elt = [(reindex[i], exp) for i, exp in x._element_list] + return self.element_class(self, elt, check) if isinstance(x, (int, Integer)) and x == 1: return self.element_class(self, x, check) if isinstance(x, FiniteWord_class): diff --git a/src/sage/monoids/indexed_free_monoid.py b/src/sage/monoids/indexed_free_monoid.py index 69b67e260f7..8f6efea8487 100644 --- a/src/sage/monoids/indexed_free_monoid.py +++ b/src/sage/monoids/indexed_free_monoid.py @@ -674,6 +674,7 @@ def dict(self): """ return copy(self._monomial) + class IndexedMonoid(Parent, IndexedGenerators, UniqueRepresentation): """ Base class for monoids with an indexed set of generators. @@ -859,6 +860,7 @@ def monoid_generators(self): gens = monoid_generators + class IndexedFreeMonoid(IndexedMonoid): """ Free monoid with an indexed set of generators. @@ -939,6 +941,7 @@ def gen(self, x): except (ValueError, TypeError, NotImplementedError): # Backup (e.g., if it is a string) return self.element_class(self, ((x, ZZ.one()),)) + class IndexedFreeAbelianMonoid(IndexedMonoid): """ Free abelian monoid with an indexed set of generators. diff --git a/src/sage/monoids/meson.build b/src/sage/monoids/meson.build index df2a4ae36be..5f785b5b257 100644 --- a/src/sage/monoids/meson.build +++ b/src/sage/monoids/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'automatic_semigroup.py', 'free_abelian_monoid.py', diff --git a/src/sage/numerical/backends/cvxpy_backend_test.py b/src/sage/numerical/backends/cvxpy_backend_test.py index 1f5f030248e..d186a1054ce 100644 --- a/src/sage/numerical/backends/cvxpy_backend_test.py +++ b/src/sage/numerical/backends/cvxpy_backend_test.py @@ -3,6 +3,7 @@ from sage.numerical.backends.generic_backend import GenericBackend from sage.numerical.mip import MixedIntegerLinearProgram + @pytest.importorskip("cvxpy") class TestCVXPYBackend(GenericBackendTests): diff --git a/src/sage/numerical/backends/generic_backend.pyx b/src/sage/numerical/backends/generic_backend.pyx index b7962c3c877..edda183ade9 100644 --- a/src/sage/numerical/backends/generic_backend.pyx +++ b/src/sage/numerical/backends/generic_backend.pyx @@ -265,7 +265,7 @@ cdef class GenericBackend: @classmethod def _test_sense(cls, tester=None, **options): """ - Run tests on `set_sense` and `is_maximization`. + Run tests on ``set_sense`` and ``is_maximization``. TESTS:: diff --git a/src/sage/numerical/backends/generic_backend_test.py b/src/sage/numerical/backends/generic_backend_test.py index 2b5411fb64e..64c9eb44670 100644 --- a/src/sage/numerical/backends/generic_backend_test.py +++ b/src/sage/numerical/backends/generic_backend_test.py @@ -3,6 +3,7 @@ from sage.structure.sage_object import SageObject from sage.structure.sage_object_test import SageObjectTests + class GenericBackendTests(SageObjectTests): @pytest.fixture diff --git a/src/sage/numerical/backends/glpk_backend.pyx b/src/sage/numerical/backends/glpk_backend.pyx index 5e1f0dcdf82..c70ac0bb0e0 100644 --- a/src/sage/numerical/backends/glpk_backend.pyx +++ b/src/sage/numerical/backends/glpk_backend.pyx @@ -364,7 +364,7 @@ cdef class GLPKBackend(GenericBackend): cdef char * n if name is None: - n = glp_get_prob_name(self.lp) + n = glp_get_prob_name(self.lp) if n == NULL: return "" else: @@ -1446,7 +1446,7 @@ cdef class GLPKBackend(GenericBackend): ... ValueError: invalid row index 2 """ - cdef char * s + cdef char * s if index < 0 or index > (self.nrows() - 1): raise ValueError("invalid row index %d" % index) @@ -3197,60 +3197,60 @@ solver_parameter_values = { 'intopt_only': intopt_only, 'exact_simplex_only': exact_simplex_only, - 'GLP_MSG_OFF' : GLP_MSG_OFF, - 'GLP_MSG_ON' : GLP_MSG_ON, - 'GLP_MSG_ERR' : GLP_MSG_ERR, - 'GLP_MSG_ALL' : GLP_MSG_ALL, - 'GLP_MSG_DBG' : GLP_MSG_DBG, - - 'GLP_PRIMAL' : GLP_PRIMAL, - 'GLP_DUAL' : GLP_DUAL, - 'GLP_DUALP' : GLP_DUALP, - - 'GLP_PT_STD' : GLP_PT_STD, - 'GLP_PT_PSE' : GLP_PT_PSE, - - 'GLP_RT_STD' : GLP_RT_STD, - 'GLP_RT_HAR' : GLP_RT_HAR, - - 'DBL_MAX' : DBL_MAX, - 'INT_MAX' : INT_MAX, - - 'GLP_ON' : GLP_ON, - 'GLP_OFF' : GLP_OFF, - - 'GLP_BR_FFV' : GLP_BR_FFV, - 'GLP_BR_LFV' : GLP_BR_LFV, - 'GLP_BR_MFV' : GLP_BR_MFV, - 'GLP_BR_DTH' : GLP_BR_DTH, - 'GLP_BR_PCH' : GLP_BR_PCH, - - 'GLP_BT_DFS' : GLP_BT_DFS, - 'GLP_BT_BFS' : GLP_BT_BFS, - 'GLP_BT_BLB' : GLP_BT_BLB, - 'GLP_BT_BPH' : GLP_BT_BPH, - - 'GLP_PP_NONE' : GLP_PP_NONE, - 'GLP_PP_ROOT' : GLP_PP_ROOT, - 'GLP_PP_ALL' : GLP_PP_ALL, - - 'GLP_MAX' : GLP_MAX, - 'GLP_MIN' : GLP_MIN, - 'GLP_UP' : GLP_UP, - 'GLP_FR' : GLP_FR, - 'GLP_DB' : GLP_DB, - 'GLP_FX' : GLP_FX, - 'GLP_LO' : GLP_LO, - 'GLP_CV' : GLP_CV, - 'GLP_IV' : GLP_IV, - 'GLP_BV' : GLP_BV, - 'GLP_MPS_DECK' : GLP_MPS_DECK, - 'GLP_MPS_FILE' : GLP_MPS_FILE, - - 'GLP_UNDEF' : GLP_UNDEF, - 'GLP_OPT' : GLP_OPT, - 'GLP_FEAS' : GLP_FEAS, - 'GLP_NOFEAS' : GLP_NOFEAS + 'GLP_MSG_OFF': GLP_MSG_OFF, + 'GLP_MSG_ON': GLP_MSG_ON, + 'GLP_MSG_ERR': GLP_MSG_ERR, + 'GLP_MSG_ALL': GLP_MSG_ALL, + 'GLP_MSG_DBG': GLP_MSG_DBG, + + 'GLP_PRIMAL': GLP_PRIMAL, + 'GLP_DUAL': GLP_DUAL, + 'GLP_DUALP': GLP_DUALP, + + 'GLP_PT_STD': GLP_PT_STD, + 'GLP_PT_PSE': GLP_PT_PSE, + + 'GLP_RT_STD': GLP_RT_STD, + 'GLP_RT_HAR': GLP_RT_HAR, + + 'DBL_MAX': DBL_MAX, + 'INT_MAX': INT_MAX, + + 'GLP_ON': GLP_ON, + 'GLP_OFF': GLP_OFF, + + 'GLP_BR_FFV': GLP_BR_FFV, + 'GLP_BR_LFV': GLP_BR_LFV, + 'GLP_BR_MFV': GLP_BR_MFV, + 'GLP_BR_DTH': GLP_BR_DTH, + 'GLP_BR_PCH': GLP_BR_PCH, + + 'GLP_BT_DFS': GLP_BT_DFS, + 'GLP_BT_BFS': GLP_BT_BFS, + 'GLP_BT_BLB': GLP_BT_BLB, + 'GLP_BT_BPH': GLP_BT_BPH, + + 'GLP_PP_NONE': GLP_PP_NONE, + 'GLP_PP_ROOT': GLP_PP_ROOT, + 'GLP_PP_ALL': GLP_PP_ALL, + + 'GLP_MAX': GLP_MAX, + 'GLP_MIN': GLP_MIN, + 'GLP_UP': GLP_UP, + 'GLP_FR': GLP_FR, + 'GLP_DB': GLP_DB, + 'GLP_FX': GLP_FX, + 'GLP_LO': GLP_LO, + 'GLP_CV': GLP_CV, + 'GLP_IV': GLP_IV, + 'GLP_BV': GLP_BV, + 'GLP_MPS_DECK': GLP_MPS_DECK, + 'GLP_MPS_FILE': GLP_MPS_FILE, + + 'GLP_UNDEF': GLP_UNDEF, + 'GLP_OPT': GLP_OPT, + 'GLP_FEAS': GLP_FEAS, + 'GLP_NOFEAS': GLP_NOFEAS } diff --git a/src/sage/numerical/backends/glpk_exact_backend_test.py b/src/sage/numerical/backends/glpk_exact_backend_test.py index 125e041f29e..67b169baa82 100644 --- a/src/sage/numerical/backends/glpk_exact_backend_test.py +++ b/src/sage/numerical/backends/glpk_exact_backend_test.py @@ -3,6 +3,7 @@ from sage.numerical.backends.generic_backend import GenericBackend from sage.numerical.mip import MixedIntegerLinearProgram + class TestGLPKExactBackend(GenericBackendTests): @pytest.fixture diff --git a/src/sage/numerical/backends/interactivelp_backend_test.py b/src/sage/numerical/backends/interactivelp_backend_test.py index 5523c40ce1f..d0e4b091563 100644 --- a/src/sage/numerical/backends/interactivelp_backend_test.py +++ b/src/sage/numerical/backends/interactivelp_backend_test.py @@ -3,6 +3,7 @@ from sage.numerical.backends.generic_backend import GenericBackend from sage.numerical.mip import MixedIntegerLinearProgram + class TestInteractiveLPBackend(GenericBackendTests): @pytest.fixture diff --git a/src/sage/numerical/backends/logging_backend.py b/src/sage/numerical/backends/logging_backend.py index d2d7bd98299..ae0c6b22d36 100644 --- a/src/sage/numerical/backends/logging_backend.py +++ b/src/sage/numerical/backends/logging_backend.py @@ -7,19 +7,20 @@ See :class:`LoggingBackendFactory` for more information. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 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. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.numerical.backends.generic_backend import GenericBackend + def _format_function_call(fn_name, *v, **k): """ Return a Python function call as a string. @@ -30,9 +31,10 @@ def _format_function_call(fn_name, *v, **k): sage: _format_function_call('foo', 17, hellooooo='goodbyeeee') "foo(17, hellooooo='goodbyeeee')" """ - args = [ repr(a) for a in v ] + [ "%s=%r" % (arg,val) for arg, val in k.items() ] + args = [repr(a) for a in v] + ["%s=%r" % (arg, val) for arg, val in k.items()] return "{}({})".format(fn_name, ", ".join(args)) + def _make_wrapper(backend, attr): """ Return a wrapper for the backend method named by ``attr`` that does the logging. @@ -90,6 +92,7 @@ def m(self, *args, **kwdargs): update_wrapper(m, getattr(backend, attr)) return m + class LoggingBackend(GenericBackend): """ See :class:`LoggingBackendFactory` for documentation. @@ -232,6 +235,7 @@ def _test_{name}(cls, tester=None, **options): from sage.rings.rational_field import QQ + def LoggingBackendFactory(solver=None, printing=True, doctest_file=None, test_method_file=None, test_method=None, base_ring=QQ): """ @@ -355,15 +359,15 @@ def LoggingBackendFactory(solver=None, printing=True, doctest_file=None, test_me # Construct output file name from method name. test_method_file = "test_{}.py".format(test_method) else: - test_method = 'CHANGE' # Will have to be edited by user in - # generated file. + test_method = 'CHANGE' + # Will have to be edited by user in generated file. if doctest_file is not None: - doctest = open(doctest_file, "w", 1) #line-buffered + doctest = open(doctest_file, "w", 1) # line-buffered else: doctest = None if test_method_file is not None: - test_method_output = open(test_method_file, "w", 1) #line-buffered + test_method_output = open(test_method_file, "w", 1) # line-buffered else: test_method_output = None diff --git a/src/sage/numerical/backends/meson.build b/src/sage/numerical/backends/meson.build index a6a53e97033..57eeaeb10b0 100644 --- a/src/sage/numerical/backends/meson.build +++ b/src/sage/numerical/backends/meson.build @@ -2,6 +2,7 @@ glpk = cc.find_library('glpk') py.install_sources( + '__init__.py', 'all.py', 'all__sagemath_polyhedra.py', 'cvxopt_backend_test.py', diff --git a/src/sage/numerical/backends/scip_backend_test.py b/src/sage/numerical/backends/scip_backend_test.py index 136d3ce914b..f10f6edee46 100644 --- a/src/sage/numerical/backends/scip_backend_test.py +++ b/src/sage/numerical/backends/scip_backend_test.py @@ -3,6 +3,7 @@ from sage.numerical.backends.generic_backend import GenericBackend from sage.numerical.mip import MixedIntegerLinearProgram + @pytest.importorskip("pyscipopt") class TestSCIPBackend(GenericBackendTests): diff --git a/src/sage/numerical/interactive_simplex_method.py b/src/sage/numerical/interactive_simplex_method.py index a89da826c77..e394224a3c9 100644 --- a/src/sage/numerical/interactive_simplex_method.py +++ b/src/sage/numerical/interactive_simplex_method.py @@ -213,6 +213,7 @@ # will have to be left. generate_real_LaTeX = False + def _assemble_arrayl(lines, stretch=None): r""" Return ``lines`` assembled in a left-justified array. @@ -442,6 +443,7 @@ def variable(R, v): current_style = 'UAlberta' + def default_variable_name(variable): r""" Return default variable name for the current :func:`style`. @@ -465,6 +467,7 @@ def default_variable_name(variable): """ return available_styles[current_style][variable] + def style(new_style=None): r""" Set or get the current style of problems and dictionaries. @@ -1535,7 +1538,7 @@ def plot(self, *args, **kwds): result += line(level.vertices(), color='black', linestyle='--') result.set_axes_range(xmin, xmax, ymin, ymax) - result.axes_labels(FP.axes_labels()) #FIXME: should be preserved! + result.axes_labels(FP.axes_labels()) # FIXME: should be preserved! return result def plot_feasible_set(self, xmin=None, xmax=None, ymin=None, ymax=None, @@ -3704,6 +3707,7 @@ def update(self): 5000 """ + class LPDictionary(LPAbstractDictionary): r""" Construct a dictionary for an LP problem. @@ -3929,7 +3933,7 @@ def _latex_(self): lines.append(r"\renewcommand{\arraystretch}{1.5} %notruncate") if generate_real_LaTeX: lines[-1] += r" \setlength{\arraycolsep}{0.125em}" - relations = [_latex_product(-Ai,N, head=[xi, "=", bi], + relations = [_latex_product(-Ai, N, head=[xi, "=", bi], drop_plus=False, allow_empty=True) + r"\\" for xi, bi, Ai in zip(B, b, A.rows())] objective = _latex_product(c, N, head=[z, "=", v], @@ -4265,6 +4269,7 @@ def update(self): random_dictionary = LPDictionary.random_element + class LPRevisedDictionary(LPAbstractDictionary): r""" Construct a revised dictionary for an LP problem. @@ -4783,9 +4788,9 @@ def add_row(self, nonbasic_coefficients, constant, basic_variable=None): The implementation of this method for revised dictionaries adds a new inequality constraint to the problem, in which the given - `basic_variable` becomes the slack variable. The resulting dictionary - (with `basic_variable` added to the basis) will have the given - `nonbasic_coefficients` and `constant` as a new row. + ``basic_variable`` becomes the slack variable. The resulting dictionary + (with ``basic_variable`` added to the basis) will have the given + ``nonbasic_coefficients`` and ``constant`` as a new row. INPUT: diff --git a/src/sage/numerical/knapsack.py b/src/sage/numerical/knapsack.py index 9f9d06fcd3b..8776799d338 100644 --- a/src/sage/numerical/knapsack.py +++ b/src/sage/numerical/knapsack.py @@ -98,6 +98,7 @@ from sage.rings.integer import Integer from sage.structure.sage_object import SageObject + class Superincreasing(SageObject): r""" A class for super-increasing sequences. @@ -545,6 +546,7 @@ def subset_sum(self, N): else: return [] + def knapsack(seq, binary=True, max=1, value_only=False, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" diff --git a/src/sage/numerical/meson.build b/src/sage/numerical/meson.build index 222deff834e..91257af0880 100644 --- a/src/sage/numerical/meson.build +++ b/src/sage/numerical/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'all__sagemath_polyhedra.py', 'interactive_simplex_method.py', diff --git a/src/sage/numerical/mip.pyx b/src/sage/numerical/mip.pyx index 78ac846d3df..36ec9bfed0d 100644 --- a/src/sage/numerical/mip.pyx +++ b/src/sage/numerical/mip.pyx @@ -2129,7 +2129,7 @@ cdef class MixedIntegerLinearProgram(SageObject): from sage.numerical.linear_functions import LinearFunction, LinearConstraint from sage.numerical.linear_tensor import LinearTensor from sage.numerical.linear_tensor_constraints import LinearTensorConstraint - if isinstance(linear_function, LinearFunction) or isinstance(linear_function, LinearTensor): + if isinstance(linear_function, (LinearFunction, LinearTensor)): # Find the parent for the coefficients if isinstance(linear_function, LinearFunction): M = linear_function.parent().base_ring() diff --git a/src/sage/numerical/sdp.pyx b/src/sage/numerical/sdp.pyx index 6693b943806..2278200e772 100644 --- a/src/sage/numerical/sdp.pyx +++ b/src/sage/numerical/sdp.pyx @@ -892,7 +892,8 @@ cdef class SemidefiniteProgram(SageObject): from sage.numerical.linear_tensor_constraints import LinearTensorConstraint from sage.numerical.linear_tensor import LinearTensor - if isinstance(linear_function, LinearTensorConstraint) or isinstance(linear_function, LinearConstraint): + if isinstance(linear_function, (LinearTensorConstraint, + LinearConstraint)): c = linear_function if c.is_equation(): self.add_constraint(c.lhs()-c.rhs(), name=name) @@ -900,7 +901,7 @@ cdef class SemidefiniteProgram(SageObject): else: self.add_constraint(c.lhs()-c.rhs(), name=name) - elif isinstance(linear_function, LinearFunction) or isinstance(linear_function, LinearTensor): + elif isinstance(linear_function, (LinearFunction, LinearTensor)): l = sorted(linear_function.dict().items()) self._backend.add_linear_constraint(l, name) diff --git a/src/sage/plot/animate.py b/src/sage/plot/animate.py index c37a17531d8..84433c492e2 100644 --- a/src/sage/plot/animate.py +++ b/src/sage/plot/animate.py @@ -839,7 +839,7 @@ def show(self, delay=None, iterations=None, **kwds): sage: a.show(delay=50) # long time # optional -- ImageMagick - You can also make use of the HTML5 video element in the Sage Notebook:: + You can also make use of the HTML5 video element in the Sage notebook:: sage: # long time, optional -- FFmpeg sage: a.show(format='ogg') diff --git a/src/sage/plot/hyperbolic_arc.py b/src/sage/plot/hyperbolic_arc.py index 904576f79b2..4aa87d4ad22 100644 --- a/src/sage/plot/hyperbolic_arc.py +++ b/src/sage/plot/hyperbolic_arc.py @@ -167,7 +167,6 @@ def _bezier_path(self, z0, z1, model, first=False): self.path.append(points[N: N + 3]) N += 3 self.last_plotted = "arc" - return class HyperbolicArc(HyperbolicArcCore): diff --git a/src/sage/plot/hyperbolic_regular_polygon.py b/src/sage/plot/hyperbolic_regular_polygon.py index 14e8bdcaf68..a6df71ebc11 100644 --- a/src/sage/plot/hyperbolic_regular_polygon.py +++ b/src/sage/plot/hyperbolic_regular_polygon.py @@ -141,9 +141,9 @@ def __init__(self, sides, i_angle, center, options): # real part of the given center. h_disp = self.center.real() - d_z_k = [z_0[0]*scale + h_disp] #d_k has the points for the polygon in the given center - z_k = z_0 #z_k has the Re(z)>0 vertices for the I centered polygon - r_z_k = [] #r_z_k has the Re(z)<0 vertices + d_z_k = [z_0[0]*scale + h_disp] # d_k has the points for the polygon in the given center + z_k = z_0 # z_k has the Re(z)>0 vertices for the I centered polygon + r_z_k = [] # r_z_k has the Re(z)<0 vertices if is_odd(self.sides): vert = (self.sides - 1) // 2 else: diff --git a/src/sage/plot/meson.build b/src/sage/plot/meson.build index 96a337faf78..8cb44114959 100644 --- a/src/sage/plot/meson.build +++ b/src/sage/plot/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'animate.py', 'arc.py', diff --git a/src/sage/plot/misc.py b/src/sage/plot/misc.py index b86b52b05f6..e5bccb0ffad 100644 --- a/src/sage/plot/misc.py +++ b/src/sage/plot/misc.py @@ -63,10 +63,10 @@ def setup_for_eval_on_grid(funcs, EXAMPLES:: - sage: x,y,z=var('x,y,z') - sage: f(x,y)=x+y-z - sage: g(x,y)=x+y - sage: h(y)=-y + sage: x,y,z = var('x,y,z') + sage: f(x,y) = x+y-z + sage: g(x,y) = x+y + sage: h(y) = -y sage: sage.plot.misc.setup_for_eval_on_grid(f, [(0, 2),(1,3),(-4,1)], plot_points=5) (, [(0.0, 2.0, 0.5), (1.0, 3.0, 0.5), (-4.0, 1.0, 1.25)]) sage: sage.plot.misc.setup_for_eval_on_grid([g,h], [(0, 2),(-1,1)], plot_points=5) @@ -149,7 +149,7 @@ def setup_for_eval_on_grid(funcs, # pad the variables if we don't have enough nargs = len(ranges) if len(vars) < nargs: - vars += ('_',)*(nargs-len(vars)) + vars += ('_',) * (nargs - len(vars)) ranges = [[float(z) for z in r] for r in ranges] @@ -157,12 +157,13 @@ def setup_for_eval_on_grid(funcs, plot_points = 2 if not isinstance(plot_points, (list, tuple)): - plot_points = [plot_points]*len(ranges) + plot_points = [plot_points] * len(ranges) elif len(plot_points) != nargs: raise ValueError("plot_points must be either an integer or a list of integers, one for each range") plot_points = [int(p) if p >= 2 else 2 for p in plot_points] - range_steps = [abs(range[1] - range[0])/(p-1) for range, p in zip(ranges, plot_points)] + range_steps = [abs(range[1] - range[0]) / (p - 1) + for range, p in zip(ranges, plot_points)] if min(range_steps) == float(0): raise ValueError("plot start point and end point must be different") @@ -206,11 +207,12 @@ def try_make_fast(f): # Handle vectors, lists, tuples, etc. if isinstance(funcs, Iterable): - funcs = tuple( try_make_fast(f) for f in funcs ) + funcs = tuple(try_make_fast(f) for f in funcs) else: funcs = try_make_fast(funcs) - #TODO: raise an error if there is a function/method in funcs that takes more values than we have ranges + # TODO: raise an error if there is a function/method in funcs that + # takes more values than we have ranges if return_vars: return (funcs, @@ -242,10 +244,10 @@ def unify_arguments(funcs): EXAMPLES:: - sage: x,y,z=var('x,y,z') - sage: f(x,y)=x+y-z - sage: g(x,y)=x+y - sage: h(y)=-y + sage: x,y,z = var('x,y,z') + sage: f(x,y) = x+y-z + sage: g(x,y) = x+y + sage: h(y) = -y sage: sage.plot.misc.unify_arguments((f,g,h)) ((x, y, z), (z,)) sage: sage.plot.misc.unify_arguments((g,h)) @@ -284,8 +286,10 @@ def _multiple_of_constant(n, pos, const): r""" Function for internal use in formatting ticks on axes with nice-looking multiples of various symbolic constants, such - as `\pi` or `e`. Should only be used via keyword argument - `tick_formatter` in :meth:`plot.show`. See documentation + as `\pi` or `e`. + + This should only be used via keyword argument + ``tick_formatter`` in :meth:`plot.show`. See documentation for the matplotlib.ticker module for more details. EXAMPLES: @@ -311,11 +315,11 @@ def _multiple_of_constant(n, pos, const): from sage.misc.latex import latex from sage.rings.continued_fraction import continued_fraction from sage.rings.infinity import Infinity - cf = continued_fraction(n/const) + cf = continued_fraction(n / const) k = 1 while cf.quotient(k) != Infinity and cf.denominator(k) < 12: k += 1 - return '$%s$' % latex(cf.convergent(k-1)*const) + return '$%s$' % latex(cf.convergent(k - 1) * const) def get_matplotlib_linestyle(linestyle, return_type): @@ -401,10 +405,14 @@ def get_matplotlib_linestyle(linestyle, return_type): {'solid', 'dashed', 'dotted', dashdot', 'None'}, respectively {'-', '--', ':', '-.', ''} """ - long_to_short_dict = {'solid' : '-','dashed' : '--', 'dotted' : ':', - 'dashdot':'-.'} - short_to_long_dict = {'-' : 'solid','--' : 'dashed', ':' : 'dotted', - '-.':'dashdot'} + long_to_short_dict = {'solid': '-', + 'dashed': '--', + 'dotted': ':', + 'dashdot': '-.'} + short_to_long_dict = {'-': 'solid', + '--': 'dashed', + ':': 'dotted', + '-.': 'dashdot'} # We need this to take care of region plot. Essentially, if None is # passed, then we just return back the same thing. @@ -416,16 +424,16 @@ def get_matplotlib_linestyle(linestyle, return_type): elif linestyle.startswith("steps"): if linestyle.startswith("steps-mid"): return "steps-mid" + get_matplotlib_linestyle( - linestyle.strip("steps-mid"), "short") + linestyle.strip("steps-mid"), "short") elif linestyle.startswith("steps-post"): return "steps-post" + get_matplotlib_linestyle( - linestyle.strip("steps-post"), "short") + linestyle.strip("steps-post"), "short") elif linestyle.startswith("steps-pre"): return "steps-pre" + get_matplotlib_linestyle( - linestyle.strip("steps-pre"), "short") + linestyle.strip("steps-pre"), "short") else: return "steps" + get_matplotlib_linestyle( - linestyle.strip("steps"), "short") + linestyle.strip("steps"), "short") if return_type == 'short': if linestyle in short_to_long_dict.keys(): diff --git a/src/sage/plot/plot3d/base.pyx b/src/sage/plot/plot3d/base.pyx index f1a9ac7c49b..687335db740 100644 --- a/src/sage/plot/plot3d/base.pyx +++ b/src/sage/plot/plot3d/base.pyx @@ -1108,8 +1108,8 @@ resolution {resolution_x:d} {resolution_y:d} {render_parameters} end_scene""".format( - #render_params.antialiasing, this only provided the default value of 8 - scene = "\n".join(sorted([t.tachyon_str() for t in self.texture_set()])), + # render_params.antialiasing, this only provided the default value of 8 + scene = "\n".join(sorted([t.tachyon_str() for t in self.texture_set()])), render_parameters = "\n".join(flatten_list(self.tachyon_repr(render_params))), viewdir1000=self._tostring(1000*vector(viewdir).normalized().n()), diff --git a/src/sage/plot/plot3d/meson.build b/src/sage/plot/plot3d/meson.build index 46cc4a25ffc..ae1dd2a6b41 100644 --- a/src/sage/plot/plot3d/meson.build +++ b/src/sage/plot/plot3d/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'base.pxd', 'implicit_plot3d.py', diff --git a/src/sage/plot/plot3d/parametric_plot3d.py b/src/sage/plot/plot3d/parametric_plot3d.py index 6a3da2b830f..c0eebb5a160 100644 --- a/src/sage/plot/plot3d/parametric_plot3d.py +++ b/src/sage/plot/plot3d/parametric_plot3d.py @@ -989,8 +989,8 @@ def g(x, y): return x, y+sin(y), x**2 + y**2 if isinstance(f, Vector): f = tuple(f) - if isinstance(f, (list, tuple)) and len(f) > 0 and isinstance(f[0], (list, tuple)): - return sum([parametric_plot3d(v, urange, vrange, plot_points=plot_points, **kwds) for v in f]) + if isinstance(f, (list, tuple)) and f and isinstance(f[0], (list, tuple)): + return sum(parametric_plot3d(v, urange, vrange, plot_points=plot_points, **kwds) for v in f) if not isinstance(f, (tuple, list)) or len(f) != 3: raise ValueError("f must be a list, tuple, or vector of length 3") @@ -1121,7 +1121,9 @@ def _parametric_plot3d_surface(f, urange, vrange, plot_points, boundary_style, * if boundary_style is not None: for u in (urange[0], urange[-1]): - G += line3d([(g[0](u,v), g[1](u,v), g[2](u,v)) for v in vrange], **boundary_style) + G += line3d([(g[0](u, v), g[1](u, v), g[2](u, v)) for v in vrange], + **boundary_style) for v in (vrange[0], vrange[-1]): - G += line3d([(g[0](u,v), g[1](u,v), g[2](u,v)) for u in urange], **boundary_style) + G += line3d([(g[0](u, v), g[1](u, v), g[2](u, v)) for u in urange], + **boundary_style) return G diff --git a/src/sage/plot/plot3d/plot3d.py b/src/sage/plot/plot3d/plot3d.py index 9f5b9a8d94d..f3fd2078d64 100644 --- a/src/sage/plot/plot3d/plot3d.py +++ b/src/sage/plot/plot3d/plot3d.py @@ -155,7 +155,7 @@ def f(x, y): return math.exp(x/5)*math.cos(y) from sage.plot.plot3d.shapes import arrow3d from sage.plot.plot3d.texture import Texture from sage.plot.plot3d.tri_plot import TrianglePlot - +from . import parametric_plot3d lazy_import("sage.functions.trig", ["cos", "sin"]) @@ -190,8 +190,12 @@ def __init__(self, dep_var, indep_vars): Arbitrary Coordinates coordinate transform (z in terms of x, y) """ all_vars = sage_getargspec(self.transform).args[1:] - if set(all_vars) != set(indep_vars + [dep_var]): - raise ValueError('variables were specified incorrectly for this coordinate system; incorrect variables were %s' % list(set(all_vars).symmetric_difference(set(indep_vars+[dep_var])))) + A = set(all_vars) + B = set(indep_vars + [dep_var]) + if A != B: + raise ValueError('variables were specified incorrectly for this ' + 'coordinate system; incorrect variables ' + 'were %s' % list(A.symmetric_difference(B))) self.dep_var = dep_var self.indep_vars = indep_vars @@ -790,10 +794,7 @@ def smooth_triangle(self, a, b, c, da, db, dc, color=None): sage: sm_tri [[0, 0, 0], [0, 0, 1], [1, 1, 0]] """ - return [a,b,c] - - -from . import parametric_plot3d + return [a, b, c] def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): @@ -1083,7 +1084,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): params = f.variables() from sage.modules.vector_callable_symbolic_dense import Vector_callable_symbolic_dense - if isinstance(transformation, (tuple, list,Vector_callable_symbolic_dense)): + if isinstance(transformation, (tuple, list, Vector_callable_symbolic_dense)): if len(transformation) == 3: if params is None: raise ValueError("must specify independent variable names in the ranges when using generic transformation") @@ -1095,7 +1096,7 @@ def plot3d(f, urange, vrange, adaptive=False, transformation=None, **kwds): raise ValueError("unknown transformation type") # find out which variable is the function variable by # eliminating the parameter variables. - all_vars = set(sum([list(s.variables()) for s in transformation],[])) + all_vars = set(sum([list(s.variables()) for s in transformation], [])) dep_var = all_vars - set(indep_vars) if len(dep_var) == 1: dep_var = dep_var.pop() @@ -1173,11 +1174,11 @@ def plot3d_adaptive(f, x_range, y_range, color='automatic', max_depth = max(max_depth, initial_depth) from sage.plot.misc import setup_for_eval_on_grid - g, ranges = setup_for_eval_on_grid(f, [x_range,y_range], plot_points=2) - xmin,xmax = ranges[0][:2] - ymin,ymax = ranges[1][:2] + g, ranges = setup_for_eval_on_grid(f, [x_range, y_range], plot_points=2) + xmin, xmax = ranges[0][:2] + ymin, ymax = ranges[1][:2] - opacity = float(kwds.get('opacity',1)) + opacity = float(kwds.get('opacity', 1)) if color == "automatic": texture = rainbow(num_colors, 'rgbtuple') @@ -1197,9 +1198,9 @@ def plot3d_adaptive(f, x_range, y_range, color='automatic', if isinstance(texture, (list, tuple)): if len(texture) == 2: # do a grid coloring - xticks = (xmax - xmin)/2**initial_depth - yticks = (ymax - ymin)/2**initial_depth - parts = P.partition(lambda x,y,z: (int((x-xmin)/xticks) + int((y-ymin)/yticks)) % 2) + xticks = (xmax - xmin) / 2**initial_depth + yticks = (ymax - ymin) / 2**initial_depth + parts = P.partition(lambda x, y, z: (int((x - xmin) / xticks) + int((y - ymin) / yticks)) % 2) else: # do a topo coloring bounds = P.bounding_box() @@ -1208,8 +1209,8 @@ def plot3d_adaptive(f, x_range, y_range, color='automatic', if max_z == min_z: span = 0 else: - span = (len(texture)-1) / (max_z - min_z) # max to avoid dividing by 0 - parts = P.partition(lambda x, y, z: int((z-min_z)*span)) + span = (len(texture) - 1) / (max_z - min_z) # max to avoid dividing by 0 + parts = P.partition(lambda x, y, z: int((z - min_z) * span)) all = [] for k, G in parts.items(): G.set_texture(texture[k], opacity=opacity) diff --git a/src/sage/plot/plot3d/plot_field3d.py b/src/sage/plot/plot3d/plot_field3d.py index 99f9449e2f8..a4f415935d2 100644 --- a/src/sage/plot/plot3d/plot_field3d.py +++ b/src/sage/plot/plot3d/plot_field3d.py @@ -2,7 +2,7 @@ """ Plotting 3D fields """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009 Jason Grout # # Distributed under the terms of the GNU General Public License (GPL) @@ -14,8 +14,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.arith.srange import srange from sage.plot.misc import setup_for_eval_on_grid @@ -143,16 +143,19 @@ def plot_vector_field3d(functions, xrange, yrange, zrange, from matplotlib.colors import LinearSegmentedColormap cm = LinearSegmentedColormap.from_list('mymap', colors) else: - cm = lambda x: colors + def cm(x): + return colors max_len = max(v.norm() for v in vectors) - scaled_vectors = [v/max_len for v in vectors] + scaled_vectors = [v / max_len for v in vectors] if center_arrows: - G = sum([plot(v, color=cm(v.norm()), **kwds).translate(p-v/2) for v, p in zip(scaled_vectors, points)]) + G = sum(plot(v, color=cm(v.norm()), **kwds).translate(p - v / 2) + for v, p in zip(scaled_vectors, points)) G._set_extra_kwds(kwds) return G else: - G = sum([plot(v, color=cm(v.norm()), **kwds).translate(p) for v, p in zip(scaled_vectors, points)]) + G = sum(plot(v, color=cm(v.norm()), **kwds).translate(p) + for v, p in zip(scaled_vectors, points)) G._set_extra_kwds(kwds) return G diff --git a/src/sage/plot/plot3d/revolution_plot3d.py b/src/sage/plot/plot3d/revolution_plot3d.py index 721573516a5..a98f2ddcc32 100644 --- a/src/sage/plot/plot3d/revolution_plot3d.py +++ b/src/sage/plot/plot3d/revolution_plot3d.py @@ -7,7 +7,7 @@ - Oscar Gerardo Lazo Arjona (2010): initial version. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2010 Oscar Gerardo Lazo Arjona algebraicamente@gmail.com # # Distributed under the terms of the GNU General Public License (GPL) @@ -19,8 +19,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.decorators import rename_keyword from sage.plot.plot3d.parametric_plot3d import parametric_plot3d @@ -253,10 +253,10 @@ def cf(u, phi): return float(2 * u / pi) % 1 phirange = (phi, phirange[0], phirange[1]) if isinstance(curve, (tuple, list)): - #this if-else provides a vector v to be plotted - #if curve is a tuple or a list of length 2, it is interpreted as a parametric curve - #in the x-z plane. - #if it is of length 3 it is interpreted as a parametric curve in 3d space + # this if-else provides a vector v to be plotted + # if curve is a tuple or a list of length 2, it is interpreted as a parametric curve + # in the x-z plane. + # if it is of length 3 it is interpreted as a parametric curve in 3d space if len(curve) == 2: x = curve[0] diff --git a/src/sage/plot/plot3d/shapes2.py b/src/sage/plot/plot3d/shapes2.py index 05d6bb6e583..08077c89f2e 100644 --- a/src/sage/plot/plot3d/shapes2.py +++ b/src/sage/plot/plot3d/shapes2.py @@ -7,7 +7,7 @@ - William Stein and Robert Bradshaw (2008-01): Many improvements """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007 William Stein # Copyright (C) 2008 Robert Bradshaw # @@ -20,10 +20,11 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** import math + from . import shapes from .base import PrimitiveObject, point_list_bounding_box @@ -34,11 +35,10 @@ from sage.arith.srange import srange from .texture import Texture - -TACHYON_PIXEL = 1/200.0 - from .shapes import Text, Sphere +TACHYON_PIXEL = 1 / 200.0 + @rename_keyword(alpha='opacity') def line3d(points, thickness=1, radius=None, arrow_head=False, **kwds): @@ -516,10 +516,12 @@ def frame_labels(lower_left, upper_right, # Helper function for formatting the frame labels from math import log log10 = log(10) - nd = lambda a: int(log(a)/log10) + + def nd(a): + return int(log(a) / log10) def fmt_string(a): - b = a/2.0 + b = a / 2.0 if b >= 1: return "%.1f" n = max(0, 2 - nd(a/2.0)) @@ -527,7 +529,7 @@ def fmt_string(a): # Slightly faster than mean for this situation def avg(a, b): - return (a+b)/2.0 + return (a + b) / 2.0 color = (0.3, 0.3, 0.3) @@ -722,8 +724,8 @@ def ruler_frame(lower_left, upper_right, ticks=4, sub_ticks=4, **kwds): sphinx_plot(ruler_frame([1,2,3],vector([2,3,4]),ticks=6, sub_ticks=2, color='red')) """ return ruler(lower_left, (upper_right[0], lower_left[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) \ - + ruler(lower_left, (lower_left[0], upper_right[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) \ - + ruler(lower_left, (lower_left[0], lower_left[1], upper_right[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) + + ruler(lower_left, (lower_left[0], upper_right[1], lower_left[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) \ + + ruler(lower_left, (lower_left[0], lower_left[1], upper_right[2]), ticks=ticks, sub_ticks=sub_ticks, absolute=True, **kwds) ########################### @@ -1143,8 +1145,8 @@ def tachyon_repr(self, render_params): cmd = ('FCylinder base {pos[0]!r} {pos[1]!r} {pos[2]!r} ' 'apex {apex[0]!r} {apex[1]!r} {apex[2]!r} ' 'rad {radius!r} {texture}').format( - pos=(px, py, pz), apex=(x, y, z), radius=radius, - texture=self.texture.id) + pos=(px, py, pz), apex=(x, y, z), radius=radius, + texture=self.texture.id) cmds.append(cmd) px, py, pz = x, y, z return cmds diff --git a/src/sage/plot/plot3d/tachyon.py b/src/sage/plot/plot3d/tachyon.py index adb1d80b7be..d04b4332a8c 100644 --- a/src/sage/plot/plot3d/tachyon.py +++ b/src/sage/plot/plot3d/tachyon.py @@ -371,8 +371,8 @@ def __init__(self, antialiasing=False, aspectratio=1.0, raydepth=8, - camera_position=None, # default value (-3, 0, 0), - camera_center=None, # alternative equivalent name + camera_position=None, # default value (-3, 0, 0), + camera_center=None, # alternative equivalent name updir=[0, 0, 1], look_at=[0, 0, 0], viewdir=None, @@ -397,10 +397,10 @@ def __init__(self, self._raydepth = raydepth if camera_position is not None: self._camera_position = camera_position - elif camera_center is not None: # make sure that old programs continue to work + elif camera_center is not None: # make sure that old programs continue to work self._camera_position = camera_center else: - self._camera_position = (-3, 0, 0) # default value + self._camera_position = (-3, 0, 0) # default value self._updir = updir self._projection = projection self._focallength = focallength @@ -689,8 +689,8 @@ def str(self): {} {} end_scene""".format(self._res(), - self._camera(), - '\n'.join(x.str() for x in self._objects)) + self._camera(), + '\n'.join(x.str() for x in self._objects)) def light(self, center, radius, color): r""" @@ -1249,15 +1249,15 @@ def str(self): phong {} {} phong_size {} color {} texfunc {} """.format(self._name, - self._ambient, - self._diffuse, - self._specular, - self._opacity, - self._phongtype, - self._phong, - self._phongsize, - tostr(self._color), - self._texfunc) + self._ambient, + self._diffuse, + self._specular, + self._opacity, + self._phongtype, + self._phong, + self._phongsize, + tostr(self._color), + self._texfunc) class Sphere: @@ -1338,7 +1338,7 @@ def str(self): return r""" ring center {} normal {} inner {} outer {} {} """.format(tostr(self._center), tostr(self._normal), - self._inner, self._outer, self._texture) + self._inner, self._outer, self._texture) class FractalLandscape: @@ -1380,7 +1380,7 @@ def str(self): return r""" scape res {} scale {} center {} {} """.format(tostr(self._res, 2, int), tostr(self._scale, 2, int), - tostr(self._center), self._texture) + tostr(self._center), self._texture) class Cylinder: diff --git a/src/sage/plot/plot3d/texture.py b/src/sage/plot/plot3d/texture.py index 561b8efbc3a..21c901fc0c3 100644 --- a/src/sage/plot/plot3d/texture.py +++ b/src/sage/plot/plot3d/texture.py @@ -421,10 +421,10 @@ def mtl_str(self): illum {illumination} Ns {shininess!r} d {opacity!r}""" - ).format(id=self.id, ambient=self.ambient, diffuse=self.diffuse, - specular=self.specular, - illumination=(2 if sum(self.specular) > 0 else 1), - shininess=self.shininess, opacity=self.opacity) + ).format(id=self.id, ambient=self.ambient, diffuse=self.diffuse, + specular=self.specular, + illumination=(2 if sum(self.specular) > 0 else 1), + shininess=self.shininess, opacity=self.opacity) def jmol_str(self, obj): r""" @@ -447,6 +447,6 @@ def jmol_str(self, obj): """ translucent = "translucent %s" % float(1 - self.opacity) if self.opacity < 1 else "" return "color {} {} [{},{},{}]".format(obj, translucent, - int(255 * self.color[0]), - int(255 * self.color[1]), - int(255 * self.color[2])) + int(255 * self.color[0]), + int(255 * self.color[1]), + int(255 * self.color[2])) diff --git a/src/sage/plot/plot3d/tri_plot.py b/src/sage/plot/plot3d/tri_plot.py index a2e843778eb..4011995a0a7 100644 --- a/src/sage/plot/plot3d/tri_plot.py +++ b/src/sage/plot/plot3d/tri_plot.py @@ -241,7 +241,7 @@ def str(self): return "".join(o.str() for o in self._objects) def __init__(self, triangle_factory, f, min_x__max_x, min_y__max_y, g=None, - min_depth=4, max_depth=8, num_colors=None, max_bend=.3): + min_depth=4, max_depth=8, num_colors=None, max_bend=.3): """ TESTS:: @@ -345,28 +345,28 @@ def plot_block(self, min_x, mid_x, max_x, min_y, mid_y, max_y, sw_z, nw_z, se_z, se_depth = next_depth ne_depth = next_depth else: - #compute the midpoint-to-corner vectors + # compute the midpoint-to-corner vectors sw_v = (min_x - mid_x, min_y - mid_y, sw_z[0] - mid_z[0]) nw_v = (min_x - mid_x, max_y - mid_y, nw_z[0] - mid_z[0]) se_v = (max_x - mid_x, min_y - mid_y, se_z[0] - mid_z[0]) ne_v = (max_x - mid_x, max_y - mid_y, ne_z[0] - mid_z[0]) - #compute triangle normal unit vectors by taking the cross-products - #of the midpoint-to-corner vectors. always go around clockwise - #so we're guaranteed to have a positive value near 1 when neighboring - #triangles are parallel - #However -- crossunit doesn't really return a unit vector. It returns - #the length of the vector to avoid numerical instability when the - #length is nearly zero -- rather than divide by nearly zero, we multiply - #the other side of the inequality by nearly zero -- in general, this - #should work a bit better because of the density of floating-point - #numbers near zero. + # compute triangle normal unit vectors by taking the cross-products + # of the midpoint-to-corner vectors. always go around clockwise + # so we're guaranteed to have a positive value near 1 when neighboring + # triangles are parallel + # However -- crossunit doesn't really return a unit vector. It returns + # the length of the vector to avoid numerical instability when the + # length is nearly zero -- rather than divide by nearly zero, we multiply + # the other side of the inequality by nearly zero -- in general, this + # should work a bit better because of the density of floating-point + # numbers near zero. norm_w = crossunit(sw_v, nw_v) norm_n = crossunit(nw_v, ne_v) norm_e = crossunit(ne_v, se_v) norm_s = crossunit(se_v, sw_v) - #compute the dot products of the triangle unit norms + # compute the dot products of the triangle unit norms e_sw = norm_w[0]*norm_s[0] + norm_w[1]*norm_s[1] + norm_w[2]*norm_s[2] e_nw = norm_w[0]*norm_n[0] + norm_w[1]*norm_n[1] + norm_w[2]*norm_n[2] e_se = norm_e[0]*norm_s[0] + norm_e[1]*norm_s[1] + norm_e[2]*norm_s[2] diff --git a/src/sage/plot/primitive.py b/src/sage/plot/primitive.py index ef69f7f4344..3c4032085cc 100644 --- a/src/sage/plot/primitive.py +++ b/src/sage/plot/primitive.py @@ -146,7 +146,7 @@ def set_zorder(self, zorder): def set_options(self, new_options): """ - Change the options to `new_options`. + Change the options to ``new_options``. EXAMPLES:: diff --git a/src/sage/probability/meson.build b/src/sage/probability/meson.build index 83b6a7e091e..2981a7496c4 100644 --- a/src/sage/probability/meson.build +++ b/src/sage/probability/meson.build @@ -1,4 +1,9 @@ -py.install_sources('all.py', 'random_variable.py', subdir: 'sage/probability') +py.install_sources( + '__init__.py', + 'all.py', + 'random_variable.py', + subdir: 'sage/probability', +) extension_data = { 'probability_distribution' : files('probability_distribution.pyx'), diff --git a/src/sage/probability/probability_distribution.pyx b/src/sage/probability/probability_distribution.pyx index fab94479291..a1d11fb2bfb 100644 --- a/src/sage/probability/probability_distribution.pyx +++ b/src/sage/probability/probability_distribution.pyx @@ -40,7 +40,8 @@ REFERENCES: # **************************************************************************** from cysignals.memory cimport sig_malloc, sig_free -from sage.libs.gsl.all cimport * +from sage.libs.gsl.rng cimport * +from sage.libs.gsl.random cimport * import sage.misc.prandom as random import sage.rings.real_double from sage.modules.free_module_element import vector diff --git a/src/sage/probability/random_variable.py b/src/sage/probability/random_variable.py index cb5c0426c5a..ce66f36bdb3 100644 --- a/src/sage/probability/random_variable.py +++ b/src/sage/probability/random_variable.py @@ -26,6 +26,7 @@ ################################################################################ ################################################################################ + def is_ProbabilitySpace(S): from sage.misc.superseded import deprecation deprecation(38184, @@ -33,6 +34,7 @@ def is_ProbabilitySpace(S): "use 'isinstance(..., ProbabilitySpace_generic)' instead.") return isinstance(S, ProbabilitySpace_generic) + def is_DiscreteProbabilitySpace(S): from sage.misc.superseded import deprecation deprecation(38184, @@ -40,6 +42,7 @@ def is_DiscreteProbabilitySpace(S): "use 'isinstance(..., DiscreteProbabilitySpace)' instead.") return isinstance(S, DiscreteProbabilitySpace) + def is_RandomVariable(X): from sage.misc.superseded import deprecation deprecation(38184, @@ -47,6 +50,7 @@ def is_RandomVariable(X): "use 'isinstance(..., RandomVariable_generic)' instead.") return isinstance(X, RandomVariable_generic) + def is_DiscreteRandomVariable(X): from sage.misc.superseded import deprecation deprecation(38184, @@ -299,6 +303,7 @@ def translation_correlation(self, other, map): ################################################################################ ################################################################################ + class ProbabilitySpace_generic(RandomVariable_generic): r""" A probability space. diff --git a/src/sage/quadratic_forms/all.py b/src/sage/quadratic_forms/all.py index 5982c6b8a5a..c4832168378 100644 --- a/src/sage/quadratic_forms/all.py +++ b/src/sage/quadratic_forms/all.py @@ -6,13 +6,17 @@ from sage.quadratic_forms.quadratic_form import QuadraticForm, DiagonalQuadraticForm, quadratic_form_from_invariants -from sage.quadratic_forms.random_quadraticform import (random_quadraticform, random_quadraticform_with_conditions, - random_ternaryqf, random_ternaryqf_with_conditions) +from sage.quadratic_forms.random_quadraticform import (random_quadraticform, + random_quadraticform_with_conditions, + random_ternaryqf, + random_ternaryqf_with_conditions) from sage.quadratic_forms.extras import least_quadratic_nonresidue, extend_to_primitive, is_triangular_number -from sage.quadratic_forms.special_values import (gamma__exact, zeta__exact, QuadraticBernoulliNumber, - quadratic_L_function__exact, quadratic_L_function__numerical) +from sage.quadratic_forms.special_values import (gamma__exact, zeta__exact, + QuadraticBernoulliNumber, + quadratic_L_function__exact, + quadratic_L_function__numerical) from sage.quadratic_forms.genera.genus import Genus diff --git a/src/sage/quadratic_forms/binary_qf.py b/src/sage/quadratic_forms/binary_qf.py old mode 100755 new mode 100644 index 1a75f415b64..202da0652ff --- a/src/sage/quadratic_forms/binary_qf.py +++ b/src/sage/quadratic_forms/binary_qf.py @@ -1630,7 +1630,7 @@ def solve_integer(self, n, *, algorithm='general', _flag=2): ALGORITHM: :pari:`qfbsolve` or :pari:`qfbcornacchia` - TODO:: Replace `_flag` with human-readable parameters c.f. :issue:`37119` + TODO:: Replace ``_flag`` with human-readable parameters c.f. :issue:`37119` EXAMPLES:: @@ -1736,7 +1736,7 @@ def solve_integer(self, n, *, algorithm='general', _flag=2): sage: Q(*xy) 0 - Test for different `_flag` values:: + Test for different ``_flag`` values:: sage: # needs sage.libs.pari sage: Q = BinaryQF([1, 0, 5]) diff --git a/src/sage/quadratic_forms/meson.build b/src/sage/quadratic_forms/meson.build index 0e352ed72be..3208c9f15f6 100644 --- a/src/sage/quadratic_forms/meson.build +++ b/src/sage/quadratic_forms/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'binary_qf.py', 'bqf_class_group.py', diff --git a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py index dc9b30aa763..a88cf660412 100644 --- a/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py +++ b/src/sage/quadratic_forms/quadratic_form__local_density_congruence.py @@ -291,7 +291,7 @@ def local_good_density_congruence_even(self, m, Zvec, NZvec): # Take cases on the existence of additional nonzero congruence conditions (mod 2) if NZvec is None: total = (4 ** len(Z_Is8)) * (8 ** len(Is8_minus_Z)) \ - * count_all_local_good_types_normal_form(Q_Not8,2, 3, m, list(Z_Not8), None) + * count_all_local_good_types_normal_form(Q_Not8, 2, 3, m, list(Z_Not8), None) else: ZNZ = Z + Set(NZvec) ZNZ_Not8 = Not8.intersection(ZNZ) diff --git a/src/sage/quadratic_forms/quadratic_form__neighbors.py b/src/sage/quadratic_forms/quadratic_form__neighbors.py index d4d579409d3..b63fbda3b60 100644 --- a/src/sage/quadratic_forms/quadratic_form__neighbors.py +++ b/src/sage/quadratic_forms/quadratic_form__neighbors.py @@ -327,7 +327,7 @@ def neighbor_iteration(seeds, p, mass=None, max_classes=None, def p_divisible_vectors(Q, max_neighbors): yield from iter(v.lift() for v in Q.orbits_lines_mod_p(p) if v != 0 and Q(v.lift()).valuation(p) > 0) - return + elif algorithm == 'exhaustion': def p_divisible_vectors(Q, max_neighbors): k = 0 diff --git a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py index 3922767e870..a8265a5bbe1 100644 --- a/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py +++ b/src/sage/quadratic_forms/quadratic_form__ternary_Tornaria.py @@ -129,8 +129,7 @@ def adjoint(self): [ * 19 4 ] [ * * 8 ] """ - from sage.quadratic_forms.quadratic_form import QuadraticForm as QuadraticForm - + from sage.quadratic_forms.quadratic_form import QuadraticForm if is_odd(self.dim()): return QuadraticForm(self.matrix().adjoint_classical() * 2) return QuadraticForm(self.matrix().adjoint_classical()) diff --git a/src/sage/quivers/ar_quiver.py b/src/sage/quivers/ar_quiver.py index f13c67dfa32..f0b2193eece 100644 --- a/src/sage/quivers/ar_quiver.py +++ b/src/sage/quivers/ar_quiver.py @@ -9,8 +9,8 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.unique_representation import UniqueRepresentation from sage.structure.parent import Parent diff --git a/src/sage/quivers/meson.build b/src/sage/quivers/meson.build index cdefdce952b..aa6d757721d 100644 --- a/src/sage/quivers/meson.build +++ b/src/sage/quivers/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'algebra.py', 'algebra_elements.pxd', 'all.py', diff --git a/src/sage/repl/attach.py b/src/sage/repl/attach.py index 89b6a789fc4..b9997d8f2df 100644 --- a/src/sage/repl/attach.py +++ b/src/sage/repl/attach.py @@ -40,7 +40,7 @@ ....: traceback.print_exc(file=sys.stdout) Traceback (most recent call last): ... - exec(preparse_file(f.read()) + "\n", globals) + exec(preparse_file(f.read()) + "\n", globals)... File "", line 3, in ValueError: third sage: detach(src) @@ -52,7 +52,7 @@ ....: traceback.print_exc(file=sys.stdout) Traceback (most recent call last): ... - exec(code, globals) + exec(code, globals)... File ".../foobar...sage.py", line ..., in raise ValueError("third") # this should appear in the source snippet... ValueError: third @@ -318,8 +318,12 @@ def attach(*files): .. SEEALSO:: - :meth:`~sage.repl.load.load` is the same as :func:`attach`, but - does not automatically reload a file when it changes. + :func:`~sage.repl.load.load` is the same as :func:`attach`, but + does not automatically reload a file when it changes unless + ``attach=True`` is passed. + + ``%attach`` magic can also be used, see + :meth:`~sage.repl.ipython_extension.SageMagics.attach`. EXAMPLES: diff --git a/src/sage/repl/configuration.py b/src/sage/repl/configuration.py index 68b2fbb9f8b..7016e12837b 100644 --- a/src/sage/repl/configuration.py +++ b/src/sage/repl/configuration.py @@ -15,15 +15,14 @@ sage: 'sage: [False, True]' in output # needs pexpect True """ - -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2016 Volker Braun # # 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 sys diff --git a/src/sage/repl/display/fancy_repr.py b/src/sage/repl/display/fancy_repr.py index 044f8e3f6b2..392e6a5f0db 100644 --- a/src/sage/repl/display/fancy_repr.py +++ b/src/sage/repl/display/fancy_repr.py @@ -120,7 +120,7 @@ def __init__(self): self._type_repr = type_repr def __call__(self, obj, p, cycle): - """ + r""" Format object. INPUT: @@ -142,7 +142,17 @@ def __call__(self, obj, p, cycle): sage: pp = SomeIPythonRepr() sage: pp.format_string(set([1, 2, 3])) '{1, 2, 3}' + + TESTS:: + + sage: pp.format_string(Sequence([[1]*20, [2]*20])) + '[[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],\n [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]]' """ + if hasattr(type(obj), '_repr_pretty_'): + # standard method for classes to extend pretty library + # see https://ipython.readthedocs.io/en/stable/api/generated/IPython.lib.pretty.html#extending + obj._repr_pretty_(p, cycle) + return True try: pretty_repr = self._type_repr[type(obj)] except KeyError: @@ -218,7 +228,7 @@ class PlainPythonRepr(ObjectReprABC): def __call__(self, obj, p, cycle): r""" - Format matrix. + Format object. INPUT: diff --git a/src/sage/repl/image.py b/src/sage/repl/image.py index 06a6f6a671a..1169b29c466 100644 --- a/src/sage/repl/image.py +++ b/src/sage/repl/image.py @@ -113,7 +113,7 @@ def pil(self): sage: from sage.repl.image import Image sage: img = Image('RGB', (16, 16), 'white') sage: img.pil - + """ return self._pil diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 3a269592917..664fa9a8444 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -75,8 +75,7 @@ sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() - sage: print("dummy line"); shell.run_cell('1/0') # known bug (meson doesn't include the Cython source code) # see #25320 for the reason of the `...` and the dummy line in this test - dummy line + sage: shell.run_cell('1/0') # known bug (meson doesn't include the Cython source code) ... ZeroDivisionError...Traceback (most recent call last) ... @@ -772,7 +771,8 @@ def __init__(self, app): contact_email = 'sage-support@googlegroups.com' bug_tracker = 'https://github.com/sagemath/sage/issues' CrashHandler.__init__(self, - app, contact_name, contact_email, bug_tracker, show_crash_traceback=True) + app, contact_name, contact_email, + bug_tracker, show_crash_traceback=True) self.crash_report_fname = 'Sage_crash_report.txt' diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index b6fc42bbb37..05468142142 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -65,6 +65,8 @@ """ from IPython.core.magic import Magics, magics_class, line_magic, cell_magic +from IPython.core.display import HTML +from IPython.core.getipython import get_ipython from sage.repl.load import load_wrap from sage.env import SAGE_IMPORTALL, SAGE_STARTUP_FILE @@ -72,6 +74,14 @@ from sage.misc.misc import run_once +def _running_in_notebook(): + try: + from ipykernel.zmqshell import ZMQInteractiveShell + except ImportError: + return False + return isinstance(get_ipython(), ZMQInteractiveShell) + + @magics_class class SageMagics(Magics): @@ -107,6 +117,10 @@ def runfile(self, s): - ``s`` -- string; the file to be loaded + .. SEEALSO:: + + This is the same as :func:`~sage.repl.load.load`. + EXAMPLES:: sage: import os @@ -133,6 +147,10 @@ def attach(self, s): - ``s`` -- string. The file to be attached + .. SEEALSO:: + + This is the same as :func:`~sage.repl.attach.attach`. + EXAMPLES:: sage: from sage.repl.interpreter import get_test_shell @@ -302,7 +320,7 @@ def display(self, args): max_width = 0 if max_width <= 0: raise ValueError( - "max width must be a positive integer") + "max width must be a positive integer") import sage.typeset.character_art as character_art character_art.MAX_WIDTH = max_width dm.preferences.text = arg0 @@ -340,9 +358,34 @@ def cython(self, line, cell): This is syntactic sugar on the :func:`~sage.misc.cython.cython_compile` function. + Note that there is also the ``%%cython`` cell magic provided by Cython, + which can be loaded with ``%load_ext cython``, see + `Cython documentation `_ + for more details. + The semantic is slightly different from the version provided by Sage. + INPUT: - - ``line`` -- ignored + - ``line`` -- parsed as keyword arguments. The allowed arguments are: + + - ``--verbose N`` / ``-v N`` + - ``--compile-message`` + - ``--use-cache`` + - ``--create-local-c-file`` + - ``--annotate`` + - ``--view-annotate`` + - ``--sage-namespace`` + - ``--create-local-so-file`` + - ``--no-compile-message``, ``--no-use-cache``, etc. + + See :func:`~sage.misc.cython.cython` for details. + + If ``--view-annotate`` is given, the annotation is either displayed + inline in the Sage notebook or opened in a new web browser, depending + on whether the Sage notebook is used. + + You can override the selection by specifying + ``--view-annotate=webbrowser`` or ``--view-annotate=displayhtml``. - ``cell`` -- string; the Cython source code to process @@ -350,19 +393,130 @@ def cython(self, line, cell): EXAMPLES:: + sage: # needs sage.misc.cython sage: from sage.repl.interpreter import get_test_shell sage: shell = get_test_shell() - sage: shell.run_cell( # needs sage.misc.cython + sage: shell.run_cell( ....: ''' - ....: %%cython + ....: %%cython -v1 --annotate --no-sage-namespace ....: def f(): ....: print('test') ....: ''') - sage: f() # needs sage.misc.cython + Compiling ....pyx because it changed. + [1/1] Cythonizing ....pyx + sage: f() test + + TESTS: + + Test unrecognized arguments:: + + sage: # needs sage.misc.cython + sage: shell.run_cell(''' + ....: %%cython --some-unrecognized-argument + ....: print(1) + ....: ''') + UsageError: unrecognized arguments: --some-unrecognized-argument + + Test ``--help`` is disabled:: + + sage: # needs sage.misc.cython + sage: shell.run_cell(''' + ....: %%cython --help + ....: print(1) + ....: ''') + UsageError: unrecognized arguments: --help + + Test ``--view-annotate`` invalid arguments:: + + sage: # needs sage.misc.cython + sage: shell.run_cell(''' + ....: %%cython --view-annotate=xx + ....: print(1) + ....: ''') # exact error message differ between Python 3.11/3.13 + UsageError: argument --view-annotate: invalid choice: 'xx' (choose from ...) + + Test ``--view-annotate=displayhtml`` (note that in a notebook environment + an inline HTML frame will be displayed):: + + sage: # needs sage.misc.cython + sage: shell.run_cell(''' + ....: %%cython --view-annotate=displayhtml + ....: print(1) + ....: ''') + 1 + + + Test ``--view-annotate=webbrowser``:: + + sage: # needs sage.misc.cython webbrowser + sage: shell.run_cell(''' + ....: %%cython --view-annotate + ....: print(1) + ....: ''') + 1 + sage: shell.run_cell(''' + ....: %%cython --view-annotate=auto + ....: print(1) + ....: ''') # --view-annotate=auto is undocumented feature, equivalent to --view-annotate + 1 + sage: shell.run_cell(''' + ....: %%cython --view-annotate=webbrowser + ....: print(1) + ....: ''') + 1 + + Test invalid quotes:: + + sage: # needs sage.misc.cython + sage: shell.run_cell(''' + ....: %%cython --a=' + ....: print(1) + ....: ''') + ... + ValueError...Traceback (most recent call last) + ... + ValueError: No closing quotation """ from sage.misc.cython import cython_compile - return cython_compile(cell) + import shlex + import argparse + + class ExitCatchingArgumentParser(argparse.ArgumentParser): + def error(self, message): + # exit_on_error=False does not work completely in some Python versions + # see https://stackoverflow.com/q/67890157 + # we raise UsageError to make the interface similar to what happens when e.g. + # IPython's ``%run`` gets unrecognized arguments + from IPython.core.error import UsageError + raise UsageError(message) + + parser = ExitCatchingArgumentParser(prog="%%cython", add_help=False) + parser.add_argument("--verbose", "-v", type=int) + parser.add_argument("--compile-message", action=argparse.BooleanOptionalAction) + parser.add_argument("--use-cache", action=argparse.BooleanOptionalAction) + parser.add_argument("--create-local-c-file", action=argparse.BooleanOptionalAction) + parser.add_argument("--annotate", action=argparse.BooleanOptionalAction) + parser.add_argument("--view-annotate", choices=["none", "auto", "webbrowser", "displayhtml"], + nargs="?", const="auto", default="none") + parser.add_argument("--sage-namespace", action=argparse.BooleanOptionalAction) + parser.add_argument("--create-local-so-file", action=argparse.BooleanOptionalAction) + args = parser.parse_args(shlex.split(line)) + view_annotate = args.view_annotate + del args.view_annotate + if view_annotate == "auto": + if _running_in_notebook(): + view_annotate = "displayhtml" + else: + view_annotate = "webbrowser" + args_dict = {k: v for k, v in args.__dict__.items() if v is not None} + if view_annotate != "none": + args_dict["view_annotate"] = True + if view_annotate == "displayhtml": + path_to_annotate_html_container = [] + cython_compile(cell, **args_dict, view_annotate_callback=path_to_annotate_html_container.append) + return HTML(filename=path_to_annotate_html_container[0]) + return cython_compile(cell, **args_dict) @cell_magic def fortran(self, line, cell): @@ -434,10 +588,7 @@ def __init__(self, shell=None): self.init_inspector() self.init_line_transforms() - try: - import sage.all # until sage's import hell is fixed - except ImportError: - import sage.all__sagemath_repl + import sage.all # noqa: F401 self.shell.verbose_quit = True diff --git a/src/sage/repl/ipython_kernel/widgets.py b/src/sage/repl/ipython_kernel/widgets.py index 42d674b7c9a..6b32b3a1ded 100644 --- a/src/sage/repl/ipython_kernel/widgets.py +++ b/src/sage/repl/ipython_kernel/widgets.py @@ -119,7 +119,7 @@ def __init__(self, *args, **kwds): <... 'dict'> """ self.__transform = kwds.pop("transform", None) - return super().__init__(*args, **kwds) + super().__init__(*args, **kwds) def get_value(self): """ diff --git a/src/sage/repl/load.py b/src/sage/repl/load.py index a1a1451f1c2..6cd0c792c76 100644 --- a/src/sage/repl/load.py +++ b/src/sage/repl/load.py @@ -87,6 +87,14 @@ def load(filename, globals, attach=False): from t import * + .. NOTE:: + + The global ``load`` function is :func:`sage.misc.persist.load`, + which delegates to this function for code file formats. + + ``%runfile`` magic can also be used, see + :meth:`~sage.repl.ipython_extension.SageMagics.runfile`. + INPUT: - ``filename`` -- string (denoting a filename or URL) or a :class:`Path` object @@ -97,13 +105,15 @@ def load(filename, globals, attach=False): - ``attach`` -- boolean (default: ``False``); whether to add the file to the list of attached files - Loading an executable Sage script from the command prompt will run whatever - code is inside an + Loading an executable Sage script from the :ref:`command line ` + will run whatever code is inside an + + :: if __name__ == "__main__": section, as the condition on ``__name__`` will hold true (code run from the - command prompt is considered to be running in the ``__main__`` module.) + command line is considered to be running in the ``__main__`` module.) EXAMPLES: @@ -159,7 +169,8 @@ def load(filename, globals, attach=False): sage: sage.repl.load.load('https://raw.githubusercontent.com/sagemath/sage-patchbot/3.0.0/sage_patchbot/util.py', globals()) # optional - internet - We attach a file:: + We attach a file (note that :func:`~sage.repl.attach.attach` + is equivalent, but available at the global scope by default):: sage: t = tmp_filename(ext='.py') sage: with open(t, 'w') as f: diff --git a/src/sage/repl/rich_output/backend_doctest.py b/src/sage/repl/rich_output/backend_doctest.py index 5113b5845b4..0f347281e82 100644 --- a/src/sage/repl/rich_output/backend_doctest.py +++ b/src/sage/repl/rich_output/backend_doctest.py @@ -13,14 +13,14 @@ The Sage display manager using the doctest backend """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun # # 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 sys @@ -295,7 +295,7 @@ def validate(self, rich_output): assert data.startswith(b'\0\0\0') # See http://www.ftyps.com/ ftyps = [data[i:i+4] for i in range(8, data[3], 4)] - del ftyps[1] # version number, not an ftyp + del ftyps[1] # version number, not an ftyp expected = [b'avc1', b'iso2', b'mp41', b'mp42'] assert any(i in ftyps for i in expected) elif isinstance(rich_output, OutputVideoFlash): diff --git a/src/sage/repl/rich_output/backend_ipython.py b/src/sage/repl/rich_output/backend_ipython.py index b736aca9538..5b013574507 100644 --- a/src/sage/repl/rich_output/backend_ipython.py +++ b/src/sage/repl/rich_output/backend_ipython.py @@ -525,7 +525,7 @@ def displayhook(self, plain_text, rich_output): elif isinstance(rich_output, OutputLatex): return ({'text/latex': rich_output.latex.get_str(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputHtml): data = {'text/html': rich_output.html.get_str(), 'text/plain': plain_text.text.get_str()} @@ -535,29 +535,29 @@ def displayhook(self, plain_text, rich_output): elif isinstance(rich_output, OutputImagePng): return ({'image/png': rich_output.png.get(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputImageGif): return ({'text/html': rich_output.html_fragment(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputImageJpg): return ({'image/jpeg': rich_output.jpg.get(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputImageSvg): return ({'image/svg+xml': rich_output.svg.get(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputImagePdf): return ({'image/png': rich_output.png.get(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputSceneJmol): from sage.repl.display.jsmol_iframe import JSMolHtml jsmol = JSMolHtml(rich_output, height=500) return ({'text/html': jsmol.iframe(), 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) elif isinstance(rich_output, OutputSceneThreejs): escaped_html = html.escape(rich_output.html.get_str()) iframe = IFRAME_TEMPLATE.format( @@ -567,7 +567,7 @@ def displayhook(self, plain_text, rich_output): ) return ({'text/html': iframe, 'text/plain': plain_text.text.get_str(), - }, {}) + }, {}) else: raise TypeError('rich_output type not supported') diff --git a/src/sage/repl/rich_output/display_manager.py b/src/sage/repl/rich_output/display_manager.py index 2d1be377cad..6e282f8aee5 100644 --- a/src/sage/repl/rich_output/display_manager.py +++ b/src/sage/repl/rich_output/display_manager.py @@ -32,18 +32,26 @@ # the License, or (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - +from __future__ import annotations import warnings +from typing import Any + +try: + from typing import Self # type: ignore (Python >= 3.11) +except ImportError: + from typing_extensions import Self # type: ignore (Python 3.9, 3.10) -from sage.structure.sage_object import SageObject from sage.repl.rich_output.output_basic import ( - OutputPlainText, OutputAsciiArt, OutputUnicodeArt, OutputLatex, + OutputAsciiArt, + OutputPlainText, + OutputUnicodeArt, ) from sage.repl.rich_output.output_browser import ( OutputHtml, ) from sage.repl.rich_output.preferences import DisplayPreferences +from sage.structure.sage_object import SageObject class DisplayException(Exception): @@ -185,7 +193,7 @@ def __exit__(self, exception_type, value, traceback): class DisplayManager(SageObject): - _instance = None + _instance: Self | None = None def __init__(self): """ @@ -205,7 +213,7 @@ def __init__(self): self.switch_backend(BackendSimple()) @classmethod - def get_instance(cls): + def get_instance(cls) -> Self: """ Get the singleton instance. @@ -771,7 +779,7 @@ def supported_output(self): """ return self._supported_output - def displayhook(self, obj): + def displayhook(self, obj: Any) -> None | Any: """ Implementation of the displayhook. diff --git a/src/sage/repl/rich_output/output_basic.py b/src/sage/repl/rich_output/output_basic.py index 70257f7f4ed..05cff326eb9 100644 --- a/src/sage/repl/rich_output/output_basic.py +++ b/src/sage/repl/rich_output/output_basic.py @@ -32,14 +32,14 @@ class is independent of user preferences and of the display file system. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun # # 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.structure.sage_object import SageObject diff --git a/src/sage/repl/rich_output/output_catalog.py b/src/sage/repl/rich_output/output_catalog.py index 542182eee69..584a077781c 100644 --- a/src/sage/repl/rich_output/output_catalog.py +++ b/src/sage/repl/rich_output/output_catalog.py @@ -5,14 +5,14 @@ If you define another output type then you must add it to the imports here. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun # # 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 .output_basic import ( diff --git a/src/sage/repl/rich_output/pretty_print.py b/src/sage/repl/rich_output/pretty_print.py index 93833e01cd8..8e00e3d70e4 100644 --- a/src/sage/repl/rich_output/pretty_print.py +++ b/src/sage/repl/rich_output/pretty_print.py @@ -160,7 +160,7 @@ def pretty_print(self): sage: seq._concatenate_graphs().show(edge_labels=True) # needs sage.graphs sage.plot Traceback (most recent call last): ... - TypeError: ...matplotlib() got an unexpected keyword argument 'edge_labels' + TypeError: ...matplotlib() got an unexpected keyword argument 'edge_labels'... """ try: from sage.plot.plot import Graphics diff --git a/src/sage/repl/rich_output/test_backend.py b/src/sage/repl/rich_output/test_backend.py index 133fb35ae5d..059eda5de3e 100644 --- a/src/sage/repl/rich_output/test_backend.py +++ b/src/sage/repl/rich_output/test_backend.py @@ -30,14 +30,14 @@ TestOutputPlainText container """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Volker Braun # # 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.structure.sage_object import SageObject diff --git a/src/sage/repl/user_globals.py b/src/sage/repl/user_globals.py index 444c0af1405..9e2090b8224 100644 --- a/src/sage/repl/user_globals.py +++ b/src/sage/repl/user_globals.py @@ -102,7 +102,7 @@ def get_globals(): return user_globals -def set_globals(g): +def set_globals(g: dict) -> None: """ Set the dictionary of all user globals to ``g``. diff --git a/src/sage/rings/abc.pyx b/src/sage/rings/abc.pyx index e8078f97743..ef74bf34d4a 100644 --- a/src/sage/rings/abc.pyx +++ b/src/sage/rings/abc.pyx @@ -1,7 +1,6 @@ """ Abstract base classes for rings """ -from sage.rings.ring import IntegralDomain class NumberField_quadratic(Field): @@ -419,7 +418,7 @@ class Order: pass -class pAdicRing(IntegralDomain): +class pAdicRing(CommutativeRing): r""" Abstract base class for :class:`~sage.rings.padics.generic_nodes.pAdicRingGeneric`. diff --git a/src/sage/rings/algebraic_closure_finite_field.py b/src/sage/rings/algebraic_closure_finite_field.py index b5e76c676d3..da9737adf38 100644 --- a/src/sage/rings/algebraic_closure_finite_field.py +++ b/src/sage/rings/algebraic_closure_finite_field.py @@ -53,12 +53,11 @@ - Vincent Delecroix (November 2013): additional methods """ - from sage.misc.abstract_method import abstract_method from sage.misc.fast_methods import WithEqualityById - from sage.rings.finite_rings.finite_field_base import FiniteField from sage.rings.ring import Field +from sage.sets.family import AbstractFamily from sage.structure.element import Element, FieldElement from sage.structure.richcmp import richcmp @@ -833,7 +832,7 @@ def gen(self, n): F = self._subfield(n) return self(F.gen()) - def gens(self): + def gens(self) -> AbstractFamily: """ Return a family of generators of ``self``. diff --git a/src/sage/rings/all.py b/src/sage/rings/all.py index e3c7167fe12..ca7946fa78f 100644 --- a/src/sage/rings/all.py +++ b/src/sage/rings/all.py @@ -12,8 +12,6 @@ # **************************************************************************** from sage.misc.lazy_import import lazy_import -from sage.rings.all__sagemath_categories import * - # Ring base classes from sage.rings.ring import (Ring, Field, CommutativeRing, IntegralDomain, PrincipalIdealDomain) diff --git a/src/sage/rings/all__sagemath_categories.py b/src/sage/rings/all__sagemath_categories.py deleted file mode 100644 index 4c0efe7b507..00000000000 --- a/src/sage/rings/all__sagemath_categories.py +++ /dev/null @@ -1,7 +0,0 @@ -# sage_setup: distribution = sagemath-categories -# Ring base classes -from sage.rings.ring import Ring -# Ideals -from sage.rings.ideal import Ideal - -ideal = Ideal diff --git a/src/sage/rings/asymptotic/asymptotic_ring.py b/src/sage/rings/asymptotic/asymptotic_ring.py index 48caffa1b6a..91a5775624e 100644 --- a/src/sage/rings/asymptotic/asymptotic_ring.py +++ b/src/sage/rings/asymptotic/asymptotic_ring.py @@ -428,7 +428,7 @@ lazy_import('sage.rings.lazy_series_ring', 'LazyPowerSeriesRing') lazy_import('sage.rings.polynomial.multi_polynomial_ring_base', 'MPolynomialRing_base') -lazy_import('sage.rings.polynomial.polynomial_ring', 'PolynomialRing_general') +lazy_import('sage.rings.polynomial.polynomial_ring', 'PolynomialRing_generic') lazy_import('sage.rings.power_series_ring', 'PowerSeriesRing_generic') lazy_import('sage.symbolic.ring', 'SymbolicRing') @@ -4013,7 +4013,7 @@ def _element_constructor_(self, data, simplify=True, convert=True): (data, self)), e) return sum(summands, self.zero()) - elif isinstance(P, PolynomialRing_general): + elif isinstance(P, PolynomialRing_generic): p = P.gen() try: return sum(iter(self.create_summand('exact', growth=p**i, @@ -4317,6 +4317,16 @@ def coefficients_of_generating_function(self, function, singularities, precision ....: 'n', precision=5)) True + Positive and negative singularities:: + + sage: def permutations_odd_cycles(z): + ....: return sqrt((1+z) / (1-z)) + sage: ex = B.coefficients_of_generating_function( + ....: permutations_odd_cycles, (1, -1,), precision=2, + ....: ); ex + sqrt(2)/sqrt(pi)*n^(-1/2) - 1/2*sqrt(1/2)/sqrt(pi)*n^(-3/2)*(-1)^n + + O(n^(-5/2)) + .. WARNING:: Once singular expansions around points other than infinity diff --git a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py index 9eaf85376ca..8603936d232 100644 --- a/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +++ b/src/sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py @@ -502,10 +502,10 @@ def dimension(self): sage: F.dimension() 2 """ - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base R = self.denominator_ring - if isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base): + if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): return R.ngens() raise NotImplementedError('only polynomial rings are supported as base') @@ -3165,9 +3165,9 @@ def _element_constructor_(self, *args, **kwargs): p = numerator q = R(denominator) - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base - if isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base): + if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): if not R(q).is_unit(): # Factor denominator try: @@ -3233,11 +3233,10 @@ def _coerce_map_from_(self, P): from sage.rings.fraction_field import FractionField_generic if isinstance(P, FractionField_generic): B = P.base() - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base - if isinstance(B, PolynomialRing_general) or isinstance(B, MPolynomialRing_base): - if self.base().has_coerce_map_from(B): - return True + if isinstance(B, (PolynomialRing_generic, MPolynomialRing_base)) and self.base().has_coerce_map_from(B): + return True if self.base().has_coerce_map_from(P): return True @@ -4032,7 +4031,7 @@ def diff_op_simple(A, B, AB_derivs, x, v, a, N): various natural numbers `e, k, l` that depend on `v` and `N`. Here `DD` is a specific linear differential operator that depends - on `a` and `v` , `A` and `B` are symbolic functions, and `AB_derivs` + on `a` and `v` , `A` and `B` are symbolic functions, and ``AB_derivs`` contains all the derivatives of `A` and `B` evaluated at `p` that are necessary for the computation. diff --git a/src/sage/rings/asymptotic/growth_group.py b/src/sage/rings/asymptotic/growth_group.py index ca2afc2b92c..3f711f269aa 100644 --- a/src/sage/rings/asymptotic/growth_group.py +++ b/src/sage/rings/asymptotic/growth_group.py @@ -1745,9 +1745,9 @@ def _initial_category_(base): # The following block can be removed once #19269 is fixed. from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic if base is ZZ or base is QQ or \ - isinstance(base, PolynomialRing_general) and \ + isinstance(base, PolynomialRing_generic) and \ (base.base_ring() is ZZ or base.base_ring() is QQ): return Posets() else: @@ -2370,7 +2370,7 @@ def _pushout_(self, other): from sage.categories.cartesian_product import cartesian_product return cartesian_product([self, other]) - def gens_monomial(self): + def gens_monomial(self) -> tuple: r""" Return a tuple containing monomial generators of this growth group. @@ -2399,9 +2399,9 @@ def gens_monomial(self): sage: GrowthGroup('QQ^x').gens_monomial() () """ - return tuple() + return () - def gens(self): + def gens(self) -> tuple: r""" Return a tuple of all generators of this growth group. @@ -3463,7 +3463,7 @@ def _convert_(self, data): from sage.symbolic.ring import SR return self._convert_(SR(data)) - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import \ MPolynomialRing_base from sage.rings.power_series_ring import PowerSeriesRing_generic @@ -3473,7 +3473,7 @@ def _convert_(self, data): base, exponent = data.operands() if str(base) == var: return exponent - elif isinstance(P, (PolynomialRing_general, MPolynomialRing_base)): + elif isinstance(P, (PolynomialRing_generic, MPolynomialRing_base)): if data.is_monomial() and len(data.variables()) == 1: if var == str(data.variables()[0]): return data.degree() @@ -3519,7 +3519,7 @@ def _split_raw_element_(raw_element): from sage.functions.other import real, imag return real(raw_element), imag(raw_element) - def gens_monomial(self): + def gens_monomial(self) -> tuple: r""" Return a tuple containing monomial generators of this growth group. @@ -3546,7 +3546,7 @@ def gens_monomial(self): return tuple() return (self(raw_element=self.base().one()),) - def gens_logarithmic(self): + def gens_logarithmic(self) -> tuple: r""" Return a tuple containing logarithmic generators of this growth group. @@ -4529,7 +4529,7 @@ def some_elements(self): return iter(self.element_class(self, e) for e in self.base().some_elements() if e > 0) - def gens(self): + def gens(self) -> tuple: r""" Return a tuple of all generators of this exponential growth group. @@ -4543,7 +4543,7 @@ def gens(self): sage: E.gens() () """ - return tuple() + return () def construction(self): r""" diff --git a/src/sage/rings/asymptotic/growth_group_cartesian.py b/src/sage/rings/asymptotic/growth_group_cartesian.py index 19bb7d975a6..1b15ac8f252 100644 --- a/src/sage/rings/asymptotic/growth_group_cartesian.py +++ b/src/sage/rings/asymptotic/growth_group_cartesian.py @@ -836,7 +836,7 @@ def next_custom(self): from sage.categories.cartesian_product import cartesian_product return pushout(cartesian_product(newS), cartesian_product(newO)) - def gens_monomial(self): + def gens_monomial(self) -> tuple: r""" Return a tuple containing monomial generators of this growth group. diff --git a/src/sage/rings/asymptotic/misc.py b/src/sage/rings/asymptotic/misc.py index e3d7a013285..740529a374e 100644 --- a/src/sage/rings/asymptotic/misc.py +++ b/src/sage/rings/asymptotic/misc.py @@ -34,7 +34,7 @@ lazy_import('sage.rings.lazy_series_ring', 'LazyPowerSeriesRing') lazy_import('sage.rings.multi_power_series_ring', 'MPowerSeriesRing_generic') lazy_import('sage.rings.polynomial.multi_polynomial_ring_base', 'MPolynomialRing_base') -lazy_import('sage.rings.polynomial.polynomial_ring', 'PolynomialRing_general') +lazy_import('sage.rings.polynomial.polynomial_ring', 'PolynomialRing_generic') lazy_import('sage.rings.power_series_ring', 'PowerSeriesRing_generic') @@ -168,7 +168,7 @@ def abbreviate(P): pass raise ValueError('Cannot abbreviate %s.' % (P,)) - poly = isinstance(P, (PolynomialRing_general, MPolynomialRing_base)) + poly = isinstance(P, (PolynomialRing_generic, MPolynomialRing_base)) power = isinstance(P, (PowerSeriesRing_generic, MPowerSeriesRing_generic, LazyPowerSeriesRing)) if poly or power: diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index 4166083de4a..f0d1c22c147 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -95,7 +95,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.laurent_series_ring import LaurentSeriesRing from sage.rings.power_series_ring import PowerSeriesRing from sage.rings.fraction_field import FractionField @@ -142,7 +142,7 @@ def CFiniteSequences(base_ring, names=None, category=None): sage: TestSuite(C).run() """ - if isinstance(base_ring, PolynomialRing_general): + if isinstance(base_ring, PolynomialRing_generic): polynomial_ring = base_ring base_ring = polynomial_ring.base_ring() if names is None: diff --git a/src/sage/rings/complex_interval.pyx b/src/sage/rings/complex_interval.pyx index 60bc5b5abff..4fd7e6bbcf3 100644 --- a/src/sage/rings/complex_interval.pyx +++ b/src/sage/rings/complex_interval.pyx @@ -249,7 +249,7 @@ cdef class ComplexIntervalFieldElement(FieldElement): if not self.real().is_zero(): s = self.real().str(base=base, style=style) if not self.imag().is_zero(): - y = self.imag() + y = self.imag() if s: if y < 0: s += " - " @@ -2237,7 +2237,7 @@ cdef _circle_invert_standard( # Consider the images # f(xmin + ymin * I), ..., f(xmax + ymax * I) # of the four corners of the input rect under inversion f. - # Now consider the the axis-parallel rectangle R that these images span. + # Now consider the axis-parallel rectangle R that these images span. # In general, the image of the input rect might not be contained in R. # In case 1, however, (and only in case 1) it is and we furthermore know # which image is mapped to which edge of R. Thus, we have: diff --git a/src/sage/rings/complex_mpc.pyx b/src/sage/rings/complex_mpc.pyx index d6bcb664a49..98efcb0b27b 100644 --- a/src/sage/rings/complex_mpc.pyx +++ b/src/sage/rings/complex_mpc.pyx @@ -185,7 +185,7 @@ cpdef inline split_complex_string(string, int base=10): exponent = '[@p]' else: exponent = '@' - exponent += sign + '?' + digit + '+' + exponent += sign + '?' + digit + '+' # Warning: number, imaginary, and complex should be enclosed in parentheses # when used as regexp because of alternatives '|' diff --git a/src/sage/rings/complex_mpfr.pyx b/src/sage/rings/complex_mpfr.pyx index bec9978401e..d24e61d2823 100644 --- a/src/sage/rings/complex_mpfr.pyx +++ b/src/sage/rings/complex_mpfr.pyx @@ -48,7 +48,6 @@ from sage.rings.integer cimport Integer from sage.rings.complex_double cimport ComplexDoubleElement from sage.rings.real_mpfr cimport RealNumber -from sage.libs.gsl.complex cimport * from sage.libs.mpmath.utils cimport mpfr_to_mpfval from sage.rings.integer_ring import ZZ diff --git a/src/sage/rings/convert/meson.build b/src/sage/rings/convert/meson.build index 0b485247bf1..04b9e285593 100644 --- a/src/sage/rings/convert/meson.build +++ b/src/sage/rings/convert/meson.build @@ -1,4 +1,9 @@ -py.install_sources('all.py', 'mpfi.pxd', subdir: 'sage/rings/convert') +py.install_sources( + '__init__.py', + 'all.py', + 'mpfi.pxd', + subdir: 'sage/rings/convert', +) extension_data = {'mpfi' : files('mpfi.pyx')} diff --git a/src/sage/rings/convert/mpfi.pyx b/src/sage/rings/convert/mpfi.pyx index 803eed59146..0c95ff6af94 100644 --- a/src/sage/rings/convert/mpfi.pyx +++ b/src/sage/rings/convert/mpfi.pyx @@ -11,11 +11,16 @@ Convert Sage/Python objects to real/complex intervals # http://www.gnu.org/licenses/ #***************************************************************************** +import re + from cpython.float cimport PyFloat_AS_DOUBLE from cpython.complex cimport PyComplex_RealAsDouble, PyComplex_ImagAsDouble +from libc.stdio cimport printf + from sage.libs.mpfr cimport * from sage.libs.mpfi cimport * +from sage.libs.gmp.mpz cimport * from sage.libs.gsl.complex cimport * from sage.arith.long cimport integer_check_long @@ -45,6 +50,243 @@ cdef inline int return_real(mpfi_ptr im) noexcept: return 0 +NUMBER = re.compile(rb'([+-]?(0[XxBb])?[0-9A-Za-z]+)\.([0-9A-Za-z]*)\?([0-9]*)(?:([EePp@])([+-]?[0-9]+))?') +# example: -0xABC.DEF?12@5 +# match groups: (-0xABC) (0x) (DEF) (12) (@) (5) + +cdef int _from_str_question_style(mpfi_ptr x, bytes s, int base) except -1: + """ + Convert a string in question style to an MPFI interval. + + INPUT: + + - ``x`` -- a pre-initialized MPFI interval + + - ``s`` -- the string to convert + + - ``base`` -- base to use for string conversion + + OUTPUT: + + - if conversion is possible: set ``x`` and return 0. + + - in all other cases: return some nonzero value, or raise an exception. + + TESTS: + + Double check that ``ZZ``, ``RR`` and ``RIF`` follows the string + conversion rule for base different from `10` (except ``ZZ`` + which only allows base up to `36`):: + + sage: ZZ("0x123", base=0) + 291 + sage: RR("0x123.e1", base=0) # rel tol 1e-12 + 291.878906250000 + sage: RR("0x123.@1", base=0) # rel tol 1e-12 + 4656.00000000000 + sage: RIF("0x123.4@1", base=0) + 4660 + sage: ZZ("1Xx", base=36) # case insensitive + 2517 + sage: ZZ("1Xx", base=62) + Traceback (most recent call last): + ... + ValueError: base (=62) must be 0 or between 2 and 36 + sage: RR("1Xx", base=36) # rel tol 1e-12 + 2517.00000000000 + sage: RR("0x123", base=36) # rel tol 1e-12 + 1.54101900000000e6 + sage: RR("-1Xx@-1", base=62) # rel tol 1e-12 + -95.9516129032258 + sage: RIF("1Xx@-1", base=62) # rel tol 1e-12 + 95.95161290322580? + sage: RIF("1aE1", base=11) + Traceback (most recent call last): + ... + TypeError: unable to convert '1aE1' to real interval + sage: RIF("1aE1", base=11) + Traceback (most recent call last): + ... + TypeError: unable to convert '1aE1' to real interval + + General checks:: + + sage: RIF("123456.?2").endpoints() # rel tol 1e-12 + (123454.0, 123458.0) + sage: RIF("1234.56?2").endpoints() # rel tol 1e-12 + (1234.54, 1234.58) + sage: RIF("1234.56?2e2").endpoints() # rel tol 1e-12 + (123454.0, 123458.0) + sage: x = RIF("-1234.56?2e2"); x.endpoints() # rel tol 1e-12 + (-123458.0, -123454.0) + sage: x + -1.2346?e5 + sage: x.str(style="question", error_digits=1) + '-123456.?2' + sage: RIF("1.?100").endpoints() # rel tol 1e-12 + (-99.0, 101.0) + sage: RIF("1.?100").str(style="question", error_digits=3) + '1.?100' + + Large exponent (ensure precision is not lost):: + + sage: x = RIF("1.123456?2e100000000"); x + 1.12346?e100000000 + sage: x.str(style="question", error_digits=3) + '1.12345600?201e100000000' + + Large precision:: + + sage: F = RealIntervalField(1000) + sage: x = F(sqrt(2)); x.endpoints() # rel tol 1e-290 + (1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157273501384623091229702492483605585073721264412149709993583141322266592750559275579995050115278206057147010955997160597027453459686201472851741864088919860955232923048430871432145083976260362799525140798, + 1.41421356237309504880168872420969807856967187537694807317667973799073247846210703885038753432764157273501384623091229702492483605585073721264412149709993583141322266592750559275579995050115278206057147010955997160597027453459686201472851741864088919860955232923048430871432145083976260362799525140799) + sage: x in F(x.str(style="question", error_digits=3)) + True + sage: x in F(x.str(style="question", error_digits=0)) + True + sage: F("1.123456789123456789123456789123456789123456789123456789123456789123456789?987654321987654321987654321e500").endpoints() # rel tol 1e-290 + (1.123456789123456789123456789123456789123456788135802467135802467135802468e500, + 1.12345678912345678912345678912345678912345679011111111111111111111111111e500) + + Stress test:: + + sage: for F in [RealIntervalField(15), RIF, RealIntervalField(100), RealIntervalField(1000)]: + ....: for i in range(1000): + ....: a, b = randint(-10^9, 10^9), randint(0, 50) + ....: c, d = randint(-2^b, 2^b), randint(2, 5) + ....: x = a * F(d)^c + ....: assert x in F(x.str(style="question", error_digits=3)), (x, a, c, d) + ....: assert x in F(x.str(style="question", error_digits=0)), (x, a, c, d) + + Base different from `10` (note that the error and exponent are specified in decimal):: + + sage: RIF("10000.?0", base=2).endpoints() # rel tol 1e-12 + (16.0, 16.0) + sage: RIF("10000.?0e10", base=2).endpoints() # rel tol 1e-12 + (16384.0, 16384.0) + sage: x = RIF("10000.?10", base=2); x.endpoints() # rel tol 1e-12 + (6.0, 26.0) + sage: x.str(base=2, style="question", error_digits=2) + '10000.000?80' + sage: x = RIF("10000.000?80", base=2); x.endpoints() # rel tol 1e-12 + (6.0, 26.0) + sage: x = RIF("12a.?", base=16); x.endpoints() # rel tol 1e-12 + (297.0, 299.0) + sage: x = RIF("12a.BcDeF?", base=16); x.endpoints() # rel tol 1e-12 + (298.737775802611, 298.737777709962) + sage: x = RIF("12a.BcDeF?@10", base=16); x.endpoints() # rel tol 1e-12 + (3.28465658150911e14, 3.28465660248065e14) + sage: x = RIF("12a.BcDeF?p10", base=16); x.endpoints() # rel tol 1e-12 + (305907.482421875, 305907.484375000) + sage: x = RIF("0x12a.BcDeF?p10", base=0); x.endpoints() # rel tol 1e-12 + (305907.482421875, 305907.484375000) + + Space is allowed:: + + sage: RIF("-1234.56?2").endpoints() # rel tol 1e-12 + (-1234.58, -1234.54) + sage: RIF("- 1234.56 ?2").endpoints() # rel tol 1e-12 + (-1234.58, -1234.54) + + Erroneous input:: + + sage: RIF("1234.56?2e2.3") + Traceback (most recent call last): + ... + TypeError: unable to convert '1234.56?2e2.3' to real interval + sage: RIF("1234?2") # decimal point required + Traceback (most recent call last): + ... + TypeError: unable to convert '1234?2' to real interval + sage: RIF("1234.?2e") + Traceback (most recent call last): + ... + TypeError: unable to convert '1234.?2e' to real interval + sage: RIF("1.?e999999999999999999999999") + [-infinity .. +infinity] + sage: RIF("0X1.?", base=33) # X is not valid digit in base 33 + Traceback (most recent call last): + ... + TypeError: unable to convert '0X1.?' to real interval + sage: RIF("1.a?1e10", base=12) + Traceback (most recent call last): + ... + TypeError: unable to convert '1.a?1e10' to real interval + sage: RIF("1.1?a@10", base=12) + Traceback (most recent call last): + ... + TypeError: unable to convert '1.1?a@10' to real interval + sage: RIF("0x1?2e1", base=0) # e is not allowed in base > 10, use @ instead + Traceback (most recent call last): + ... + TypeError: unable to convert '0x1?2e1' to real interval + sage: RIF("0x1?2p1", base=36) + Traceback (most recent call last): + ... + TypeError: unable to convert '0x1?2p1' to real interval + """ + cdef mpz_t error_part + cdef mpfi_t error + cdef mpfr_t radius, neg_radius + cdef bytes int_part_string, base_prefix, frac_part_string, error_string, e, sci_expo_string, optional_expo, tmp + + match = NUMBER.fullmatch(s) + if match is None: + return 1 + int_part_string, base_prefix, frac_part_string, error_string, e, sci_expo_string = match.groups() + + if (base > 10 or (base == 0 and base_prefix in (b'0X', b'0X'))) and e in (b'e', b'E'): + return 1 + if base > 16 and e in (b'p', b'P'): + return 1 + if base > 16 or not base_prefix: + base_prefix = b'' + + if error_string: + if mpz_init_set_str(error_part, error_string, 10): + mpz_clear(error_part) + return 1 + else: + mpz_init_set_ui(error_part, 1) + + optional_expo = e + sci_expo_string if e else b'' + if mpfi_set_str(x, int_part_string + b'.' + frac_part_string + optional_expo, base): + mpz_clear(error_part) + return 1 + + mpfr_init2(radius, mpfi_get_prec(x)) + tmp = base_prefix + ( + b'0.' + b'0'*(len(frac_part_string)-1) + b'1' + optional_expo + if frac_part_string else + b'1.' + optional_expo) + # if base = 0: + # when s = '-0x123.456@7', tmp = '0x0.001@7' + # when s = '-0x123.@7', tmp = '0x1.@7' + # if base = 36: + # when s = '-0x123.456@7', tmp = '0.001@7' + if mpfr_set_str(radius, tmp, base, MPFR_RNDU): + mpfr_clear(radius) + mpz_clear(error_part) + return 1 + + mpfr_mul_z(radius, radius, error_part, MPFR_RNDU) + mpz_clear(error_part) + + mpfr_init2(neg_radius, mpfi_get_prec(x)) + mpfr_neg(neg_radius, radius, MPFR_RNDD) + + mpfi_init2(error, mpfi_get_prec(x)) + mpfi_interv_fr(error, neg_radius, radius) + mpfr_clear(radius) + mpfr_clear(neg_radius) + + mpfi_add(x, x, error) + mpfi_clear(error) + + return 0 + + cdef int mpfi_set_sage(mpfi_ptr re, mpfi_ptr im, x, field, int base) except -1: """ Convert any object ``x`` to an MPFI interval or a pair of @@ -72,6 +314,33 @@ cdef int mpfi_set_sage(mpfi_ptr re, mpfi_ptr im, x, field, int base) except -1: imaginary component is 0. - in all other cases: raise an exception. + + TESTS:: + + sage: RIF('0xabc') + Traceback (most recent call last): + ... + TypeError: unable to convert '0xabc' to real interval + sage: RIF("0x123.e1", base=0) # rel tol 1e-12 + 291.87890625000000? + sage: RIF("0x123.@1", base=0) # rel tol 1e-12 + 4656 + sage: RIF("1Xx", base=36) # rel tol 1e-12 + 2517 + sage: RIF("-1Xx@-10", base=62) # rel tol 1e-12 + -7.088054920481391?e-15 + sage: RIF("1", base=1) + Traceback (most recent call last): + ... + ValueError: base (=1) must be 0 or between 2 and 62 + sage: RIF("1", base=-1) + Traceback (most recent call last): + ... + ValueError: base (=-1) must be 0 or between 2 and 62 + sage: RIF("1", base=63) + Traceback (most recent call last): + ... + ValueError: base (=63) must be 0 or between 2 and 62 """ cdef RealIntervalFieldElement ri cdef ComplexIntervalFieldElement zi @@ -79,6 +348,8 @@ cdef int mpfi_set_sage(mpfi_ptr re, mpfi_ptr im, x, field, int base) except -1: cdef ComplexDoubleElement zd cdef bytes s + if base != 0 and (base < 2 or base > 62): + raise ValueError(f"base (={base}) must be 0 or between 2 and 62") if im is not NULL and isinstance(x, tuple): # For complex numbers, interpret tuples as real/imag parts if len(x) != 2: @@ -157,6 +428,11 @@ cdef int mpfi_set_sage(mpfi_ptr re, mpfi_ptr im, x, field, int base) except -1: if isinstance(x, unicode): x = x.encode("ascii") if isinstance(x, bytes): + if b"?" in x: + if _from_str_question_style(re, (x).replace(b' ', b''), base): + x = bytes_to_str(x) + raise TypeError(f"unable to convert {x!r} to real interval") + return return_real(im) s = (x).replace(b'..', b',').replace(b' ', b'').replace(b'+infinity', b'@inf@').replace(b'-infinity', b'-@inf@') if mpfi_set_str(re, s, base): x = bytes_to_str(x) diff --git a/src/sage/rings/derivation.py b/src/sage/rings/derivation.py index b824e16e0d1..24c9ac92dd7 100644 --- a/src/sage/rings/derivation.py +++ b/src/sage/rings/derivation.py @@ -193,7 +193,7 @@ from sage.structure.element import ModuleElement from sage.rings.integer_ring import ZZ -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base from sage.rings.power_series_ring import PowerSeriesRing_generic from sage.rings.laurent_series_ring import LaurentSeriesRing @@ -331,9 +331,9 @@ def __init__(self, domain, codomain, twist=None): self._basis = [ ] self._dual_basis = [ ] self._constants = (domain, True) - elif (isinstance(domain, (PolynomialRing_general, MPolynomialRing_base, PowerSeriesRing_generic, LaurentSeriesRing)) + elif (isinstance(domain, (PolynomialRing_generic, MPolynomialRing_base, PowerSeriesRing_generic, LaurentSeriesRing)) or (isinstance(domain, FractionField_generic) - and isinstance(domain.ring(), (PolynomialRing_general, MPolynomialRing_base)))): + and isinstance(domain.ring(), (PolynomialRing_generic, MPolynomialRing_base)))): self._base_derivation = RingDerivationModule(domain.base_ring(), defining_morphism) self.Element = RingDerivationWithoutTwist_function try: @@ -649,7 +649,7 @@ def ngens(self): raise NotImplementedError("generators are not implemented for this derivation module") return len(self._gens) - def gens(self): + def gens(self) -> tuple: r""" Return the generators of this module of derivations. @@ -996,7 +996,7 @@ def list(self): parent = self.parent() return [self(x) for x in parent.dual_basis()] - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): r""" Return dictionary of nonzero coordinates (on the canonical basis) of this derivation. diff --git a/src/sage/rings/finite_rings/element_base.pxd b/src/sage/rings/finite_rings/element_base.pxd index c214e4745a9..2c509e2d5e3 100644 --- a/src/sage/rings/finite_rings/element_base.pxd +++ b/src/sage/rings/finite_rings/element_base.pxd @@ -9,4 +9,3 @@ cdef class FinitePolyExtElement(FiniteRingElement): cdef class Cache_base(SageObject): cpdef FinitePolyExtElement fetch_int(self, number) - diff --git a/src/sage/rings/finite_rings/element_base.pyx b/src/sage/rings/finite_rings/element_base.pyx old mode 100755 new mode 100644 diff --git a/src/sage/rings/finite_rings/element_givaro.pyx b/src/sage/rings/finite_rings/element_givaro.pyx index bb5a9f6b376..695ecd2c8bf 100644 --- a/src/sage/rings/finite_rings/element_givaro.pyx +++ b/src/sage/rings/finite_rings/element_givaro.pyx @@ -359,7 +359,7 @@ cdef class Cache_givaro(Cache_base): else: raise TypeError("unable to coerce from a finite field other than the prime subfield") - elif isinstance(e, (int, Integer)) or isinstance(e, IntegerMod_abstract): + elif isinstance(e, (int, Integer, IntegerMod_abstract)): try: e_int = e % self.characteristic() self.objectptr.initi(res, e_int) diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index c1d0c58a4d3..332fedc4713 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -1358,7 +1358,7 @@ cdef class FiniteField(Field): False """ from sage.rings.integer_ring import ZZ - if R is int or R is long or R is ZZ: + if R is int or R is ZZ: return True if isinstance(R, sage.rings.abc.IntegerModRing) and self.characteristic().divides(R.characteristic()): return R.hom((self.one(),), check=False) diff --git a/src/sage/rings/finite_rings/homset.py b/src/sage/rings/finite_rings/homset.py index 617f9da0086..cee7867fe0b 100644 --- a/src/sage/rings/finite_rings/homset.py +++ b/src/sage/rings/finite_rings/homset.py @@ -236,33 +236,27 @@ def list(self): sage: k1 = GF(1009) sage: k2 = GF(1009, modulus='primitive') sage: Hom(k1, k2).list() - [ - Ring morphism: - From: Finite Field of size 1009 - To: Finite Field of size 1009 - Defn: 1 |--> 1 - ] + [Ring morphism: + From: Finite Field of size 1009 + To: Finite Field of size 1009 + Defn: 1 |--> 1] sage: Hom(k2, k1).list() - [ - Ring morphism: - From: Finite Field of size 1009 - To: Finite Field of size 1009 - Defn: 11 |--> 11 - ] + [Ring morphism: + From: Finite Field of size 1009 + To: Finite Field of size 1009 + Defn: 11 |--> 11] sage: k1. = GF(1009^2, modulus='first_lexicographic') sage: k2. = GF(1009^2, modulus='conway') sage: Hom(k1, k2).list() - [ - Ring morphism: - From: Finite Field in a of size 1009^2 - To: Finite Field in b of size 1009^2 - Defn: a |--> 290*b + 864, - Ring morphism: - From: Finite Field in a of size 1009^2 - To: Finite Field in b of size 1009^2 - Defn: a |--> 719*b + 145 - ] + [Ring morphism: + From: Finite Field in a of size 1009^2 + To: Finite Field in b of size 1009^2 + Defn: a |--> 290*b + 864, + Ring morphism: + From: Finite Field in a of size 1009^2 + To: Finite Field in b of size 1009^2 + Defn: a |--> 719*b + 145] TESTS: @@ -303,16 +297,14 @@ def __getitem__(self, n): To: Finite Field in b of size 2^10 Defn: a |--> b^7 + b^5 sage: H[2:4] - [ - Ring morphism: - From: Finite Field in a of size 2^5 - To: Finite Field in b of size 2^10 - Defn: a |--> b^8 + b^6 + b^2, - Ring morphism: - From: Finite Field in a of size 2^5 - To: Finite Field in b of size 2^10 - Defn: a |--> b^9 + b^7 + b^6 + b^5 + b^4 - ] + [Ring morphism: + From: Finite Field in a of size 2^5 + To: Finite Field in b of size 2^10 + Defn: a |--> b^8 + b^6 + b^2, + Ring morphism: + From: Finite Field in a of size 2^5 + To: Finite Field in b of size 2^10 + Defn: a |--> b^9 + b^7 + b^6 + b^5 + b^4] """ return self.list()[n] diff --git a/src/sage/rings/finite_rings/integer_mod.pyx b/src/sage/rings/finite_rings/integer_mod.pyx index cf2d43ca59a..19525b40937 100644 --- a/src/sage/rings/finite_rings/integer_mod.pyx +++ b/src/sage/rings/finite_rings/integer_mod.pyx @@ -2039,8 +2039,12 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): sage: e = Mod(19, 10^10) sage: e << 102 9443608576 + sage: e << (2^200) + Traceback (most recent call last): + ... + OverflowError: Python int too large to convert to C long """ - return self.shift(long(k)) + return self.shift(k) def __rshift__(IntegerMod_gmp self, k): r""" @@ -2053,8 +2057,12 @@ cdef class IntegerMod_gmp(IntegerMod_abstract): sage: e = Mod(19, 10^10) sage: e >> 1 9 + sage: e << (2^200) + Traceback (most recent call last): + ... + OverflowError: Python int too large to convert to C long """ - return self.shift(-long(k)) + return self.shift(-k) cdef shift(IntegerMod_gmp self, long k): r""" diff --git a/src/sage/rings/finite_rings/integer_mod_ring.py b/src/sage/rings/finite_rings/integer_mod_ring.py index 893fde4e929..6d5b7c6b36c 100644 --- a/src/sage/rings/finite_rings/integer_mod_ring.py +++ b/src/sage/rings/finite_rings/integer_mod_ring.py @@ -69,7 +69,6 @@ from sage.arith.misc import CRT_basis from sage.rings.ring import Field, CommutativeRing from sage.misc.mrange import cartesian_product_iterator -import sage.rings.ring as ring import sage.rings.abc from sage.rings.finite_rings import integer_mod import sage.rings.integer as integer @@ -2030,7 +2029,7 @@ def crt(v): 1027 """ if len(v) == 0: - return IntegerModRing(1)(1) + return IntegerModRing(1).one() x = v[0] for i in range(1, len(v)): x = x.crt(v[i]) diff --git a/src/sage/rings/finite_rings/meson.build b/src/sage/rings/finite_rings/meson.build index 7f7a5744a1f..7e6c338636f 100644 --- a/src/sage/rings/finite_rings/meson.build +++ b/src/sage/rings/finite_rings/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'conway_polynomials.py', 'element_base.pxd', diff --git a/src/sage/rings/finite_rings/residue_field.pyx b/src/sage/rings/finite_rings/residue_field.pyx index be83c5165f6..f6f8c08666f 100644 --- a/src/sage/rings/finite_rings/residue_field.pyx +++ b/src/sage/rings/finite_rings/residue_field.pyx @@ -189,7 +189,7 @@ from sage.rings.number_field.number_field_ideal import NumberFieldIdeal from sage.rings.fraction_field import FractionField_generic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.polynomial_element import Polynomial from sage.structure.element cimport Element, parent, Vector @@ -337,7 +337,7 @@ class ResidueFieldFactory(UniqueFactory): raise ValueError("p must be an ideal or element of a number field or function field.") if not p.is_prime(): raise ValueError("p (%s) must be prime" % p) - if isinstance(p.ring(), PolynomialRing_general): + if isinstance(p.ring(), PolynomialRing_generic): if not p.ring().base_ring().is_finite(): raise ValueError("residue fields only supported for polynomial rings over finite fields") if not p.ring().base_ring().is_prime_field(): @@ -373,7 +373,7 @@ class ResidueFieldFactory(UniqueFactory): if pring is ZZ: return ResidueFiniteField_prime_modn(p, names, p.gen(), None, None, None) - if isinstance(pring, PolynomialRing_general): + if isinstance(pring, PolynomialRing_generic): K = pring.fraction_field() Kbase = pring.base_ring() f = p.gen() @@ -1400,7 +1400,7 @@ cdef class ResidueFieldHomomorphism_global(RingHomomorphism): # No special code for residue fields of Z, since we just use the normal reduction map to GF(p) if self._K is ZZ: return self._F(x) - if isinstance(self._K, PolynomialRing_general): + if isinstance(self._K, PolynomialRing_generic): p = self._F.p.gen() if p.degree() == 1: return self._F((x % p)[0]) @@ -1658,7 +1658,7 @@ cdef class LiftingMap(Section): return self._K(self._K.ring_of_integers()(x)) else: return self._K(self._K.ring_of_integers()(x.polynomial().list())) - elif isinstance(self._K, PolynomialRing_general): + elif isinstance(self._K, PolynomialRing_generic): return self._K(x.polynomial().list()) # Else the lifting map is just x |--> to_order(x * PB) x = self._F(x) diff --git a/src/sage/rings/finite_rings/stdint.pxd b/src/sage/rings/finite_rings/stdint.pxd index b2b96a90c39..4e4cb6522d3 100644 --- a/src/sage/rings/finite_rings/stdint.pxd +++ b/src/sage/rings/finite_rings/stdint.pxd @@ -16,4 +16,3 @@ from libc.stdint cimport int_fast32_t, int_fast64_t cdef extern from "integer_mod_limits.h": int_fast32_t INTEGER_MOD_INT32_LIMIT int_fast64_t INTEGER_MOD_INT64_LIMIT - diff --git a/src/sage/rings/fraction_field_element.pyx b/src/sage/rings/fraction_field_element.pyx index bd8718da968..c8c91e88808 100644 --- a/src/sage/rings/fraction_field_element.pyx +++ b/src/sage/rings/fraction_field_element.pyx @@ -348,9 +348,9 @@ cdef class FractionFieldElement(FieldElement): This function hashes in a special way to ensure that generators of a ring `R` and generators of a fraction field of `R` have the same hash. This enables them to be used as keys interchangeably in a - dictionary (since ``==`` will claim them equal). This is particularly - useful for methods like ``subs`` on ``ParentWithGens`` if you are - passing a dictionary of substitutions. + dictionary (since ``==`` will claim them equal). + + This is useful for substitution using dicts. EXAMPLES:: diff --git a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py index e29626593b4..0b8d4cd32ff 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -38,7 +38,7 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.ore_polynomial_element import OrePolynomial -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.structure.parent import Parent from sage.structure.sage_object import SageObject from sage.structure.sequence import Sequence @@ -564,7 +564,7 @@ def __classcall_private__(cls, function_ring, gen, name='t'): # duplicate. As a general comment, there are sanity checks both # here and in the category constructor, which is not ideal. # Check domain is Fq[T] - if not isinstance(function_ring, PolynomialRing_general): + if not isinstance(function_ring, PolynomialRing_generic): raise NotImplementedError('function ring must be a polynomial ' 'ring') function_ring_base = function_ring.base_ring() diff --git a/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py index 2269085539d..9662572d5c0 100644 --- a/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/finite_drinfeld_module.py @@ -127,8 +127,8 @@ def __init__(self, gen, category): """ Initialize ``self``. - Validity of the input is checked in `__classcall_private__`. The - `__init__` just saves attributes. + Validity of the input is checked in ``__classcall_private__``. The + ``__init__`` just saves attributes. INPUT: @@ -469,7 +469,7 @@ def _frobenius_charpoly_CSA(self): Compute the characteristic polynomial of the Frobenius from the reduced characteristic polynomial of the Ore polynomial - `phi_T`. This algorithm is particularly interesting when the + `\phi_T`. This algorithm is particularly interesting when the rank of the Drinfeld module is large compared to the degree of the extension `K/\mathbb F_q`. See [CL2023]_. """ diff --git a/src/sage/rings/function_field/ideal.py b/src/sage/rings/function_field/ideal.py index 2ef9d20d132..640e2f53ae3 100644 --- a/src/sage/rings/function_field/ideal.py +++ b/src/sage/rings/function_field/ideal.py @@ -723,7 +723,7 @@ def module(self): """ return self._module - def gens(self): + def gens(self) -> tuple: """ Return a set of generators of this ideal. diff --git a/src/sage/rings/function_field/ideal_polymod.py b/src/sage/rings/function_field/ideal_polymod.py index 829598231cb..cedc8d3b273 100644 --- a/src/sage/rings/function_field/ideal_polymod.py +++ b/src/sage/rings/function_field/ideal_polymod.py @@ -579,7 +579,7 @@ def module(self): return V.span([to(g) for g in self.gens_over_base()], base_ring=O) @cached_method - def gens_over_base(self): + def gens_over_base(self) -> tuple: """ Return the generators of this ideal as a module over the maximal order of the base rational function field. @@ -624,7 +624,7 @@ def _gens_over_base(self): for row in self._hnf] return gens, self._denominator - def gens(self): + def gens(self) -> tuple: """ Return a set of generators of this ideal. @@ -1108,7 +1108,7 @@ def __pow__(self, mod): return generic_power(self, mod) - def gens(self): + def gens(self) -> tuple: """ Return a set of generators of this ideal. @@ -1134,10 +1134,9 @@ def gens(self): """ if self._gens_two.is_in_cache(): return self._gens_two.cache - else: - return self.gens_over_base() + return self.gens_over_base() - def gens_two(self): + def gens_two(self) -> tuple: r""" Return two generators of this fractional ideal. @@ -1173,7 +1172,7 @@ def gens_two(self): return tuple(e / d for e in self._gens_two()) @cached_method - def _gens_two(self): + def _gens_two(self) -> tuple: r""" Return a set of two generators of the integral ideal, that is the denominator times this fractional ideal. @@ -1556,7 +1555,7 @@ def _relative_degree(self): return self._ideal._relative_degree - def gens(self): + def gens(self) -> tuple: """ Return a set of generators of this ideal. @@ -1582,7 +1581,7 @@ def gens(self): iF, from_iF, to_iF = F._inversion_isomorphism() return tuple(from_iF(b) for b in self._ideal.gens()) - def gens_two(self): + def gens_two(self) -> tuple: """ Return a set of at most two generators of this ideal. @@ -1608,7 +1607,7 @@ def gens_two(self): iF, from_iF, to_iF = F._inversion_isomorphism() return tuple(from_iF(b) for b in self._ideal.gens_two()) - def gens_over_base(self): + def gens_over_base(self) -> tuple: """ Return a set of generators of this ideal. diff --git a/src/sage/rings/function_field/ideal_rational.py b/src/sage/rings/function_field/ideal_rational.py index 59c63cc9782..6cb21710e0d 100644 --- a/src/sage/rings/function_field/ideal_rational.py +++ b/src/sage/rings/function_field/ideal_rational.py @@ -252,7 +252,7 @@ def gen(self): """ return self._gen - def gens(self): + def gens(self) -> tuple: """ Return the tuple of the unique generator of this ideal. @@ -267,7 +267,7 @@ def gens(self): """ return (self._gen,) - def gens_over_base(self): + def gens_over_base(self) -> tuple: """ Return the generator of this ideal as a rank one module over the maximal order. @@ -548,7 +548,7 @@ def gen(self): """ return self._gen - def gens(self): + def gens(self) -> tuple: """ Return the generator of this principal ideal. @@ -563,7 +563,7 @@ def gens(self): """ return (self._gen,) - def gens_over_base(self): + def gens_over_base(self) -> tuple: """ Return the generator of this ideal as a rank one module over the infinite maximal order. diff --git a/src/sage/rings/function_field/jacobian_base.py b/src/sage/rings/function_field/jacobian_base.py index 405d90bfc3f..177ea6058ab 100644 --- a/src/sage/rings/function_field/jacobian_base.py +++ b/src/sage/rings/function_field/jacobian_base.py @@ -52,6 +52,7 @@ We can get the corresponding point in the Jacobian in a different model. :: + sage: # long time sage: p1km = J_km(p1) sage: p1km.order() 5 @@ -111,6 +112,7 @@ def order(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(29), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -640,6 +642,7 @@ def __call__(self, x): TESTS:: + sage: # long time sage: K. = FunctionField(GF(2)); _. = K[] sage: F. = K.extension(Y^2 + Y + x + 1/x) sage: J_hess = F.jacobian(model='hess') @@ -651,6 +654,26 @@ def __call__(self, x): True sage: J_hess(q) == p True + + If ``x`` is an effective divisor, it is checked that the degree + is equal to the degree of the base divisor. See :issue:`38623`. + + sage: K. = FunctionField(GF(7)) + sage: _. = K[] + sage: F. = K.extension(t^2 - x^6 - 3) + sage: O = F.maximal_order() + sage: D1 = (O.ideal(x + 1, y + 2) * O.ideal(x + 2, y + 2)).divisor() + sage: I = O.ideal(x + 3, y+5) * O.ideal(x + 4, y + 5) * O.ideal(x + 5, y + 5) + sage: D2 = I.divisor() + sage: J = F.jacobian(model='hess') + sage: J(D1) + [Place (x + 1, y + 2) + Place (x + 2, y + 2)] + sage: J(D2) + Traceback (most recent call last): + ... + ValueError: effective divisor is not of degree 2 + sage: J.base_divisor().degree() + 2 """ F = self._function_field if isinstance(x, JacobianPoint_base): @@ -666,9 +689,8 @@ def __call__(self, x): if x == 0: return self.group().zero() if x in F.divisor_group(): - G = self.group() - return G.point(x) - raise ValueError(f"Cannot create a point of the Jacobian from {x}") + return self.group()(x) + raise ValueError(f"cannot create a point of the Jacobian from {x}") def curve(self): """ diff --git a/src/sage/rings/function_field/jacobian_hess.py b/src/sage/rings/function_field/jacobian_hess.py index a85bc10e256..882b2eb917d 100644 --- a/src/sage/rings/function_field/jacobian_hess.py +++ b/src/sage/rings/function_field/jacobian_hess.py @@ -606,7 +606,7 @@ def _element_constructor_(self, x): """ Construct an element of ``self`` from ``x``. - If ``x`` is an effective divisor, then it is assumed to of + If ``x`` is an effective divisor, then it must be of degree `g`, the genus of the function field. EXAMPLES:: @@ -634,9 +634,11 @@ def _element_constructor_(self, x): if x.degree() == 0: return self.point(x) if x.is_effective(): + if x.degree() != self._genus: + raise ValueError(f"effective divisor is not of degree {self._genus}") return self.element_class(self, *self._get_dS_ds(x)) - raise ValueError(f"Cannot construct a point from {x}") + raise ValueError(f"cannot construct a point from {x}") def _get_dS_ds(self, divisor): """ @@ -805,6 +807,8 @@ def point(self, divisor): sage: G.point(p - b) [Place (y + 2, z + 1)] """ + if divisor.degree() != 0: + raise ValueError('divisor not of degree zero') c = divisor + self._base_div f = c.basis_function_space()[0] d = f.divisor() + c diff --git a/src/sage/rings/function_field/jacobian_khuri_makdisi.py b/src/sage/rings/function_field/jacobian_khuri_makdisi.py index 2c9a2e5da97..4a86a2d4a08 100644 --- a/src/sage/rings/function_field/jacobian_khuri_makdisi.py +++ b/src/sage/rings/function_field/jacobian_khuri_makdisi.py @@ -68,6 +68,7 @@ EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -154,6 +155,7 @@ class JacobianPoint(JacobianPoint_base): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -176,6 +178,7 @@ def __init__(self, parent, w): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -196,6 +199,7 @@ def _repr_(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -218,6 +222,7 @@ def __hash__(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -242,6 +247,7 @@ def _richcmp_(self, other, op): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -275,6 +281,7 @@ def _add_(self, other): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -306,6 +313,7 @@ def _neg_(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -340,6 +348,7 @@ def _rmul_(self, n): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -363,6 +372,7 @@ def multiple(self, n): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -394,6 +404,7 @@ def addflip(self, other): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -426,6 +437,7 @@ def defining_matrix(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -450,6 +462,7 @@ def divisor(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -493,6 +506,7 @@ class JacobianGroupEmbedding(Map): EXAMPLES:: + sage: # long time sage: k = GF(5) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + z^3 - y^2*z, P2) @@ -514,6 +528,7 @@ def __init__(self, base_group, extension_group): TESTS:: + sage: # long time sage: k = GF(5) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + z^3 - y^2*z, P2) @@ -538,6 +553,7 @@ def _repr_type(self): TESTS:: + sage: # long time sage: k = GF(5) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + z^3 - y^2*z, P2) @@ -561,6 +577,7 @@ def _call_(self, x): TESTS:: + sage: # long time sage: k = GF(5) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + z^3 - y^2*z, P2) @@ -592,6 +609,7 @@ class JacobianGroup(UniqueRepresentation, JacobianGroup_base): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -609,6 +627,7 @@ def __init__(self, parent, function_field, base_div): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -619,6 +638,7 @@ def __init__(self, parent, function_field, base_div): D0 = base_div + self._base_div_degree = base_div.degree() self._V_cache = 10*[None] V_cache = self._V_cache @@ -672,6 +692,7 @@ def _repr_(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -693,6 +714,7 @@ def _wd_from_divisor(self, x): TESTS: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -719,6 +741,7 @@ def _element_constructor_(self, x): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -760,10 +783,12 @@ def _element_constructor_(self, x): if x.degree() == 0: return self.point(x) if x.is_effective(): + if x.degree() != self._base_div_degree: + raise ValueError(f"effective divisor is not of degree {self._base_div_degree}") wd = self._wd_from_divisor(x) return self.element_class(self, wd) - raise ValueError(f"Cannot construct a point from {x}") + raise ValueError(f"cannot construct a point from {x}") def point(self, divisor): """ @@ -775,6 +800,7 @@ def point(self, divisor): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -808,6 +834,7 @@ def zero(self): EXAMPLES:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -839,6 +866,7 @@ class JacobianGroup_finite_field(JacobianGroup, JacobianGroup_finite_field_base) EXAMPLES:: + sage: # long time sage: k = GF(7) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) @@ -862,6 +890,7 @@ def __init__(self, parent, function_field, base_div): TESTS:: + sage: # long time sage: k = GF(7) sage: P2. = ProjectiveSpace(k, 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) @@ -952,6 +981,7 @@ def _frobenius_on(self, pt): TESTS:: + sage: # long time sage: k = GF(7) sage: A. = AffineSpace(k,2) sage: C = Curve(y^2 + x^3 + 2*x + 1).projective_closure() @@ -986,6 +1016,7 @@ def __init__(self, function_field, base_div, model, **kwds): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: J = C.jacobian(model='km_large') @@ -993,6 +1024,7 @@ def __init__(self, function_field, base_div, model, **kwds): :: + sage: # long time sage: J = C.jacobian(model='km_unknown') Traceback (most recent call last): ... diff --git a/src/sage/rings/function_field/khuri_makdisi.pyx b/src/sage/rings/function_field/khuri_makdisi.pyx index 5933abcd1ce..d32677bed6f 100644 --- a/src/sage/rings/function_field/khuri_makdisi.pyx +++ b/src/sage/rings/function_field/khuri_makdisi.pyx @@ -86,6 +86,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: k = GF(7) sage: A. = AffineSpace(k,2) sage: C = Curve(y^2 + x^3 + 2*x + 1).projective_closure() @@ -180,6 +181,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -205,6 +207,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -230,6 +233,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -255,6 +259,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -324,6 +329,7 @@ cdef class KhuriMakdisi_base(object): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -357,6 +363,7 @@ cdef class KhuriMakdisi_large(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -414,6 +421,7 @@ cdef class KhuriMakdisi_large(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: J = C.jacobian(model='km_large') @@ -476,6 +484,7 @@ cdef class KhuriMakdisi_large(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: F = C.function_field() @@ -507,6 +516,7 @@ cdef class KhuriMakdisi_large(KhuriMakdisi_base): TESTS:: + sage: # long time sage: k = GF(7) sage: A. = AffineSpace(k,2) sage: C = Curve(y^2 + x^3 + 2*x + 1).projective_closure() @@ -537,6 +547,7 @@ cdef class KhuriMakdisi_medium(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -588,6 +599,7 @@ cdef class KhuriMakdisi_medium(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -623,6 +635,7 @@ cdef class KhuriMakdisi_medium(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: h = C.function(y/x).divisor_of_poles() @@ -642,6 +655,7 @@ cdef class KhuriMakdisi_medium(KhuriMakdisi_base): We check the computation in other model:: + sage: # long time sage: J = C.jacobian(model='km_large', base_div=h) sage: G = J.group() sage: p1 = G.point(pl1 - b) @@ -671,6 +685,7 @@ cdef class KhuriMakdisi_medium(KhuriMakdisi_base): TESTS:: + sage: # long time sage: k = GF(7) sage: A. = AffineSpace(k,2) sage: C = Curve(y^2 + x^3 + 2*x + 1).projective_closure() @@ -702,6 +717,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -759,6 +775,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -793,6 +810,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(17), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -812,6 +830,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): We check the computation in other model:: + sage: # long time sage: h = C.function(y/x).divisor_of_poles() sage: Jl = C.jacobian(model='km_large', base_div=h) sage: G = J.group() @@ -840,6 +859,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): TESTS:: + sage: # long time sage: P2. = ProjectiveSpace(GF(7), 2) sage: C = Curve(x^3 + 5*z^3 - y^2*z, P2) sage: b = C([0,1,0]).place() @@ -851,13 +871,31 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): sage: p2 = G.point(pl2 - b) sage: -(-p1) == p1 # indirect doctest True + + Check that :issue:`39148` is fixed:: + + sage: # long time + sage: k. = FunctionField(GF(17)); t = polygen(k) + sage: F. = k.extension(t^4 + (14*x + 14)*t^3 + 9*t^2 + (10*x^2 + 15*x + 8)*t + ....: + 7*x^3 + 15*x^2 + 6*x + 16) + sage: infty1, infty2 = F.places_infinite() + sage: O = F.maximal_order() + sage: P = O.ideal((x + 1, y + 7)).divisor() + sage: D1 = 3*infty2 + infty1 - 4*P + sage: D2 = F.divisor_group().zero() + sage: J = F.jacobian(model='km-small', base_div=4*P) + sage: J(D1) + J(D2) == J(D1) + True """ cdef int d0 = self.d0 cdef int g = self.g cdef Matrix w1, w2, w3, w4 w1 = self.mu_image(self.wV2, wd, self.mu_mat23, 4*d0 - g + 1) - w2 = self.mu_preimage(self.wV3, w1, self.mu_mat23, d0) + # The row space of w2 represents H^0(O(2D_0 - D)), whose dimension is + # at least d0 - g + 1, and hence the codimension is at most d0. Thus, + # we cannot provide an expected_codim argument for mu_preimage. + w2 = self.mu_preimage(self.wV3, w1, self.mu_mat23) # efficient than # wf = matrix(w2[0]) # w3 = self.mu_image(wf, self.wV4, self.mu_mat24, 4*d0 - g + 1) @@ -874,6 +912,7 @@ cdef class KhuriMakdisi_small(KhuriMakdisi_base): TESTS:: + sage: # long time sage: k = GF(7) sage: A. = AffineSpace(k,2) sage: C = Curve(y^2 + x^3 + 2*x + 1).projective_closure() diff --git a/src/sage/rings/function_field/meson.build b/src/sage/rings/function_field/meson.build index 16e5fa6fa6f..0ed61989167 100644 --- a/src/sage/rings/function_field/meson.build +++ b/src/sage/rings/function_field/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'constructor.py', 'derivations.py', diff --git a/src/sage/rings/ideal.py b/src/sage/rings/ideal.py index dc785891828..96520442c49 100644 --- a/src/sage/rings/ideal.py +++ b/src/sage/rings/ideal.py @@ -280,7 +280,7 @@ def __init__(self, ring, gens, coerce=True, **kwds): gens = [ring(x) for x in gens] gens = tuple(gens) - if len(gens) == 0: + if not gens: gens = (ring.zero(),) self.__gens = gens MonoidElement.__init__(self, ring.ideal_monoid()) @@ -622,7 +622,7 @@ def reduce(self, f): """ return f # default - def gens(self): + def gens(self): # -> tuple | PolynomialSequence """ Return a set of generators / a basis of ``self``. diff --git a/src/sage/rings/integer.pyx b/src/sage/rings/integer.pyx index ffc5ee16e0f..da004072ccd 100644 --- a/src/sage/rings/integer.pyx +++ b/src/sage/rings/integer.pyx @@ -645,7 +645,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): mpz_set_pylong(self.value, x) elif isinstance(x, float): - n = long(x) + n = int(x) if n == x: mpz_set_pylong(self.value, n) else: @@ -684,7 +684,7 @@ cdef class Integer(sage.structure.element.EuclideanDomainElement): mpz_set_str_python(self.value, str_to_bytes(x), base) return - elif (isinstance(x, list) or isinstance(x, tuple)) and base > 1: + elif isinstance(x, (list, tuple)) and base > 1: b = the_integer_ring(base) if b == 2: # we use a faster method for j in range(len(x)): @@ -7434,7 +7434,7 @@ cdef class int_to_Z(Morphism): def __init__(self): import sage.categories.homset from sage.sets.pythonclass import Set_PythonType - Morphism.__init__(self, sage.categories.homset.Hom(Set_PythonType(long), integer_ring.ZZ)) + Morphism.__init__(self, sage.categories.homset.Hom(Set_PythonType(int), integer_ring.ZZ)) cpdef Element _call_(self, a): cdef Integer r diff --git a/src/sage/rings/integer_ring.pyx b/src/sage/rings/integer_ring.pyx index 346a67481e1..d6555ac0eab 100644 --- a/src/sage/rings/integer_ring.pyx +++ b/src/sage/rings/integer_ring.pyx @@ -1142,22 +1142,6 @@ cdef class IntegerRing_class(CommutativeRing): """ return 1 - def is_integrally_closed(self): - """ - Return that the integer ring is, in fact, integrally closed. - - .. NOTE:: - - This should rather be inherited from the category - of ``DedekindDomains``. - - EXAMPLES:: - - sage: ZZ.is_integrally_closed() - True - """ - return True - def completion(self, p, prec, extras={}): r""" Return the metric completion of the integers at the prime `p`. diff --git a/src/sage/rings/laurent_series_ring.py b/src/sage/rings/laurent_series_ring.py index 2142f717460..1feba6e675b 100644 --- a/src/sage/rings/laurent_series_ring.py +++ b/src/sage/rings/laurent_series_ring.py @@ -52,7 +52,7 @@ lazy_import('sage.rings.polynomial.laurent_polynomial_ring_base', 'LaurentPolynomialRing_generic') lazy_import('sage.rings.lazy_series_ring', ('LazyPowerSeriesRing', 'LazyLaurentSeriesRing')) -lazy_import('sage.rings.polynomial.polynomial_ring', 'PolynomialRing_general') +lazy_import('sage.rings.polynomial.polynomial_ring', 'PolynomialRing_generic') lazy_import('sage.rings.power_series_ring', 'PowerSeriesRing_generic') @@ -691,7 +691,7 @@ def _coerce_map_from_(self, P): if (isinstance(P, (LaurentSeriesRing, LazyLaurentSeriesRing, LaurentPolynomialRing_generic, PowerSeriesRing_generic, LazyPowerSeriesRing, - PolynomialRing_general)) + PolynomialRing_generic)) and P.variable_name() == self.variable_name() and A.has_coerce_map_from(P.base_ring())): return True diff --git a/src/sage/rings/laurent_series_ring_element.pxd b/src/sage/rings/laurent_series_ring_element.pxd index 8df5a92c9e7..3fc8e5dfffd 100644 --- a/src/sage/rings/laurent_series_ring_element.pxd +++ b/src/sage/rings/laurent_series_ring_element.pxd @@ -7,4 +7,3 @@ cdef class LaurentSeries(AlgebraElement): cdef _normalize(self) cpdef _add_(self, other) cpdef _mul_(self, other) - diff --git a/src/sage/rings/lazy_series.py b/src/sage/rings/lazy_series.py index b48e0e6bc38..6a4fea857a4 100644 --- a/src/sage/rings/lazy_series.py +++ b/src/sage/rings/lazy_series.py @@ -4203,8 +4203,8 @@ def __call__(self, g): if not isinstance(g, LazyModuleElement): # Check to see if it belongs to a polynomial ring # that we can extend to a lazy series ring - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if isinstance(P, PolynomialRing_general): + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(P, PolynomialRing_generic): from sage.rings.lazy_series_ring import LazyLaurentSeriesRing R = LazyLaurentSeriesRing(P.base_ring(), P.variable_names(), P.is_sparse()) g = R(P(g)) @@ -4948,7 +4948,6 @@ def compute_coefficients(self, i): """ 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): """ @@ -5203,7 +5202,7 @@ def __call__(self, *g): # f now has (potentially) infinitely many terms # Lift the resulting parent to a lazy series (if possible) # Also make sure each element of g is a LazyModuleElement - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing_univariate from sage.rings.lazy_series_ring import LazySeriesRing @@ -5211,7 +5210,7 @@ def __call__(self, *g): if fP._laurent_poly_ring.has_coerce_map_from(P): S = fP._laurent_poly_ring P = fP - if isinstance(P, (PolynomialRing_general, MPolynomialRing_base)): + if isinstance(P, (PolynomialRing_generic, MPolynomialRing_base)): from sage.rings.lazy_series_ring import LazyPowerSeriesRing S = P try: diff --git a/src/sage/rings/lazy_series_ring.py b/src/sage/rings/lazy_series_ring.py index a5900982a3a..51359391111 100644 --- a/src/sage/rings/lazy_series_ring.py +++ b/src/sage/rings/lazy_series_ring.py @@ -1604,7 +1604,7 @@ def ngens(self): return 1 @cached_method - def gens(self): + def gens(self) -> tuple: """ Return the generators of ``self``. @@ -2168,7 +2168,7 @@ def ngens(self): return len(self.variable_names()) @cached_method - def gens(self): + def gens(self) -> tuple: """ Return the generators of ``self``. diff --git a/src/sage/rings/localization.py b/src/sage/rings/localization.py index ab6916d36c8..8ac31a6ff67 100644 --- a/src/sage/rings/localization.py +++ b/src/sage/rings/localization.py @@ -180,7 +180,7 @@ from sage.structure.unique_representation import UniqueRepresentation from sage.categories.integral_domains import IntegralDomains -from sage.rings.ring import IntegralDomain +from sage.structure.parent import Parent from sage.structure.element import IntegralDomainElement @@ -193,7 +193,7 @@ def normalize_extra_units(base_ring, add_units, warning=True): INPUT: - - ``base_ring`` -- an instance of :class:`IntegralDomain` + - ``base_ring`` -- a ring in the category of :class:`IntegralDomains` - ``add_units`` -- list of elements from base ring - ``warning`` -- boolean (default: ``True``); to suppress a warning which is thrown if no normalization was possible @@ -561,7 +561,7 @@ def _integer_(self, Z=None): return self._value._integer_(Z=Z) -class Localization(IntegralDomain, UniqueRepresentation): +class Localization(Parent, UniqueRepresentation): r""" The localization generalizes the construction of the field of fractions of an integral domain to an arbitrary ring. Given a (not necessarily @@ -580,21 +580,18 @@ class Localization(IntegralDomain, UniqueRepresentation): this class relies on the construction of the field of fraction and is therefore restricted to integral domains. - Accordingly, this class is inherited from :class:`IntegralDomain` and can - only be used in that context. Furthermore, the base ring should support + Accordingly, the base ring must be in the category of ``IntegralDomains``. + Furthermore, the base ring should support :meth:`sage.structure.element.CommutativeRingElement.divides` and the exact division operator ``//`` (:meth:`sage.structure.element.Element.__floordiv__`) in order to guarantee a successful application. INPUT: - - ``base_ring`` -- an instance of :class:`Ring` allowing the construction - of :meth:`fraction_field` (that is an integral domain) + - ``base_ring`` -- a ring in the category of ``IntegralDomains`` - ``extra_units`` -- tuple of elements of ``base_ring`` which should be turned into units - - ``names`` -- passed to :class:`IntegralDomain` - - ``normalize`` -- boolean (default: ``True``); passed to :class:`IntegralDomain` - - ``category`` -- (default: ``None``) passed to :class:`IntegralDomain` + - ``category`` -- (default: ``None``) passed to :class:`Parent` - ``warning`` -- boolean (default: ``True``); to suppress a warning which is thrown if ``self`` cannot be represented uniquely @@ -712,7 +709,7 @@ def __init__(self, base_ring, extra_units, names=None, normalize=True, category= # since by construction the base ring must contain non units self must be infinite category = IntegralDomains().Infinite() - IntegralDomain.__init__(self, base_ring, names=names, normalize=normalize, category=category) + Parent.__init__(self, base=base_ring, names=names, normalize=normalize, category=category) self._extra_units = tuple(extra_units) self._fraction_field = base_ring.fraction_field() self._populate_coercion_lists_() @@ -841,7 +838,7 @@ def gen(self, i): """ return self(self.base_ring().gen(i)) - def gens(self): + def gens(self) -> tuple: """ Return a tuple whose entries are the generators for this object, in order. diff --git a/src/sage/rings/meson.build b/src/sage/rings/meson.build index 171592eccbd..5f4dafdf7c2 100644 --- a/src/sage/rings/meson.build +++ b/src/sage/rings/meson.build @@ -1,8 +1,8 @@ py.install_sources( + '__init__.py', 'abc.pxd', 'algebraic_closure_finite_field.py', 'all.py', - 'all__sagemath_categories.py', 'all__sagemath_objects.py', 'big_oh.py', 'cc.py', diff --git a/src/sage/rings/morphism.pyx b/src/sage/rings/morphism.pyx index 3079bfa3974..0aa710b4fa9 100644 --- a/src/sage/rings/morphism.pyx +++ b/src/sage/rings/morphism.pyx @@ -1036,7 +1036,7 @@ cdef class RingHomomorphism(RingMap): from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic from sage.rings.quotient_ring import QuotientRing_nc from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic B = self.codomain() graph, from_B, to_A = self._graph_ideal() Q = graph.ring() @@ -1045,8 +1045,10 @@ cdef class RingHomomorphism(RingMap): # avoid adding the 0-ideal to the graph ideal in order to benefit # from a cached Gröbner basis graph_I = graph - elif (isinstance(B, MPolynomialRing_base) or isinstance(B, PolynomialRing_general) - or isinstance(B, QuotientRing_nc) or isinstance(B, PolynomialQuotientRing_generic)): + elif isinstance(B, (MPolynomialRing_base, + PolynomialRing_generic, + QuotientRing_nc, + PolynomialQuotientRing_generic)): graph_I = graph + from_B(I) else: # nonzero fractional ideals of number fields not yet supported @@ -3137,7 +3139,7 @@ def _tensor_product_ring(B, A): from sage.rings.number_field.number_field_base import NumberField from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base from sage.rings.polynomial.polynomial_quotient_ring import PolynomialQuotientRing_generic - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.term_order import TermOrder from sage.rings.quotient_ring import QuotientRing_nc @@ -3150,7 +3152,7 @@ def _tensor_product_ring(B, A): def term_order(A): # univariate rings do not have a term order - if (isinstance(A, PolynomialRing_general) or isinstance(A, PolynomialQuotientRing_generic) + if (isinstance(A, (PolynomialRing_generic, PolynomialQuotientRing_generic)) or (isinstance(A, (NumberField, FiniteField)) and not A.is_prime_field())): return TermOrder('lex', 1) @@ -3166,7 +3168,7 @@ def _tensor_product_ring(B, A): order=term_order(B) + term_order(A)) def relations(A, R_gens_A): - if isinstance(A, MPolynomialRing_base) or isinstance(A, PolynomialRing_general): + if isinstance(A, (MPolynomialRing_base, PolynomialRing_generic)): return [] elif isinstance(A, PolynomialQuotientRing_generic): to_R = A.ambient().hom(R_gens_A, R, check=False) diff --git a/src/sage/rings/multi_power_series_ring.py b/src/sage/rings/multi_power_series_ring.py index 3a30b89b9e9..43f446a7e09 100644 --- a/src/sage/rings/multi_power_series_ring.py +++ b/src/sage/rings/multi_power_series_ring.py @@ -208,7 +208,7 @@ from sage.misc.lazy_import import lazy_import from sage.rings.infinity import infinity from sage.rings.multi_power_series_ring_element import MPowerSeries -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base from sage.rings.polynomial.term_order import TermOrder @@ -674,7 +674,7 @@ def _coerce_impl(self, f): True """ P = f.parent() - if isinstance(P, (PolynomialRing_general, MPolynomialRing_base, + if isinstance(P, (PolynomialRing_generic, MPolynomialRing_base, PowerSeriesRing_generic, MPowerSeriesRing_generic, LazyPowerSeriesRing)): if set(P.variable_names()).issubset(set(self.variable_names())): @@ -841,7 +841,7 @@ def _coerce_map_from_(self, P): True """ if isinstance(P, (MPolynomialRing_base, MPowerSeriesRing_generic, LazyPowerSeriesRing, - PolynomialRing_general, PowerSeriesRing_generic)): + PolynomialRing_generic, PowerSeriesRing_generic)): if set(P.variable_names()).issubset(set(self.variable_names())): if self.has_coerce_map_from(P.base_ring()): return True diff --git a/src/sage/rings/multi_power_series_ring_element.py b/src/sage/rings/multi_power_series_ring_element.py index 9c27ba678bb..5f8bba84c49 100644 --- a/src/sage/rings/multi_power_series_ring_element.py +++ b/src/sage/rings/multi_power_series_ring_element.py @@ -158,7 +158,7 @@ from sage.rings.finite_rings.integer_mod_ring import Zmod from sage.rings.infinity import infinity, InfinityElement from sage.rings.integer import Integer -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.power_series_ring_element import PowerSeries from sage.structure.richcmp import richcmp @@ -406,7 +406,7 @@ def __init__(self, parent, x=0, prec=infinity, is_gen=False, check=False): self._bg_value = parent._send_to_bg(x).add_bigoh(prec) # test whether x coerces to underlying polynomial ring of parent - elif isinstance(xparent, PolynomialRing_general): + elif isinstance(xparent, PolynomialRing_generic): self._bg_value = parent._send_to_bg(x).add_bigoh(prec) else: @@ -1099,7 +1099,7 @@ def __mod__(self, other): return self.change_ring(Zmod(other)) raise NotImplementedError("Mod on multivariate power series ring elements not defined except modulo an integer.") - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return underlying dictionary with keys the exponents and values the coefficients of this power series. diff --git a/src/sage/rings/number_field/class_group.py b/src/sage/rings/number_field/class_group.py index 34a48931f8e..e1185a499bb 100644 --- a/src/sage/rings/number_field/class_group.py +++ b/src/sage/rings/number_field/class_group.py @@ -303,7 +303,7 @@ def representative_prime(self, norm_bound=1000): return P raise RuntimeError("No prime of norm less than %s found in class %s" % (norm_bound, c)) - def gens(self): + def gens(self) -> tuple: r""" Return generators for a representative ideal in this (`S`-)ideal class. diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index c974c3df6ff..bb4e453c650 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -994,7 +994,7 @@ def artin_symbol(self, P): sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^4 - 2*x^2 + 2, 'a').galois_closure() sage: G = K.galois_group() - sage: [G.artin_symbol(P) for P in K.primes_above(7)] + sage: [G.artin_symbol(P) for P in K.primes_above(7)] # random (see remark in primes_above) [(1,4)(2,3)(5,8)(6,7), (1,4)(2,3)(5,8)(6,7), (1,5)(2,6)(3,7)(4,8), (1,5)(2,6)(3,7)(4,8)] sage: G.artin_symbol(17) diff --git a/src/sage/rings/number_field/homset.py b/src/sage/rings/number_field/homset.py index 62ca214754d..49f309fdd34 100644 --- a/src/sage/rings/number_field/homset.py +++ b/src/sage/rings/number_field/homset.py @@ -195,14 +195,12 @@ def list(self): sage: x = polygen(ZZ, 'x') sage: K. = NumberField(x^3 - 3*x + 1) sage: End(K).list() - [ - Ring endomorphism of Number Field in a with defining polynomial x^3 - 3*x + 1 - Defn: a |--> a, - Ring endomorphism of Number Field in a with defining polynomial x^3 - 3*x + 1 - Defn: a |--> a^2 - 2, - Ring endomorphism of Number Field in a with defining polynomial x^3 - 3*x + 1 - Defn: a |--> -a^2 - a + 2 - ] + [Ring endomorphism of Number Field in a with defining polynomial x^3 - 3*x + 1 + Defn: a |--> a, + Ring endomorphism of Number Field in a with defining polynomial x^3 - 3*x + 1 + Defn: a |--> a^2 - 2, + Ring endomorphism of Number Field in a with defining polynomial x^3 - 3*x + 1 + Defn: a |--> -a^2 - a + 2] sage: Hom(K, CyclotomicField(9))[0] # indirect doctest Ring morphism: From: Number Field in a with defining polynomial x^3 - 3*x + 1 @@ -214,20 +212,18 @@ def list(self): sage: K. = NumberField(x^3 - 2) sage: L. = K.extension(x^2 + 3) sage: Hom(K, L).list() - [ - Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Number Field in b with defining polynomial x^2 + 3 over its base field - Defn: a |--> a, - Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Number Field in b with defining polynomial x^2 + 3 over its base field - Defn: a |--> -1/2*a*b - 1/2*a, - Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Number Field in b with defining polynomial x^2 + 3 over its base field - Defn: a |--> 1/2*a*b - 1/2*a - ] + [Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Number Field in b with defining polynomial x^2 + 3 over its base field + Defn: a |--> a, + Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Number Field in b with defining polynomial x^2 + 3 over its base field + Defn: a |--> -1/2*a*b - 1/2*a, + Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Number Field in b with defining polynomial x^2 + 3 over its base field + Defn: a |--> 1/2*a*b - 1/2*a] """ D = self.domain() C = self.codomain() @@ -479,36 +475,30 @@ def list(self): sage: x = polygen(ZZ, 'x') sage: K. = NumberField([x^2 + x + 1, x^3 + 2]) sage: End(K).list() - [ - Relative number field endomorphism of - Number Field in a with defining polynomial x^2 + x + 1 over its base field - Defn: a |--> a - b |--> b, - ... - Relative number field endomorphism of - Number Field in a with defining polynomial x^2 + x + 1 over its base field - Defn: a |--> a - b |--> -b*a - b - ] + [Relative number field endomorphism of Number Field in a with defining polynomial x^2 + x + 1 over its base field + Defn: a |--> a + b |--> b, + ... + Relative number field endomorphism of Number Field in a with defining polynomial x^2 + x + 1 over its base field + Defn: a |--> a + b |--> -b*a - b] An example with an absolute codomain:: sage: x = polygen(ZZ, 'x') sage: K. = NumberField([x^2 - 3, x^2 + 2]) sage: Hom(K, CyclotomicField(24, 'z')).list() - [ - Relative number field morphism: - From: Number Field in a with defining polynomial x^2 - 3 over its base field - To: Cyclotomic Field of order 24 and degree 8 - Defn: a |--> z^6 - 2*z^2 - b |--> -z^5 - z^3 + z, - ... - Relative number field morphism: - From: Number Field in a with defining polynomial x^2 - 3 over its base field - To: Cyclotomic Field of order 24 and degree 8 - Defn: a |--> -z^6 + 2*z^2 - b |--> z^5 + z^3 - z - ] + [Relative number field morphism: + From: Number Field in a with defining polynomial x^2 - 3 over its base field + To: Cyclotomic Field of order 24 and degree 8 + Defn: a |--> z^6 - 2*z^2 + b |--> -z^5 - z^3 + z, + ... + Relative number field morphism: + From: Number Field in a with defining polynomial x^2 - 3 over its base field + To: Cyclotomic Field of order 24 and degree 8 + Defn: a |--> -z^6 + 2*z^2 + b |--> z^5 + z^3 - z] """ D = self.domain() C = self.codomain() diff --git a/src/sage/rings/number_field/meson.build b/src/sage/rings/number_field/meson.build index 46162077eb8..5b612679d40 100644 --- a/src/sage/rings/number_field/meson.build +++ b/src/sage/rings/number_field/meson.build @@ -1,5 +1,6 @@ py.install_sources( 'S_unit_solver.py', + '__init__.py', 'all.py', 'bdd_height.py', 'class_group.py', diff --git a/src/sage/rings/number_field/number_field.py b/src/sage/rings/number_field/number_field.py index 7128d40032e..fa9c452c961 100644 --- a/src/sage/rings/number_field/number_field.py +++ b/src/sage/rings/number_field/number_field.py @@ -75,10 +75,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** from __future__ import annotations +from itertools import count +from collections import Counter + from sage.misc.cachefunc import cached_method from sage.misc.superseded import deprecation - import sage.libs.ntl.all as ntl import sage.rings.abc import sage.rings.complex_mpfr @@ -99,7 +101,6 @@ from sage.rings.finite_rings.integer_mod import mod from sage.categories.number_fields import NumberFields -from sage.rings.ring import Ring from sage.misc.latex import latex_variable_name from .unit_group import UnitGroup @@ -118,8 +119,6 @@ from . import maps from . import structure from . import number_field_morphisms -from itertools import count -from collections import Counter from sage.categories.homset import Hom from sage.categories.sets_cat import Sets @@ -128,6 +127,7 @@ from sage.rings.real_mpfr import RR from sage.interfaces.abc import GapElement +from sage.rings.number_field.morphism import RelativeNumberFieldHomomorphism_from_abs lazy_import('sage.libs.gap.element', 'GapElement', as_='LibGapElement') lazy_import('sage.rings.universal_cyclotomic_field', 'UniversalCyclotomicFieldElement') @@ -136,13 +136,12 @@ _NumberFields = NumberFields() -from sage.rings.number_field.morphism import RelativeNumberFieldHomomorphism_from_abs - - def is_NumberFieldHomsetCodomain(codomain): """ Return whether ``codomain`` is a valid codomain for a number - field homset. This is used by NumberField._Hom_ to determine + field homset. + + This is used by NumberField._Hom_ to determine whether the created homsets should be a :class:`sage.rings.number_field.homset.NumberFieldHomset`. @@ -414,8 +413,8 @@ def NumberField(polynomial, name=None, check=True, names=None, embedding=None, sage: RR(g) -1.25992104989487 - If no embedding is specified or is complex, the comparison is not returning something - meaningful.:: + If no embedding is specified or is complex, the comparison is not + returning something meaningful. :: sage: N. = NumberField(x^3 + 2) sage: 1 < g @@ -1762,8 +1761,8 @@ def _element_constructor_(self, x, check=True): return self._convert_from_str(s.replace('!', '')) elif isinstance(x, str): return self._convert_from_str(x) - elif (isinstance(x, (tuple, list)) or - isinstance(x, sage.modules.free_module_element.FreeModuleElement)): + elif isinstance(x, (tuple, list, + sage.modules.free_module_element.FreeModuleElement)): if len(x) != self.relative_degree(): raise ValueError("Length must be equal to the degree of this number field") base = self.base_ring() @@ -3142,26 +3141,20 @@ def real_embeddings(self, prec=53): sage: x = polygen(QQ, 'x') sage: K. = NumberField(x^3 + 2) sage: K.real_embeddings() - [ - Ring morphism: - From: Number Field in a with defining polynomial x^3 + 2 - To: Real Field with 53 bits of precision - Defn: a |--> -1.25992104989487 - ] + [Ring morphism: + From: Number Field in a with defining polynomial x^3 + 2 + To: Real Field with 53 bits of precision + Defn: a |--> -1.25992104989487] sage: K.real_embeddings(16) - [ - Ring morphism: - From: Number Field in a with defining polynomial x^3 + 2 - To: Real Field with 16 bits of precision - Defn: a |--> -1.260 - ] + [Ring morphism: + From: Number Field in a with defining polynomial x^3 + 2 + To: Real Field with 16 bits of precision + Defn: a |--> -1.260] sage: K.real_embeddings(100) - [ - Ring morphism: - From: Number Field in a with defining polynomial x^3 + 2 - To: Real Field with 100 bits of precision - Defn: a |--> -1.2599210498948731647672106073 - ] + [Ring morphism: + From: Number Field in a with defining polynomial x^3 + 2 + To: Real Field with 100 bits of precision + Defn: a |--> -1.2599210498948731647672106073] As this is a numerical function, the number of embeddings may be incorrect if the precision is too low:: @@ -3726,6 +3719,9 @@ def primes_above(self, x, degree=None): The output is sorted by residue degree first, then by underlying prime (or equivalently, by norm). + If there is a tie, the exact ordering should be assumed to be random. + See the remark in :meth:`NumberFieldIdeal._richcmp_`. + EXAMPLES:: sage: x = ZZ['x'].gen() @@ -6245,13 +6241,11 @@ def galois_group(self, type=None, algorithm='pari', names=None, gc_numbering=Non sage: G = End(L); G Automorphism group of Number Field in b1 with defining polynomial x^6 + 108 sage: G.list() - [ - Ring endomorphism of Number Field in b1 with defining polynomial x^6 + 108 - Defn: b1 |--> b1, - ... - Ring endomorphism of Number Field in b1 with defining polynomial x^6 + 108 - Defn: b1 |--> -1/12*b1^4 - 1/2*b1 - ] + [Ring endomorphism of Number Field in b1 with defining polynomial x^6 + 108 + Defn: b1 |--> b1, + ... + Ring endomorphism of Number Field in b1 with defining polynomial x^6 + 108 + Defn: b1 |--> -1/12*b1^4 - 1/2*b1] sage: G[2](b1) 1/12*b1^4 + 1/2*b1 @@ -8662,40 +8656,52 @@ def optimized_subfields(self, degree=0, name=None, both_maps=True): polynomials are supported (:issue:`252`):: sage: K. = NumberField(2*x^4 + 6*x^2 + 1/2) - sage: K.optimized_subfields() - [ - (Number Field in a0 with defining polynomial x, Ring morphism: - From: Number Field in a0 with defining polynomial x - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: 0 |--> 0, None), - (Number Field in a1 with defining polynomial x^2 - 2*x + 2, Ring morphism: - From: Number Field in a1 with defining polynomial x^2 - 2*x + 2 - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: a1 |--> a^3 + 7/2*a + 1, None), - (Number Field in a2 with defining polynomial x^2 - 2*x + 2, Ring morphism: - From: Number Field in a2 with defining polynomial x^2 - 2*x + 2 - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: a2 |--> -a^3 - 7/2*a + 1, None), - (Number Field in a3 with defining polynomial x^2 - 2, Ring morphism: - From: Number Field in a3 with defining polynomial x^2 - 2 - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: a3 |--> a^2 + 3/2, None), - (Number Field in a4 with defining polynomial x^2 + 1, Ring morphism: - From: Number Field in a4 with defining polynomial x^2 + 1 - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: a4 |--> a^3 + 7/2*a, None), - (Number Field in a5 with defining polynomial x^2 + 2, Ring morphism: - From: Number Field in a5 with defining polynomial x^2 + 2 - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: a5 |--> 2*a^3 + 5*a, None), - (Number Field in a6 with defining polynomial x^4 + 1, Ring morphism: - From: Number Field in a6 with defining polynomial x^4 + 1 - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: a6 |--> a^3 + 1/2*a^2 + 5/2*a + 3/4, Ring morphism: - From: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - To: Number Field in a6 with defining polynomial x^4 + 1 - Defn: a |--> -1/2*a6^3 + a6^2 - 1/2*a6) - ] + sage: K.optimized_subfields() # random + [(Number Field in a0 with defining polynomial x, + Ring morphism: + From: Number Field in a0 with defining polynomial x + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: 0 |--> 0, + None), + (Number Field in a1 with defining polynomial x^2 - 2*x + 2, + Ring morphism: + From: Number Field in a1 with defining polynomial x^2 - 2*x + 2 + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: a1 |--> a^3 + 7/2*a + 1, + None), + (Number Field in a2 with defining polynomial x^2 - 2*x + 2, + Ring morphism: + From: Number Field in a2 with defining polynomial x^2 - 2*x + 2 + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: a2 |--> -a^3 - 7/2*a + 1, + None), + (Number Field in a3 with defining polynomial x^2 - 2, + Ring morphism: + From: Number Field in a3 with defining polynomial x^2 - 2 + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: a3 |--> a^2 + 3/2, + None), + (Number Field in a4 with defining polynomial x^2 + 1, + Ring morphism: + From: Number Field in a4 with defining polynomial x^2 + 1 + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: a4 |--> a^3 + 7/2*a, + None), + (Number Field in a5 with defining polynomial x^2 + 2, + Ring morphism: + From: Number Field in a5 with defining polynomial x^2 + 2 + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: a5 |--> 2*a^3 + 5*a, + None), + (Number Field in a6 with defining polynomial x^4 + 1, + Ring morphism: + From: Number Field in a6 with defining polynomial x^4 + 1 + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: a6 |--> a^3 + 1/2*a^2 + 5/2*a + 3/4, + Ring morphism: + From: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + To: Number Field in a6 with defining polynomial x^4 + 1 + Defn: a |--> -1/2*a6^3 + a6^2 - 1/2*a6)] """ return self._subfields_helper(degree=degree, name=name, both_maps=both_maps, optimize=True) @@ -8774,32 +8780,40 @@ def subfields(self, degree=0, name=None): polynomials are supported (:issue:`252`):: sage: K. = NumberField(2*x^4 + 6*x^2 + 1/2) - sage: K.subfields() - [ - (Number Field in a0 with defining polynomial x, Ring morphism: - From: Number Field in a0 with defining polynomial x - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: 0 |--> 0, None), - (Number Field in a1 with defining polynomial x^2 - 2, Ring morphism: - From: Number Field in a1 with defining polynomial x^2 - 2 - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: a1 |--> a^2 + 3/2, None), - (Number Field in a2 with defining polynomial x^2 + 4, Ring morphism: - From: Number Field in a2 with defining polynomial x^2 + 4 - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: a2 |--> 2*a^3 + 7*a, None), - (Number Field in a3 with defining polynomial x^2 + 2, Ring morphism: - From: Number Field in a3 with defining polynomial x^2 + 2 - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: a3 |--> 2*a^3 + 5*a, None), - (Number Field in a4 with defining polynomial x^4 + 1, Ring morphism: - From: Number Field in a4 with defining polynomial x^4 + 1 - To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - Defn: a4 |--> a^3 + 1/2*a^2 + 5/2*a + 3/4, Ring morphism: - From: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 - To: Number Field in a4 with defining polynomial x^4 + 1 - Defn: a |--> -1/2*a4^3 + a4^2 - 1/2*a4) - ] + sage: sorted(K.subfields(), key=lambda x: x[0].discriminant()) + [(Number Field in a3 with defining polynomial x^2 + 2, + Ring morphism: + From: Number Field in a3 with defining polynomial x^2 + 2 + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: a3 |--> 2*a^3 + 5*a, + None), + (Number Field in a2 with defining polynomial x^2 + 4, + Ring morphism: + From: Number Field in a2 with defining polynomial x^2 + 4 + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: a2 |--> 2*a^3 + 7*a, + None), + (Number Field in a0 with defining polynomial x, + Ring morphism: + From: Number Field in a0 with defining polynomial x + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: 0 |--> 0, + None), + (Number Field in a1 with defining polynomial x^2 - 2, + Ring morphism: + From: Number Field in a1 with defining polynomial x^2 - 2 + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: a1 |--> a^2 + 3/2, + None), + (Number Field in a4 with defining polynomial x^4 + 1, + Ring morphism: + From: Number Field in a4 with defining polynomial x^4 + 1 + To: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + Defn: a4 |--> a^3 + 1/2*a^2 + 5/2*a + 3/4, + Ring morphism: + From: Number Field in a with defining polynomial 2*x^4 + 6*x^2 + 1/2 + To: Number Field in a4 with defining polynomial x^4 + 1 + Defn: a |--> -1/2*a4^3 + a4^2 - 1/2*a4)] """ return self._subfields_helper(degree=degree, name=name, both_maps=True, optimize=False) @@ -9236,12 +9250,10 @@ def automorphisms(self): sage: x = polygen(QQ, 'x') sage: K. = NumberField(x^2 + 10000) sage: K.automorphisms() - [ - Ring endomorphism of Number Field in a with defining polynomial x^2 + 10000 - Defn: a |--> a, - Ring endomorphism of Number Field in a with defining polynomial x^2 + 10000 - Defn: a |--> -a - ] + [Ring endomorphism of Number Field in a with defining polynomial x^2 + 10000 + Defn: a |--> a, + Ring endomorphism of Number Field in a with defining polynomial x^2 + 10000 + Defn: a |--> -a] Here's a larger example, that would take some time if we found roots instead of using PARI's specialized machinery:: @@ -9266,14 +9278,12 @@ def automorphisms(self): sage: f = 7/9*x^3 + 7/3*x^2 - 56*x + 123 sage: K. = NumberField(f) sage: A = K.automorphisms(); A - [ - Ring endomorphism of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 - Defn: a |--> a, - Ring endomorphism of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 - Defn: a |--> -7/15*a^2 - 18/5*a + 96/5, - Ring endomorphism of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 - Defn: a |--> 7/15*a^2 + 13/5*a - 111/5 - ] + [Ring endomorphism of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 + Defn: a |--> a, + Ring endomorphism of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 + Defn: a |--> -7/15*a^2 - 18/5*a + 96/5, + Ring endomorphism of Number Field in a with defining polynomial 7/9*x^3 + 7/3*x^2 - 56*x + 123 + Defn: a |--> 7/15*a^2 + 13/5*a - 111/5] sage: prod(x - sigma(a) for sigma in A) == f.monic() True """ @@ -9313,73 +9323,63 @@ def embeddings(self, K): sage: L. = QuadraticField(-7) sage: K = CyclotomicField(7) sage: L.embeddings(K) - [ - Ring morphism: - From: Number Field in a with defining polynomial x^2 + 7 - with a = 2.645751311064591?*I - To: Cyclotomic Field of order 7 and degree 6 - Defn: a |--> 2*zeta7^4 + 2*zeta7^2 + 2*zeta7 + 1, - Ring morphism: - From: Number Field in a with defining polynomial x^2 + 7 - with a = 2.645751311064591?*I - To: Cyclotomic Field of order 7 and degree 6 - Defn: a |--> -2*zeta7^4 - 2*zeta7^2 - 2*zeta7 - 1 - ] + [Ring morphism: + From: Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I + To: Cyclotomic Field of order 7 and degree 6 + Defn: a |--> 2*zeta7^4 + 2*zeta7^2 + 2*zeta7 + 1, + Ring morphism: + From: Number Field in a with defining polynomial x^2 + 7 with a = 2.645751311064591?*I + To: Cyclotomic Field of order 7 and degree 6 + Defn: a |--> -2*zeta7^4 - 2*zeta7^2 - 2*zeta7 - 1] We embed a cubic field in the complex numbers:: sage: x = polygen(QQ, 'x') sage: K. = NumberField(x^3 - 2) - sage: K.embeddings(CC) - [ - Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Complex Field with 53 bits of precision - Defn: a |--> -0.62996052494743... - 1.09112363597172*I, - Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Complex Field with 53 bits of precision - Defn: a |--> -0.62996052494743... + 1.09112363597172*I, - Ring morphism: - From: Number Field in a with defining polynomial x^3 - 2 - To: Complex Field with 53 bits of precision - Defn: a |--> 1.25992104989487 - ] + sage: K.embeddings(CC) # abs tol 1e-12 + [Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Complex Field with 53 bits of precision + Defn: a |--> -0.629960524947437 - 1.09112363597172*I, + Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Complex Field with 53 bits of precision + Defn: a |--> -0.629960524947437 + 1.09112363597172*I, + Ring morphism: + From: Number Field in a with defining polynomial x^3 - 2 + To: Complex Field with 53 bits of precision + Defn: a |--> 1.25992104989487] Some more (possible and impossible) embeddings of cyclotomic fields:: sage: CyclotomicField(5).embeddings(QQbar) - [ - Ring morphism: - From: Cyclotomic Field of order 5 and degree 4 - To: Algebraic Field - Defn: zeta5 |--> 0.3090169943749474? + 0.9510565162951536?*I, - Ring morphism: - From: Cyclotomic Field of order 5 and degree 4 - To: Algebraic Field - Defn: zeta5 |--> -0.8090169943749474? + 0.5877852522924731?*I, - Ring morphism: - From: Cyclotomic Field of order 5 and degree 4 - To: Algebraic Field - Defn: zeta5 |--> -0.8090169943749474? - 0.5877852522924731?*I, - Ring morphism: - From: Cyclotomic Field of order 5 and degree 4 - To: Algebraic Field - Defn: zeta5 |--> 0.3090169943749474? - 0.9510565162951536?*I - ] + [Ring morphism: + From: Cyclotomic Field of order 5 and degree 4 + To: Algebraic Field + Defn: zeta5 |--> 0.3090169943749474? + 0.9510565162951536?*I, + Ring morphism: + From: Cyclotomic Field of order 5 and degree 4 + To: Algebraic Field + Defn: zeta5 |--> -0.8090169943749474? + 0.5877852522924731?*I, + Ring morphism: + From: Cyclotomic Field of order 5 and degree 4 + To: Algebraic Field + Defn: zeta5 |--> -0.8090169943749474? - 0.5877852522924731?*I, + Ring morphism: + From: Cyclotomic Field of order 5 and degree 4 + To: Algebraic Field + Defn: zeta5 |--> 0.3090169943749474? - 0.9510565162951536?*I] sage: CyclotomicField(3).embeddings(CyclotomicField(7)) - [ ] + [] sage: CyclotomicField(3).embeddings(CyclotomicField(6)) - [ - Ring morphism: - From: Cyclotomic Field of order 3 and degree 2 - To: Cyclotomic Field of order 6 and degree 2 - Defn: zeta3 |--> zeta6 - 1, - Ring morphism: - From: Cyclotomic Field of order 3 and degree 2 - To: Cyclotomic Field of order 6 and degree 2 - Defn: zeta3 |--> -zeta6 - ] + [Ring morphism: + From: Cyclotomic Field of order 3 and degree 2 + To: Cyclotomic Field of order 6 and degree 2 + Defn: zeta3 |--> zeta6 - 1, + Ring morphism: + From: Cyclotomic Field of order 3 and degree 2 + To: Cyclotomic Field of order 6 and degree 2 + Defn: zeta3 |--> -zeta6] Test that :issue:`15053` is fixed:: @@ -11652,24 +11652,22 @@ def complex_embeddings(self, prec=53): EXAMPLES:: sage: CyclotomicField(5).complex_embeddings() - [ - Ring morphism: - From: Cyclotomic Field of order 5 and degree 4 - To: Complex Field with 53 bits of precision - Defn: zeta5 |--> 0.309016994374947 + 0.951056516295154*I, - Ring morphism: - From: Cyclotomic Field of order 5 and degree 4 - To: Complex Field with 53 bits of precision - Defn: zeta5 |--> -0.809016994374947 + 0.587785252292473*I, - Ring morphism: - From: Cyclotomic Field of order 5 and degree 4 - To: Complex Field with 53 bits of precision - Defn: zeta5 |--> -0.809016994374947 - 0.587785252292473*I, - Ring morphism: - From: Cyclotomic Field of order 5 and degree 4 - To: Complex Field with 53 bits of precision - Defn: zeta5 |--> 0.309016994374947 - 0.951056516295154*I - ] + [Ring morphism: + From: Cyclotomic Field of order 5 and degree 4 + To: Complex Field with 53 bits of precision + Defn: zeta5 |--> 0.309016994374947 + 0.951056516295154*I, + Ring morphism: + From: Cyclotomic Field of order 5 and degree 4 + To: Complex Field with 53 bits of precision + Defn: zeta5 |--> -0.809016994374947 + 0.587785252292473*I, + Ring morphism: + From: Cyclotomic Field of order 5 and degree 4 + To: Complex Field with 53 bits of precision + Defn: zeta5 |--> -0.809016994374947 - 0.587785252292473*I, + Ring morphism: + From: Cyclotomic Field of order 5 and degree 4 + To: Complex Field with 53 bits of precision + Defn: zeta5 |--> 0.309016994374947 - 0.951056516295154*I] """ CC = sage.rings.complex_mpfr.ComplexField(prec) return self.embeddings(CC) @@ -11686,12 +11684,10 @@ def real_embeddings(self, prec=53): sage: len(CyclotomicField(4).real_embeddings()) 0 sage: CyclotomicField(2).real_embeddings() - [ - Ring morphism: - From: Cyclotomic Field of order 2 and degree 1 - To: Real Field with 53 bits of precision - Defn: -1 |--> -1.00000000000000 - ] + [Ring morphism: + From: Cyclotomic Field of order 2 and degree 1 + To: Real Field with 53 bits of precision + Defn: -1 |--> -1.00000000000000] """ K = sage.rings.real_mpfr.RealField(prec) return self.embeddings(K) @@ -12730,12 +12726,12 @@ def _splitting_classes_gens_(K, m, d): sage: L = K.subfields(20)[0][0] sage: L.conductor() # needs sage.groups 101 - sage: _splitting_classes_gens_(L,101,20) # needs sage.libs.gap # optional - gap_package_polycyclic + sage: _splitting_classes_gens_(L,101,20) # optional - gap_package_polycyclic, needs sage.libs.gap [95] sage: K = CyclotomicField(44) sage: L = K.subfields(4)[0][0] - sage: _splitting_classes_gens_(L,44,4) # needs sage.libs.gap # optional - gap_package_polycyclic + sage: _splitting_classes_gens_(L,44,4) # optional - gap_package_polycyclic, needs sage.libs.gap [37] sage: K = CyclotomicField(44) @@ -12747,7 +12743,7 @@ def _splitting_classes_gens_(K, m, d): with zeta44_0 = 3.837971894457990? sage: L.conductor() # needs sage.groups 11 - sage: _splitting_classes_gens_(L,11,5) # needs sage.libs.gap # optional - gap_package_polycyclic + sage: _splitting_classes_gens_(L,11,5) # optional - gap_package_polycyclic, needs sage.libs.gap [10] """ from sage.groups.abelian_gps.abelian_group import AbelianGroup diff --git a/src/sage/rings/number_field/number_field_base.pyx b/src/sage/rings/number_field/number_field_base.pyx index 910f6ff7904..1c8259a8250 100644 --- a/src/sage/rings/number_field/number_field_base.pyx +++ b/src/sage/rings/number_field/number_field_base.pyx @@ -65,7 +65,7 @@ cdef class NumberField(Field): +Infinity """ # This token docstring is mostly there to prevent Sphinx from pasting in - # the docstring of the __init__ method inherited from IntegralDomain, which + # the docstring of the __init__ method inherited from Field, which # is rather confusing. def _pushout_(self, other): r""" diff --git a/src/sage/rings/number_field/number_field_element_quadratic.pxd b/src/sage/rings/number_field/number_field_element_quadratic.pxd index 6dce9c04d90..7bb9e57a3a2 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pxd +++ b/src/sage/rings/number_field/number_field_element_quadratic.pxd @@ -31,4 +31,3 @@ cdef class OrderElement_quadratic(NumberFieldElement_quadratic): pass cpdef bint is_sqrt_disc(Rational ad, Rational bd) noexcept - 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 a0e90d1d63d..cc2e63ec8e7 100644 --- a/src/sage/rings/number_field/number_field_element_quadratic.pyx +++ b/src/sage/rings/number_field/number_field_element_quadratic.pyx @@ -1515,7 +1515,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: (1+a)*3 # indirect doctest 3*a + 3 """ - cdef Rational c = _c + cdef Rational c = _c cdef NumberFieldElement_quadratic res = self._new() mpz_mul(res.a, self.a, mpq_numref(c.value)) mpz_mul(res.b, self.b, mpq_numref(c.value)) @@ -1532,7 +1532,7 @@ cdef class NumberFieldElement_quadratic(NumberFieldElement_absolute): sage: 5*(a-1/5) # indirect doctest 5*a - 1 """ - cdef Rational c = _c + cdef Rational c = _c cdef NumberFieldElement_quadratic res = self._new() mpz_mul(res.a, self.a, mpq_numref(c.value)) mpz_mul(res.b, self.b, mpq_numref(c.value)) diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index 3686840ccba..30fc8326917 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -230,6 +230,11 @@ def _richcmp_(self, other, op): can give rise to the same ideal. And this can easily be detected using Hermite normal form. + As an implementation detail (this may change in the future), + the Hermite normal form is with respect to the integral basis + computed by Pari, and this may be different across different + runs and operating systems. + EXAMPLES:: sage: x = polygen(ZZ) @@ -237,7 +242,7 @@ def _richcmp_(self, other, op): Number Field in a with defining polynomial x^2 + 3 sage: f = K.factor(15); f (Fractional ideal (1/2*a + 3/2))^2 * (Fractional ideal (5)) - sage: (f[0][0] < f[1][0]) + sage: (f[0][0] < f[1][0]) # potentially random True sage: (f[0][0] == f[0][0]) True @@ -815,7 +820,7 @@ def gens_reduced(self, proof=None): self._cache_bnfisprincipal(proof=proof, gens=True) return self._reduced_generators - def gens_two(self): + def gens_two(self) -> tuple: r""" Express this ideal using exactly two generators, the first of which is a generator for the intersection of the ideal with `\QQ`. @@ -861,8 +866,8 @@ def gens_two(self): HNF = self.pari_hnf() # Check whether the ideal is generated by an integer, i.e. # whether HNF is a multiple of the identity matrix - if HNF.gequal(HNF[0,0]): - a = HNF[0,0] + if HNF.gequal(HNF[0, 0]): + a = HNF[0, 0] alpha = 0 else: a, alpha = K.pari_nf().idealtwoelt(HNF) @@ -2170,17 +2175,18 @@ def reduce(self, f): M = MatrixSpace(ZZ,n)([R.coordinates(y) for y in self.basis()]) D = M.hermite_form() - d = [D[i,i] for i in range(n)] + d = [D[i, i] for i in range(n)] v = R.coordinates(f) for i in range(n): - q, r = ZZ(v[i]).quo_rem(d[i])#v is a vector of rationals, we want division of integers + q, r = ZZ(v[i]).quo_rem(d[i]) + # v is a vector of rationals, we want division of integers if 2*r > d[i]: q = q + 1 v = v - q*D[i] - return sum([v[i]*Rbasis[i] for i in range(n)]) + return sum([v[i] * Rbasis[i] for i in range(n)]) def residues(self): r""" diff --git a/src/sage/rings/number_field/number_field_morphisms.pyx b/src/sage/rings/number_field/number_field_morphisms.pyx index e71bad5db7c..330e0a8ab69 100644 --- a/src/sage/rings/number_field/number_field_morphisms.pyx +++ b/src/sage/rings/number_field/number_field_morphisms.pyx @@ -20,16 +20,14 @@ fields (generally `\RR` or `\CC`). # https://www.gnu.org/licenses/ # **************************************************************************** -import sage.rings.complex_double - from sage.structure.element cimport Element from sage.categories.morphism cimport Morphism from sage.categories.map cimport Map from sage.categories.pushout import pushout +from sage.rings.complex_double import CDF from sage.rings.real_lazy import RLF, CLF, LazyField, LazyAlgebraic - cdef class NumberFieldEmbedding(Morphism): cdef _gen_image @@ -254,7 +252,7 @@ cdef class EmbeddedNumberFieldMorphism(NumberFieldEmbedding): candidate_ambient_fields.append(ambient_field.algebraic_closure()) except NotImplementedError: pass - candidate_ambient_fields.append(sage.rings.complex_double.CDF) + candidate_ambient_fields.append(CDF) else: candidate_ambient_fields = [ambient_field] diff --git a/src/sage/rings/number_field/number_field_rel.py b/src/sage/rings/number_field/number_field_rel.py index 7ea070b113e..ea81834f56c 100644 --- a/src/sage/rings/number_field/number_field_rel.py +++ b/src/sage/rings/number_field/number_field_rel.py @@ -419,47 +419,36 @@ def subfields(self, degree=0, name=None): sage: PF. = F[] sage: K. = F.extension(Y^2 - (1 + a)*(a + b)*a*b) sage: K.subfields(2) - [ - (Number Field in c0 with defining polynomial x^2 - 24*x + 96, - Ring morphism: - From: Number Field in c0 with defining polynomial x^2 - 24*x + 96 - To: Number Field in c with defining polynomial - Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - Defn: c0 |--> -4*b + 12, - None), - (Number Field in c1 with defining polynomial x^2 - 24*x + 120, - Ring morphism: - From: Number Field in c1 with defining polynomial x^2 - 24*x + 120 - To: Number Field in c with defining polynomial - Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - Defn: c1 |--> 2*b*a + 12, - None), - (Number Field in c2 with defining polynomial x^2 - 24*x + 72, - Ring morphism: - From: Number Field in c2 with defining polynomial x^2 - 24*x + 72 - To: Number Field in c with defining polynomial - Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - Defn: c2 |--> -6*a + 12, - None) - ] + [(Number Field in c0 with defining polynomial x^2 - 24*x + 96, + Ring morphism: + From: Number Field in c0 with defining polynomial x^2 - 24*x + 96 + To: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Defn: c0 |--> -4*b + 12, + None), + (Number Field in c1 with defining polynomial x^2 - 24*x + 120, + Ring morphism: + From: Number Field in c1 with defining polynomial x^2 - 24*x + 120 + To: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Defn: c1 |--> 2*b*a + 12, + None), + (Number Field in c2 with defining polynomial x^2 - 24*x + 72, + Ring morphism: + From: Number Field in c2 with defining polynomial x^2 - 24*x + 72 + To: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Defn: c2 |--> -6*a + 12, + None)] sage: K.subfields(8, 'w') - [ - (Number Field in w0 with defining polynomial x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9, - Ring morphism: - From: Number Field in w0 with defining polynomial - x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9 - To: Number Field in c with defining polynomial - Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - Defn: w0 |--> (-1/2*b*a + 1/2*b + 1/2)*c, - Relative number field morphism: - From: Number Field in c with defining polynomial - Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - To: Number Field in w0 with defining polynomial - x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9 - Defn: c |--> -1/3*w0^7 + 4*w0^5 - 12*w0^3 + 11*w0 - a |--> 1/3*w0^6 - 10/3*w0^4 + 5*w0^2 - b |--> -2/3*w0^6 + 7*w0^4 - 14*w0^2 + 6) - ] + [(Number Field in w0 with defining polynomial x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9, + Ring morphism: + From: Number Field in w0 with defining polynomial x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9 + To: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Defn: w0 |--> (-1/2*b*a + 1/2*b + 1/2)*c, + Relative number field morphism: + From: Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + To: Number Field in w0 with defining polynomial x^8 - 12*x^6 + 36*x^4 - 36*x^2 + 9 + Defn: c |--> -1/3*w0^7 + 4*w0^5 - 12*w0^3 + 11*w0 + a |--> 1/3*w0^6 - 10/3*w0^4 + 5*w0^2 + b |--> -2/3*w0^6 + 7*w0^4 - 14*w0^2 + 6)] sage: K.subfields(3) [] """ @@ -493,7 +482,7 @@ def is_absolute(self): """ return False - def gens(self): + def gens(self) -> tuple: """ Return the generators of this relative number field. @@ -2052,19 +2041,17 @@ def embeddings(self, K): sage: x = polygen(ZZ, 'x') sage: K. = NumberField([x^3 - 2, x^2 + 1]) sage: f = K.embeddings(ComplexField(58)); f - [ - Relative number field morphism: - From: Number Field in a with defining polynomial x^3 - 2 over its base field - To: Complex Field with 58 bits of precision - Defn: a |--> -0.62996052494743676 - 1.0911236359717214*I - b |--> -1.9428902930940239e-16 + 1.0000000000000000*I, - ... - Relative number field morphism: - From: Number Field in a with defining polynomial x^3 - 2 over its base field - To: Complex Field with 58 bits of precision - Defn: a |--> 1.2599210498948731 - b |--> -0.99999999999999999*I - ] + [Relative number field morphism: + From: Number Field in a with defining polynomial x^3 - 2 over its base field + To: Complex Field with 58 bits of precision + Defn: a |--> -0.62996052494743676 - 1.0911236359717214*I + b |--> -1.9428902930940239e-16 + 1.0000000000000000*I, + ... + Relative number field morphism: + From: Number Field in a with defining polynomial x^3 - 2 over its base field + To: Complex Field with 58 bits of precision + Defn: a |--> 1.2599210498948731 + b |--> -0.99999999999999999*I] sage: f[0](a)^3 2.0000000000000002 - 8.6389229103644993e-16*I sage: f[0](b)^2 @@ -2105,16 +2092,12 @@ def automorphisms(self): sage: K. = NumberField([x^2 + 10000, x^2 + x + 50]); K Number Field in a with defining polynomial x^2 + 10000 over its base field sage: K.automorphisms() - [ - Relative number field endomorphism of Number Field in a - with defining polynomial x^2 + 10000 over its base field - Defn: a |--> a - b |--> b, - Relative number field endomorphism of Number Field in a - with defining polynomial x^2 + 10000 over its base field - Defn: a |--> -a - b |--> b - ] + [Relative number field endomorphism of Number Field in a with defining polynomial x^2 + 10000 over its base field + Defn: a |--> a + b |--> b, + Relative number field endomorphism of Number Field in a with defining polynomial x^2 + 10000 over its base field + Defn: a |--> -a + b |--> b] sage: rho, tau = K.automorphisms() sage: tau(a) -a @@ -2124,16 +2107,12 @@ def automorphisms(self): sage: L. = NumberField([x^2 + x + 50, x^2 + 10000, ]); L Number Field in b with defining polynomial x^2 + x + 50 over its base field sage: L.automorphisms() - [ - Relative number field endomorphism of Number Field in b - with defining polynomial x^2 + x + 50 over its base field - Defn: b |--> b - a |--> a, - Relative number field endomorphism of Number Field in b - with defining polynomial x^2 + x + 50 over its base field - Defn: b |--> -b - 1 - a |--> a - ] + [Relative number field endomorphism of Number Field in b with defining polynomial x^2 + x + 50 over its base field + Defn: b |--> b + a |--> a, + Relative number field endomorphism of Number Field in b with defining polynomial x^2 + x + 50 over its base field + Defn: b |--> -b - 1 + a |--> a] sage: rho, tau = L.automorphisms() sage: tau(a) == a True @@ -2145,18 +2124,14 @@ def automorphisms(self): sage: PF. = F[] sage: K. = F.extension(Y^2 - (1 + a)*(a + b)*a*b) sage: K.automorphisms() - [ - Relative number field endomorphism of Number Field in c - with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - Defn: c |--> c - a |--> a - b |--> b, - Relative number field endomorphism of Number Field in c - with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field - Defn: c |--> -c - a |--> a - b |--> b - ] + [Relative number field endomorphism of Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Defn: c |--> c + a |--> a + b |--> b, + Relative number field endomorphism of Number Field in c with defining polynomial Y^2 + (-2*b - 3)*a - 2*b - 6 over its base field + Defn: c |--> -c + a |--> a + b |--> b] """ try: return self.__automorphisms diff --git a/src/sage/rings/number_field/order.py b/src/sage/rings/number_field/order.py index 9dee6a8a481..fd5662048df 100644 --- a/src/sage/rings/number_field/order.py +++ b/src/sage/rings/number_field/order.py @@ -631,9 +631,11 @@ def is_noetherian(self): """ return True - def is_integrally_closed(self): + def is_integrally_closed(self) -> bool: r""" - Return ``True`` if this ring is integrally closed, i.e., is equal + Return whether this ring is integrally closed. + + This is true if and only if it is equal to the maximal order. EXAMPLES:: diff --git a/src/sage/rings/number_field/order_ideal.py b/src/sage/rings/number_field/order_ideal.py index 772c4ad3a9a..3e0ecce3653 100644 --- a/src/sage/rings/number_field/order_ideal.py +++ b/src/sage/rings/number_field/order_ideal.py @@ -399,7 +399,7 @@ def conjugate(self): conj_gens = [g.conjugate() for g in self.gens()] return NumberFieldOrderIdeal(self.ring(), conj_gens) - def gens_two(self): + def gens_two(self) -> tuple: r""" Express this ideal using exactly two generators, the first of which is a generator for the intersection of the ideal with `\ZZ`. @@ -506,7 +506,7 @@ def is_principal(self): sol = f.solve_integer(-1) return sol is not None - def gens_reduced(self): + def gens_reduced(self) -> tuple: r""" Express this ideal in terms of at most two generators, and one if possible (i.e., if the ideal is principal). @@ -550,7 +550,7 @@ def gens_reduced(self): sol = f.solve_integer(-1) if sol is None: return self.gens_two() - gen = sum(c*g for c,g in zip(sol, bas)) + gen = sum(c * g for c, g in zip(sol, bas)) assert NumberFieldOrderIdeal(self.ring(), gen) == self return (gen,) diff --git a/src/sage/rings/number_field/totallyreal_data.pxd b/src/sage/rings/number_field/totallyreal_data.pxd index 61973829ddb..006189325f9 100644 --- a/src/sage/rings/number_field/totallyreal_data.pxd +++ b/src/sage/rings/number_field/totallyreal_data.pxd @@ -23,4 +23,3 @@ cdef class tr_data: cdef int *df cdef void incr(self, int *f_out, int verbose, int haltk, int phc) noexcept - diff --git a/src/sage/rings/padics/common_conversion.pyx b/src/sage/rings/padics/common_conversion.pyx index a352cc74c18..6831fbde141 100644 --- a/src/sage/rings/padics/common_conversion.pyx +++ b/src/sage/rings/padics/common_conversion.pyx @@ -106,7 +106,7 @@ cdef long get_ordp(x, PowComputer_class prime_pow) except? -10000: k = mpz_remove(temp.value, mpq_numref((x).value), prime_pow.prime.value) if k == 0: k = -mpz_remove(temp.value, mpq_denref((x).value), prime_pow.prime.value) - elif isinstance(x, (list,tuple)): + elif isinstance(x, (list, tuple)): f = prime_pow.f if (e == 1 and len(x) > f) or (e != 1 and len(x) > e): # could reduce modulo the defining polynomial but that isn't currently supported @@ -114,11 +114,11 @@ cdef long get_ordp(x, PowComputer_class prime_pow) except? -10000: k = maxordp shift = 0 for a in x: - if isinstance(a, (list,tuple)): + if isinstance(a, (list, tuple)): if e == 1 or f == 1: raise ValueError("nested lists not allowed for unramified and eisenstein extensions") for b in a: - if isinstance(b, (list,tuple)): + if isinstance(b, (list, tuple)): raise ValueError("list nesting too deep") curterm = get_ordp(b, prime_pow) k = min(k, curterm + shift, maxordp) @@ -191,13 +191,13 @@ cdef long get_preccap(x, PowComputer_class prime_pow) except? -10000: cdef long k, shift, e = prime_pow.e cdef Integer prec cdef GEN pari_tmp - if isinstance(x, int) or isinstance(x, Integer) or isinstance(x, Rational): + if isinstance(x, (int, Integer, Rational)): return maxordp - elif isinstance(x, (list,tuple)): + elif isinstance(x, (list, tuple)): k = maxordp shift = 0 for a in x: - if isinstance(a, (list,tuple)): + if isinstance(a, (list, tuple)): for b in a: curterm = get_preccap(b, prime_pow) k = min(k, curterm + shift) diff --git a/src/sage/rings/padics/factory.py b/src/sage/rings/padics/factory.py index cee585d48a1..de5e112343f 100644 --- a/src/sage/rings/padics/factory.py +++ b/src/sage/rings/padics/factory.py @@ -17,7 +17,7 @@ sage: R = QpLF(2) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2007-2013 David Roe # William Stein # @@ -26,10 +26,11 @@ # the License, or (at your option) any later version. # # https://www.gnu.org/licenses/ -#***************************************************************************** +# **************************************************************************** from sage.misc.superseded import experimental +from sage.categories.fields import Fields from sage.structure.factory import UniqueFactory from sage.rings.integer import Integer from sage.rings.infinity import Infinity @@ -783,35 +784,45 @@ def create_object(self, version, key): pass p, prec, type, print_mode, name, print_pos, print_sep, print_alphabet, print_max_terms, show_prec, label = key + _Fields = Fields() + if type == 'capped-rel': if print_mode == 'terse': return pAdicFieldCappedRelative(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name) + 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, + category=_Fields) else: return pAdicFieldCappedRelative(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) + 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, + category=_Fields) elif type == 'floating-point': if print_mode == 'terse': return pAdicFieldFloatingPoint(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name) + 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, + category=_Fields) else: return pAdicFieldFloatingPoint(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) + 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, + category=_Fields) elif type == 'relaxed': if print_mode == 'terse': return pAdicFieldRelaxed(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name) + 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, + category=_Fields) else: return pAdicFieldRelaxed(p, prec, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name) + 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, + category=_Fields) elif type[:8] == 'lattice-': subtype = type[8:] if print_mode == 'terse': return pAdicFieldLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, label) + 'ram_name': name, 'max_terse_terms': print_max_terms, 'show_prec': show_prec}, name, label, + category=_Fields) else: return pAdicFieldLattice(p, prec, subtype, {'mode': print_mode, 'pos': print_pos, 'sep': print_sep, 'alphabet': print_alphabet, - 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, label) + 'ram_name': name, 'max_ram_terms': print_max_terms, 'show_prec': show_prec}, name, label, + category=_Fields) else: raise ValueError("unexpected type") @@ -2570,7 +2581,7 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, True """ if check: - if isinstance(q, Factorization) or isinstance(q, (list, tuple)): + if isinstance(q, (Factorization, list, tuple)): if not isinstance(q, Factorization) and len(q) == 2: F = [(Integer(q[0]), Integer(q[1]))] else: @@ -2592,7 +2603,8 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, if isinstance(names, (list, tuple)): names = names[0] from sage.structure.element import Expression - if not (modulus is None or isinstance(modulus, Polynomial) or isinstance(modulus, Expression)): + if not (modulus is None or isinstance(modulus, (Polynomial, + Expression))): raise TypeError("modulus must be a polynomial") if names is not None and not isinstance(names, str): names = str(names) @@ -3547,7 +3559,7 @@ def krasner_check(poly, prec): sage: krasner_check(1,2) # this is a stupid example. True """ - return True #This needs to be implemented + return True # This needs to be implemented def is_eisenstein(poly): diff --git a/src/sage/rings/padics/generic_nodes.py b/src/sage/rings/padics/generic_nodes.py index 27ca55b274f..c1459a3a204 100644 --- a/src/sage/rings/padics/generic_nodes.py +++ b/src/sage/rings/padics/generic_nodes.py @@ -257,7 +257,7 @@ def _test_additive_associativity(self, **options): tester = self._tester(**options) S = tester.some_elements() from sage.misc.misc import some_tuples - for x,y,z in some_tuples(S, 3, tester._max_runs): + for x, y, z in some_tuples(S, 3, tester._max_runs): tester.assertTrue(((x + y) + z).is_equal_to(x + (y + z), min(x.precision_absolute(), y.precision_absolute(), z.precision_absolute()))) @@ -265,7 +265,8 @@ class FloatingPointRingGeneric(FloatingPointGeneric): pass -class FloatingPointFieldGeneric(FloatingPointGeneric):#, sage.rings.ring.Field): +class FloatingPointFieldGeneric(FloatingPointGeneric): + # in category of Fields() pass @@ -273,7 +274,8 @@ class CappedRelativeRingGeneric(CappedRelativeGeneric): pass -class CappedRelativeFieldGeneric(CappedRelativeGeneric):#, sage.rings.ring.Field): +class CappedRelativeFieldGeneric(CappedRelativeGeneric): + # in category of Fields() pass @@ -312,7 +314,7 @@ class pAdicLatticeGeneric(pAdicGeneric): sage: R._prec_type() 'lattice-float' """ - def __init__(self, p, prec, print_mode, names, label=None): + def __init__(self, p, prec, print_mode, names, label=None, category=None): """ Initialization. @@ -355,7 +357,7 @@ def __init__(self, p, prec, print_mode, names, label=None): else: raise ValueError("subtype must be either 'cap' or 'float'") self._element_class = self.__make_element_class__(element_class) - pAdicGeneric.__init__(self, self, p, prec, print_mode, names, None) + pAdicGeneric.__init__(self, self, p, prec, print_mode, names, None, category=category) def _prec_type(self): """ diff --git a/src/sage/rings/padics/meson.build b/src/sage/rings/padics/meson.build index 9cb64492095..f589881042e 100644 --- a/src/sage/rings/padics/meson.build +++ b/src/sage/rings/padics/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'common_conversion.pxd', 'eisenstein_extension_generic.py', diff --git a/src/sage/rings/padics/padic_base_generic.py b/src/sage/rings/padics/padic_base_generic.py index 8001d366b23..003d34c8315 100644 --- a/src/sage/rings/padics/padic_base_generic.py +++ b/src/sage/rings/padics/padic_base_generic.py @@ -34,7 +34,7 @@ class pAdicBaseGeneric(pAdicGeneric): _implementation = 'GMP' - def __init__(self, p, prec, print_mode, names, element_class): + def __init__(self, p, prec, print_mode, names, element_class, category=None): """ Initialization. @@ -47,7 +47,7 @@ def __init__(self, p, prec, print_mode, names, element_class): self.prime_pow = PowComputer_flint(p, 1, 1, 1, self.is_field()) else: self.prime_pow = PowComputer(p, max(min(prec - 1, 30), 1), prec, self.is_field(), self._prec_type()) - pAdicGeneric.__init__(self, self, p, prec, print_mode, names, element_class) + pAdicGeneric.__init__(self, self, p, prec, print_mode, names, element_class, category=category) if self.is_field(): if self.is_capped_relative(): coerce_list = [pAdicCoercion_ZZ_CR(self), pAdicCoercion_QQ_CR(self)] diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 64be9291c49..4eb9e584de1 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -211,7 +211,7 @@ class pAdicRingCappedRelative(pAdicRingBaseGeneric, pAdicCappedRelativeRingGener An implementation of the `p`-adic integers with capped relative precision. """ - def __init__(self, p, prec, print_mode, names): + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -247,7 +247,7 @@ def __init__(self, p, prec, print_mode, names): ....: max_runs=2^5, skip='_test_log') sage: R._test_log(max_runs=2, elements=[R.random_element() for i in range(4)]) # long time """ - pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicCappedRelativeElement) + pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicCappedRelativeElement, category=category) def _coerce_map_from_(self, R): """ @@ -309,7 +309,7 @@ class pAdicRingCappedAbsolute(pAdicRingBaseGeneric, pAdicCappedAbsoluteRingGener r""" An implementation of the `p`-adic integers with capped absolute precision. """ - def __init__(self, p, prec, print_mode, names): + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -345,7 +345,7 @@ def __init__(self, p, prec, print_mode, names): ....: max_runs=2^5, skip='_test_log') sage: R._test_log(max_runs=2, elements=[R.random_element() for i in range(4)]) """ - pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicCappedAbsoluteElement) + pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicCappedAbsoluteElement, category=category) def _coerce_map_from_(self, R): """ @@ -410,7 +410,7 @@ class pAdicRingFloatingPoint(pAdicRingBaseGeneric, pAdicFloatingPointRingGeneric An implementation of the `p`-adic integers with floating point precision. """ - def __init__(self, p, prec, print_mode, names): + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -446,7 +446,7 @@ def __init__(self, p, prec, print_mode, names): ....: max_runs=2^5, skip='_test_log') sage: R._test_log(max_runs=2, elements=[R.random_element() for i in range(4)]) """ - pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicFloatingPointElement) + pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicFloatingPointElement, category=category) def _coerce_map_from_(self, R): """ @@ -505,7 +505,7 @@ class pAdicRingFixedMod(pAdicRingBaseGeneric, pAdicFixedModRingGeneric): r""" An implementation of the `p`-adic integers using fixed modulus. """ - def __init__(self, p, prec, print_mode, names): + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -550,7 +550,7 @@ def __init__(self, p, prec, print_mode, names): sage: K(R(90)) 3*5 + 3*5^2 """ - pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicFixedModElement) + pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicFixedModElement, category=category) def _coerce_map_from_(self, R): """ @@ -618,7 +618,7 @@ class pAdicFieldCappedRelative(pAdicFieldBaseGeneric, pAdicCappedRelativeFieldGe sage: K = Qp(101) # indirect doctest """ - def __init__(self, p, prec, print_mode, names): + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -660,7 +660,7 @@ def __init__(self, p, prec, print_mode, names): ....: max_runs=2^5, skip='_test_log') sage: R._test_log(max_runs=2, elements=[R.random_element() for i in range(4)]) """ - pAdicFieldBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicCappedRelativeElement) + pAdicFieldBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicCappedRelativeElement, category=category) def _coerce_map_from_(self, R): """ @@ -749,7 +749,7 @@ class pAdicFieldFloatingPoint(pAdicFieldBaseGeneric, pAdicFloatingPointFieldGene An implementation of the `p`-adic rationals with floating point precision. """ - def __init__(self, p, prec, print_mode, names): + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -786,7 +786,7 @@ def __init__(self, p, prec, print_mode, names): ....: max_runs=2^5, skip='_test_log') sage: R._test_log(max_runs=2, elements=[R.random_element() for i in range(4)]) """ - pAdicFieldBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicFloatingPointElement) + pAdicFieldBaseGeneric.__init__(self, p, prec, print_mode, names, pAdicFloatingPointElement, category=category) def _coerce_map_from_(self, R): """ @@ -881,7 +881,7 @@ class pAdicRingLattice(pAdicLatticeGeneric, pAdicRingBaseGeneric): sage: R 2-adic Ring with lattice-cap precision (label: init) """ - def __init__(self, p, prec, subtype, print_mode, names, label=None): + def __init__(self, p, prec, subtype, print_mode, names, label=None, category=None): """ Initialization. @@ -893,11 +893,11 @@ def __init__(self, p, prec, subtype, print_mode, names, label=None): # We need to set the subtype first, so that # pAdicRingBaseGeneric.__init__ can work self._subtype = subtype - if isinstance(prec,tuple): - pAdicRingBaseGeneric.__init__(self, p, prec[1], print_mode, names, None) + if isinstance(prec, tuple): + pAdicRingBaseGeneric.__init__(self, p, prec[1], print_mode, names, None, category=category) else: - pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, None) - pAdicLatticeGeneric.__init__(self, p, prec, print_mode, names, label) + pAdicRingBaseGeneric.__init__(self, p, prec, print_mode, names, None, category=category) + pAdicLatticeGeneric.__init__(self, p, prec, print_mode, names, label, category=category) def _coerce_map_from_(self, R): """ @@ -1012,7 +1012,7 @@ class pAdicFieldLattice(pAdicLatticeGeneric, pAdicFieldBaseGeneric): sage: R 2-adic Field with lattice-cap precision (label: init) """ - def __init__(self, p, prec, subtype, print_mode, names, label=None): + def __init__(self, p, prec, subtype, print_mode, names, label=None, category=None): """ Initialization. @@ -1024,11 +1024,11 @@ def __init__(self, p, prec, subtype, print_mode, names, label=None): # We need to set the subtype first, so that # pAdicFieldBaseGeneric.__init__ can work self._subtype = subtype - if isinstance(prec,tuple): - pAdicFieldBaseGeneric.__init__(self, p, prec[1], print_mode, names, None) + if isinstance(prec, tuple): + pAdicFieldBaseGeneric.__init__(self, p, prec[1], print_mode, names, None, category=category) else: - pAdicFieldBaseGeneric.__init__(self, p, prec, print_mode, names, None) - pAdicLatticeGeneric.__init__(self, p, prec, print_mode, names, label) + pAdicFieldBaseGeneric.__init__(self, p, prec, print_mode, names, None, category=category) + pAdicLatticeGeneric.__init__(self, p, prec, print_mode, names, label, category=category) def _coerce_map_from_(self, R): """ @@ -1137,7 +1137,7 @@ class pAdicRingRelaxed(pAdicRelaxedGeneric, pAdicRingBaseGeneric): sage: type(R) # needs sage.libs.flint """ - def __init__(self, p, prec, print_mode, names): + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -1151,7 +1151,7 @@ def __init__(self, p, prec, print_mode, names): """ from sage.rings.padics import padic_relaxed_element self._default_prec, self._halting_prec, self._secure = prec - pAdicRingBaseGeneric.__init__(self, p, self._default_prec, print_mode, names, padic_relaxed_element.pAdicRelaxedElement) + pAdicRingBaseGeneric.__init__(self, p, self._default_prec, print_mode, names, padic_relaxed_element.pAdicRelaxedElement, category=category) self._element_class_module = padic_relaxed_element self._element_class_prefix = "pAdicRelaxedElement_" @@ -1176,7 +1176,7 @@ class pAdicFieldRelaxed(pAdicRelaxedGeneric, pAdicFieldBaseGeneric): sage: type(R) # needs sage.libs.flint """ - def __init__(self, p, prec, print_mode, names): + def __init__(self, p, prec, print_mode, names, category=None): """ Initialization. @@ -1190,6 +1190,6 @@ def __init__(self, p, prec, print_mode, names): """ from sage.rings.padics import padic_relaxed_element self._default_prec, self._halting_prec, self._secure = prec - pAdicFieldBaseGeneric.__init__(self, p, self._default_prec, print_mode, names, padic_relaxed_element.pAdicRelaxedElement) + pAdicFieldBaseGeneric.__init__(self, p, self._default_prec, print_mode, names, padic_relaxed_element.pAdicRelaxedElement, category=category) self._element_class_module = padic_relaxed_element self._element_class_prefix = "pAdicRelaxedElement_" diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index 39d1fb43006..be3f3de2e7d 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -145,20 +145,20 @@ def ngens(self): """ return 1 - def gens(self): + def gens(self) -> tuple: r""" - Return a list of generators. + Return a tuple of generators. EXAMPLES:: sage: R = Zp(5); R.gens() - [5 + O(5^21)] + (5 + O(5^21),) sage: Zq(25,names='a').gens() # needs sage.libs.ntl - [a + O(5^20)] + (a + O(5^20),) sage: S. = ZZ[]; f = x^5 + 25*x -5; W. = R.ext(f); W.gens() # needs sage.libs.ntl - [w + O(w^101)] + (w + O(w^101),) """ - return [self.gen()] + return (self.gen(),) def __richcmp__(self, other, op): r""" @@ -195,14 +195,6 @@ def __richcmp__(self, other, op): return self._printer.richcmp_modes(other._printer, op) - # def ngens(self): - # return 1 - - # def gen(self, n=0): - # if n != 0: - # raise IndexError, "only one generator" - # return self(self.prime()) - def print_mode(self): r""" Return the current print mode as a string. diff --git a/src/sage/rings/padics/padic_generic_element.pyx b/src/sage/rings/padics/padic_generic_element.pyx index 073a3d98f5f..7a103be85b3 100644 --- a/src/sage/rings/padics/padic_generic_element.pyx +++ b/src/sage/rings/padics/padic_generic_element.pyx @@ -115,7 +115,7 @@ cdef class pAdicGenericElement(LocalGenericElement): m = min(left.precision_absolute(), right.precision_absolute()) x_ordp = left.valuation() - left_zero = bool(x_ordp >= m) + left_zero = bool(x_ordp >= m) y_ordp = right.valuation() right_zero = bool(y_ordp >= m) # handle approximate zeros @@ -1349,7 +1349,7 @@ cdef class pAdicGenericElement(LocalGenericElement): sage: Zp(5)(0).gamma() 1 + O(5^20) - Check the cached version of `dwork_expansion` from :issue:`24433`:: + Check the cached version of ``dwork_expansion`` from :issue:`24433`:: sage: p = next_prime(200) sage: F = Qp(p) diff --git a/src/sage/rings/padics/padic_valuation.py b/src/sage/rings/padics/padic_valuation.py index 1050055e1fb..3d150562508 100644 --- a/src/sage/rings/padics/padic_valuation.py +++ b/src/sage/rings/padics/padic_valuation.py @@ -554,8 +554,8 @@ def is_unramified(self, G, include_steps=False, assume_squarefree=False): """ R = G.parent() - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if not isinstance(R, PolynomialRing_general) or R.base_ring() is not self.domain() or not G.is_monic(): + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if not isinstance(R, PolynomialRing_generic) or R.base_ring() is not self.domain() or not G.is_monic(): raise ValueError("G must be a monic univariate polynomial over the domain of this valuation") if not assume_squarefree and not G.is_squarefree(): raise ValueError("G must be squarefree") @@ -651,8 +651,8 @@ def is_totally_ramified(self, G, include_steps=False, assume_squarefree=False): """ R = G.parent() - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if not isinstance(R, PolynomialRing_general) or R.base_ring() is not self.domain() or not G.is_monic(): + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if not isinstance(R, PolynomialRing_generic) or R.base_ring() is not self.domain() or not G.is_monic(): raise ValueError("G must be a monic univariate polynomial over the domain of this valuation") if not assume_squarefree and not G.is_squarefree(): raise ValueError("G must be squarefree") diff --git a/src/sage/rings/padics/relative_extension_leaves.py b/src/sage/rings/padics/relative_extension_leaves.py index 3005ae0825b..b88aebf129a 100644 --- a/src/sage/rings/padics/relative_extension_leaves.py +++ b/src/sage/rings/padics/relative_extension_leaves.py @@ -378,7 +378,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, """ self._exact_modulus = exact_modulus unram_prec = (prec + approx_modulus.degree() - 1) // approx_modulus.degree() - KFP = approx_modulus.base_ring()#.change(field=False, show_prec=False) + KFP = approx_modulus.base_ring() # .change(field=False, show_prec=False) self.prime_pow = PowComputer_relative_maker(approx_modulus.base_ring().prime(), max(min(unram_prec - 1, 30), 1), unram_prec, prec, False, exact_modulus.change_ring(KFP), shift_seed.change_ring(KFP), 'floating-point') self._implementation = 'Polynomial' EisensteinExtensionGeneric.__init__(self, approx_modulus, prec, print_mode, names, RelativeRamifiedFloatingPointElement) @@ -416,7 +416,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, """ self._exact_modulus = exact_modulus unram_prec = (prec + approx_modulus.degree() - 1) // approx_modulus.degree() - KFP = approx_modulus.base_ring()#.change(field=False, show_prec=False) + KFP = approx_modulus.base_ring() # .change(field=False, show_prec=False) self.prime_pow = PowComputer_relative_maker(approx_modulus.base_ring().prime(), max(min(unram_prec - 1, 30), 1), unram_prec, prec, True, exact_modulus.change_ring(KFP), shift_seed.change_ring(KFP), 'floating-point') self._implementation = 'Polynomial' EisensteinExtensionGeneric.__init__(self, approx_modulus, prec, print_mode, names, RelativeRamifiedFloatingPointElement) diff --git a/src/sage/rings/padics/relaxed_template.pxi b/src/sage/rings/padics/relaxed_template.pxi index 1b6b4fb0833..79869e9b7a1 100644 --- a/src/sage/rings/padics/relaxed_template.pxi +++ b/src/sage/rings/padics/relaxed_template.pxi @@ -1659,7 +1659,7 @@ cdef class RelaxedElement(pAdicGenericElement): 964*997^4 + 572*997^5 + 124*997^6 + ... """ cdef long start - cdef long shift = long(s) + cdef long shift = s if shift: if (self)._parent.is_field(): start = -maxordp diff --git a/src/sage/rings/polynomial/all.py b/src/sage/rings/polynomial/all.py index 853f422bdc7..f2295443420 100644 --- a/src/sage/rings/polynomial/all.py +++ b/src/sage/rings/polynomial/all.py @@ -54,3 +54,5 @@ # Integer-valued Univariate Polynomial Ring lazy_import('sage.rings.polynomial.integer_valued_polynomials', 'IntegerValuedPolynomialRing') +lazy_import('sage.rings.polynomial.q_integer_valued_polynomials', + 'QuantumValuedPolynomialRing') diff --git a/src/sage/rings/polynomial/cyclotomic.pyx b/src/sage/rings/polynomial/cyclotomic.pyx index 8c9088434fa..e9eb5675b90 100644 --- a/src/sage/rings/polynomial/cyclotomic.pyx +++ b/src/sage/rings/polynomial/cyclotomic.pyx @@ -4,7 +4,7 @@ Fast calculation of cyclotomic polynomials This module provides a function :func:`cyclotomic_coeffs`, which calculates the coefficients of cyclotomic polynomials. This is not intended to be invoked directly by the user, but it is called by the method -:meth:`~sage.rings.polynomial.polynomial_ring.PolynomialRing_general.cyclotomic_polynomial` +:meth:`~sage.rings.polynomial.polynomial_ring.PolynomialRing_generic.cyclotomic_polynomial` method of univariate polynomial ring objects and the top-level :func:`~sage.misc.functional.cyclotomic_polynomial` function. """ diff --git a/src/sage/rings/polynomial/flatten.py b/src/sage/rings/polynomial/flatten.py index 6354bbcd382..174c1d7b1bd 100644 --- a/src/sage/rings/polynomial/flatten.py +++ b/src/sage/rings/polynomial/flatten.py @@ -38,7 +38,7 @@ from sage.categories.morphism import Morphism from sage.misc.cachefunc import cached_method from .polynomial_ring_constructor import PolynomialRing -from .polynomial_ring import PolynomialRing_general +from .polynomial_ring import PolynomialRing_generic from .multi_polynomial_ring_base import MPolynomialRing_base from sage.rings.fraction_field import FractionField_generic from sage.rings.fraction_field_element import FractionFieldElement @@ -160,14 +160,14 @@ def __init__(self, domain): sage: fl.section()(fl(p)) == p True """ - if not isinstance(domain, PolynomialRing_general) and not isinstance(domain, MPolynomialRing_base): + if not isinstance(domain, (PolynomialRing_generic, MPolynomialRing_base)): raise ValueError("domain should be a polynomial ring") ring = domain variables = [] intermediate_rings = [] - while isinstance(ring, PolynomialRing_general) or isinstance(ring, MPolynomialRing_base): + while isinstance(ring, (PolynomialRing_generic, MPolynomialRing_base)): intermediate_rings.append(ring) v = ring.variable_names() variables.extend(reversed(v)) @@ -221,7 +221,7 @@ def _call_(self, p): for ring in self._intermediate_rings: new_p = {} - if isinstance(ring, PolynomialRing_general): + if isinstance(ring, PolynomialRing_generic): for mon, pp in p.items(): assert pp.parent() is ring for i, j in pp.monomial_coefficients().items(): @@ -347,14 +347,14 @@ def __init__(self, domain, codomain): """ if not isinstance(domain, MPolynomialRing_base): raise ValueError("domain should be a multivariate polynomial ring") - if not isinstance(codomain, PolynomialRing_general) and not isinstance(codomain, MPolynomialRing_base): + if not isinstance(codomain, (PolynomialRing_generic, MPolynomialRing_base)): raise ValueError("codomain should be a polynomial ring") ring = codomain intermediate_rings = [] while True: - is_polynomial_ring = isinstance(ring, PolynomialRing_general) + is_polynomial_ring = isinstance(ring, PolynomialRing_generic) if not (is_polynomial_ring or isinstance(ring, MPolynomialRing_base)): break intermediate_rings.append((ring, is_polynomial_ring)) @@ -499,7 +499,7 @@ def __init__(self, domain, D): Defn: Defined on coordinates by sending (z) to (z^2 + 1.00000000000000) """ - if not isinstance(domain, PolynomialRing_general) and not isinstance(domain, MPolynomialRing_base): + if not isinstance(domain, (PolynomialRing_generic, MPolynomialRing_base)): raise TypeError("domain should be a polynomial ring") # use only the generators that are in the stack somewhere, @@ -538,7 +538,9 @@ def __init__(self, domain, D): # Construct unflattened codomain R new_vars = [] R = domain - while isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base) or isinstance(R, FractionField_generic): + while isinstance(R, (PolynomialRing_generic, + MPolynomialRing_base, + FractionField_generic)): if isinstance(R, FractionField_generic): # We've hit base_ring, so set _sub_specialization and exit the loop field_over = R.base() diff --git a/src/sage/rings/polynomial/infinite_polynomial_ring.py b/src/sage/rings/polynomial/infinite_polynomial_ring.py index 05735a21cd2..278e7b6e676 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_ring.py +++ b/src/sage/rings/polynomial/infinite_polynomial_ring.py @@ -1265,7 +1265,7 @@ def _first_ngens(self, n): return self.gens()[-n:] @cached_method - def gens_dict(self): + def gens_dict(self) -> GenDictWithBasering: """ Return a dictionary-like object containing the infinitely many ``{var_name:variable}`` pairs. diff --git a/src/sage/rings/polynomial/laurent_polynomial.pyx b/src/sage/rings/polynomial/laurent_polynomial.pyx index 0fed2467c05..cdd459c8218 100644 --- a/src/sage/rings/polynomial/laurent_polynomial.pyx +++ b/src/sage/rings/polynomial/laurent_polynomial.pyx @@ -13,7 +13,7 @@ from sage.structure.element import coerce_binop, parent from sage.structure.factorization import Factorization from sage.misc.derivative import multi_derivative from sage.rings.polynomial.polynomial_element import Polynomial -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.structure.richcmp cimport richcmp, rich_to_bool from sage.rings.infinity import minus_infinity @@ -429,7 +429,7 @@ cdef class LaurentPolynomial_univariate(LaurentPolynomial): if self.__n < 0: raise ValueError("Laurent polynomial with negative valuation cannot be converted to polynomial") - if isinstance(R, PolynomialRing_general): + if isinstance(R, PolynomialRing_generic): return R(self.__u) << self.__n elif self.__n == 0: return R(self.__u) diff --git a/src/sage/rings/polynomial/laurent_polynomial_ideal.py b/src/sage/rings/polynomial/laurent_polynomial_ideal.py index 0403526ae15..096e6bff57d 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ideal.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ideal.py @@ -211,7 +211,7 @@ def __contains__(self, f): g = f.__reduce__()[1][0] return (g in self.polynomial_ideal()) - def gens_reduced(self): + def gens_reduced(self) -> tuple: """ Return a reduced system of generators. diff --git a/src/sage/rings/polynomial/laurent_polynomial_ring.py b/src/sage/rings/polynomial/laurent_polynomial_ring.py index 2e4cf5ce6ea..0e48259a531 100644 --- a/src/sage/rings/polynomial/laurent_polynomial_ring.py +++ b/src/sage/rings/polynomial/laurent_polynomial_ring.py @@ -236,14 +236,14 @@ def LaurentPolynomialRing(base_ring, *args, **kwds): sage: (w0 + 2*w8 + w13)^2 # needs sage.modules w0^2 + 4*w0*w8 + 4*w8^2 + 2*w0*w13 + 4*w8*w13 + w13^2 """ - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base R = PolynomialRing(base_ring, *args, **kwds) if R in _cache: return _cache[R] # put () here to re-enable weakrefs - if isinstance(R, PolynomialRing_general): + if isinstance(R, PolynomialRing_generic): # univariate case P = LaurentPolynomialRing_univariate(R) else: diff --git a/src/sage/rings/polynomial/meson.build b/src/sage/rings/polynomial/meson.build index 94a0a0c8b9a..a74efed061a 100644 --- a/src/sage/rings/polynomial/meson.build +++ b/src/sage/rings/polynomial/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'binary_form_reduce.py', 'commutative_polynomial.pxd', @@ -52,6 +53,7 @@ py.install_sources( 'polynomial_singular_interface.py', 'polynomial_zmod_flint.pxd', 'polynomial_zz_pex.pxd', + 'q_integer_valued_polynomials.py', 'real_roots.pxd', 'skew_polynomial_element.pxd', 'skew_polynomial_finite_field.pxd', diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 1b54a1fd0aa..87b4e2d081c 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -208,6 +208,56 @@ cdef class MPolynomial(CommutativePolynomial): return R(self.polynomial(self._parent(var))) return R([self]) + def leading_support(self, *args, **kwds): + r""" + Return the maximal element of the support of ``self``, + according to the term order. + + If the term ordering of the basis elements is not what is + desired, a comparison key, ``key(x)``, can be provided. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ) + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_support() + (0, 4, 0) + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_support() + (1, 2, 0) + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).leading_support() + (0, 1, 3) + """ + if 'key' in kwds: + return max(self.support(), *args, **kwds) + kwds['key'] = self._parent.term_order().sortkey + return max(self.support(), *args, **kwds) + + def trailing_support(self, *args, **kwds): + r""" + Return the minimal element of the support of ``self``, + according to the term order. + + If the term ordering of the basis elements is not what is + desired, a comparison key, ``key(x)``, can be provided. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ) + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_support() + (1, 1, 1) + sage: R. = PolynomialRing(QQ, order='lex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_support() + (0, 1, 3) + sage: R. = PolynomialRing(QQ, order='invlex') + sage: (3*x*y^2 + 2*y*z^3 + y^4 + 4*x*y*z).trailing_support() + (1, 2, 0) + """ + if 'key' in kwds: + return min(self.support(), *args, **kwds) + kwds['key'] = self._parent.term_order().sortkey + return min(self.support(), *args, **kwds) + def coefficients(self): r""" Return the nonzero coefficients of this polynomial in a list. @@ -429,7 +479,7 @@ cdef class MPolynomial(CommutativePolynomial): for e, val in self.monomial_coefficients().items() if not e[ind]} v = [B(w)] # coefficients that don't involve var z = var - for i in range(1,d+1): + for i in range(1, d+1): c = self.coefficient(z).monomial_coefficients() w = {remove_from_tuple(e, ind): val for e, val in c.items()} v.append(B(w)) @@ -487,7 +537,7 @@ cdef class MPolynomial(CommutativePolynomial): elif my_vars[-1] not in vars: x = base_ring(self) if base_ring is not None else self const_ix = ETuple((0,)*len(vars)) - return { const_ix: x } + return {const_ix: x} elif not set(my_vars).issubset(set(vars)): # we need to split it up p = self.polynomial(self._parent.gen(len(my_vars)-1)) @@ -734,7 +784,7 @@ cdef class MPolynomial(CommutativePolynomial): P = P.change_ring(names=P.variable_names() + [str(var)]) return P(self)._homogenize(len(V)) - elif isinstance(var, int) or isinstance(var, Integer): + elif isinstance(var, (int, Integer)): if 0 <= var < P.ngens(): return self._homogenize(var) else: @@ -769,7 +819,7 @@ cdef class MPolynomial(CommutativePolynomial): subclasses. """ M = self.monomials() - if M==[]: + if M == []: return True d = M.pop().degree() for m in M: @@ -1099,14 +1149,14 @@ cdef class MPolynomial(CommutativePolynomial): g = R.gen_names() v = [] for m, c in zip(self.monomials(), self.coefficients()): - v.append('(%s)*%s'%( c._magma_init_(magma), - m._repr_with_changed_varnames(g))) + v.append('(%s)*%s' % (c._magma_init_(magma), + m._repr_with_changed_varnames(g))) if len(v) == 0: s = '0' else: s = '+'.join(v) - return '%s!(%s)'%(R.name(), s) + return '%s!(%s)' % (R.name(), s) def _giac_init_(self): r""" @@ -1183,7 +1233,7 @@ cdef class MPolynomial(CommutativePolynomial): """ from sage.geometry.polyhedron.constructor import Polyhedron e = self.exponents() - P = Polyhedron(vertices = e, base_ring=ZZ) + P = Polyhedron(vertices=e, base_ring=ZZ) return P def __iter__(self): @@ -1399,7 +1449,7 @@ cdef class MPolynomial(CommutativePolynomial): raise TypeError("k must be a finite field") p = k.characteristic() e = k.degree() - v = [self] + [self.map_coefficients(k.hom([k.gen()**(p**i)])) for i in range(1,e)] + v = [self] + [self.map_coefficients(k.hom([k.gen()**(p**i)])) for i in range(1, e)] return prod(v).change_ring(k.prime_subfield()) def sylvester_matrix(self, right, variable=None): @@ -1854,7 +1904,7 @@ cdef class MPolynomial(CommutativePolynomial): for y in x: d = d.lcm(y.denominator()) return d - except(AttributeError): + except AttributeError: return self.base_ring().one() def numerator(self): @@ -1975,7 +2025,7 @@ cdef class MPolynomial(CommutativePolynomial): ArithmeticError: element is non-invertible """ P = self.parent() - B = I.gens() + B = I.gens() try: XY = P.one().lift((self,) + tuple(B)) return P(XY[0]) @@ -2061,7 +2111,7 @@ cdef class MPolynomial(CommutativePolynomial): #Corner case, note that the degree of zero is an Integer return Integer(-1) - if len(weights) == 1: + if len(weights) == 1: # First unwrap it if it is given as one element argument weights = weights[0] @@ -2082,9 +2132,9 @@ cdef class MPolynomial(CommutativePolynomial): for i in range(n): l += weights[i]*m[i] deg = l - for j in range(1,len(A)): + for j in range(1, len(A)): l = Integer(0) - m = A[j] + m = A[j] for i in range(n): l += weights[i]*m[i] if deg < l: @@ -2510,12 +2560,12 @@ cdef class MPolynomial(CommutativePolynomial): from sage.rings.real_mpfr import RealField if self.parent().ngens() != 2: - raise ValueError("(=%s) must have two variables"%self) + raise ValueError("(=%s) must have two variables" % self) if not self.is_homogeneous(): - raise ValueError("(=%s) must be homogeneous"%self) + raise ValueError("(=%s) must be homogeneous" % self) prec = kwds.get('prec', 300) - return_conjugation =kwds.get('return_conjugation', True) + return_conjugation = kwds.get('return_conjugation', True) error_limit = kwds.get('error_limit', 0.000001) emb = kwds.get('emb', None) @@ -2523,14 +2573,14 @@ cdef class MPolynomial(CommutativePolynomial): CF = ComplexIntervalField(prec=prec) # keeps trac of our precision error RF = RealField(prec=prec) R = self.parent() - x,y = R.gens() + x, y = R.gens() # finding quadratic Q_0, gives us our covariant, z_0 from sage.rings.polynomial.binary_form_reduce import covariant_z0 try: z, th = covariant_z0(self, prec=prec, emb=emb, z0_cov=True) except ValueError:# multiple roots - F = self.lc()*prod([p for p,e in self.factor()]) + F = self.lc()*prod([p for p, e in self.factor()]) z, th = covariant_z0(F, prec=prec, emb=emb, z0_cov=True) z = CF(z) # this moves z_0 to our fundamental domain using the three steps laid @@ -2544,11 +2594,11 @@ cdef class MPolynomial(CommutativePolynomial): # moves z into fundamental domain by m m = zc.real().round() # finds amount to move z's real part by Qm = QQ(m) - M = M * matrix(QQ, [[1,Qm], [0,1]]) # move + M = M * matrix(QQ, [[1, Qm], [0, 1]]) # move z -= m # M.inverse()*z is supposed to move z by m elif (zc.real() <= RF(0) and zc.abs() < RF(1)) or (zc.real() > RF(0) and zc.abs() <= RF(1)): # flips z z = -1/z - M = M * matrix(QQ, [[0,-1], [1,0]])# multiply on left because we are taking inverse matrices + M = M * matrix(QQ, [[0, -1], [1, 0]])# multiply on left because we are taking inverse matrices zc = z.center() smallest_coeffs = kwds.get('smallest_coeffs', True) diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 3e00ef62991..3b18664f505 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -636,12 +636,12 @@ def degree(self, x=None, std_grading=False): sage: GF(3037000453)['x','y'].gen(0).degree(x0) # needs sage.rings.finite_rings Traceback (most recent call last): ... - TypeError: x must canonically coerce to parent + TypeError: argument is not coercible to the parent sage: GF(3037000453)['x','y'].gen(0).degree(x^2) # needs sage.rings.finite_rings Traceback (most recent call last): ... - TypeError: x must be one of the generators of the parent + TypeError: argument is not a generator TESTS:: @@ -802,7 +802,7 @@ def monomial_coefficient(self, mon): zero = self.parent().base_ring().zero() return self.element().get(exp, zero) - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return underlying dictionary with keys the exponents and values the coefficients of this polynomial. @@ -817,7 +817,7 @@ def monomial_coefficients(self): ``dict`` is an alias:: - sage: f.dict() # needs sage.rings.number_field + sage: f.dict() # needs sage.rings.number_field {(1, 5, 2): 1, (2, 0, 1): 1, (4, 1, 3): 1} """ return self.element().dict() diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index d06f07d722e..24239660dec 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -248,9 +248,10 @@ from sage.rings.integer_ring import ZZ from sage.rings.noncommutative_ideals import Ideal_nc from sage.rings.qqbar_decorators import handle_AA_and_QQbar +from sage.structure.element import parent from sage.structure.richcmp import (op_EQ, op_GE, op_GT, op_LE, op_LT, op_NE, rich_to_bool, richcmp_method) -from sage.structure.sequence import Sequence +from sage.structure.sequence import Sequence, Sequence_generic try: from sage.interfaces.expect import StdOutContext @@ -447,8 +448,7 @@ def _groebner_basis_magma(self, deg_bound=None, prot=False, magma=magma_default) from sage.rings.polynomial.multi_polynomial_sequence import \ PolynomialSequence - B = PolynomialSequence([R(e) for e in mgb], R, immutable=True) - return B + return PolynomialSequence([R(e) for e in mgb], R, immutable=True) class MPolynomialIdeal_singular_base_repr: @@ -600,10 +600,10 @@ def _groebner_cover(self): """ from sage.rings.fraction_field import FractionField_generic from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic F = self.base_ring() if (not isinstance(F, FractionField_generic) or - not isinstance(F.ring(), (MPolynomialRing_base, PolynomialRing_general))): + not isinstance(F.ring(), (MPolynomialRing_base, PolynomialRing_generic))): raise TypeError("the base ring must be a field with parameters") from sage.arith.functions import lcm from sage.libs.singular.function import lib, singular_function @@ -1160,7 +1160,7 @@ def triangular_decomposition(self, algorithm=None, singular=None): else: raise TypeError("algorithm '%s' unknown" % algorithm) - T = Sequence([ MPolynomialIdeal(Q,t) for t in Tbar]) + T = Sequence([MPolynomialIdeal(Q, t) for t in Tbar]) return sorted(T, key=lambda x: x.gens()) @require_field @@ -3918,10 +3918,12 @@ def __hash__(self): return 0 @cached_method - def gens(self): + def gens(self) -> Sequence_generic: """ - Return a set of generators / a basis of this ideal. This is usually the - set of generators provided during object creation. + Return a set of generators / a basis of this ideal. + + This is usually the set of generators provided during object + creation. EXAMPLES:: @@ -4527,8 +4529,7 @@ def groebner_basis(self, algorithm='', deg_bound=None, mult_bound=None, prot=Fal sage: R. = PolynomialRing(Zmod(2233497349584)) sage: I = R.ideal([z*(x-3*y), 3^2*x^2-y*z, z^2+y^2]) sage: I.groebner_basis() - [2*z^4, y*z^2 + 81*z^3, 248166372176*z^3, 9*x^2 - y*z, y^2 + z^2, x*z + - 2233497349581*y*z, 248166372176*y*z] + [2*z^4, y*z^2 + 81*z^3, 248166372176*z^3, 9*x^2 + 2233497349583*y*z, y^2 + z^2, x*z + 2233497349581*y*z, 248166372176*y*z] Sage also supports local orderings:: @@ -4965,6 +4966,23 @@ def reduce(self, f): Requires computation of a Groebner basis, which can be a very expensive operation. + + TESTS: + + Check for :issue:`38560`:: + + sage: I.reduce(1) + 1 + sage: I.reduce(1r) + 1 + sage: I.reduce(pi.n()) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Real Field with 53 bits of precision to Multivariate Polynomial Ring in x, y over Rational Field + sage: I.reduce(float(pi.n())) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from to Multivariate Polynomial Ring in x, y over Rational Field """ try: strat = self._groebner_strategy() @@ -4973,6 +4991,7 @@ def reduce(self, f): pass gb = self.groebner_basis() + f = self.ring().coerce(f) return f.reduce(gb) def _contains_(self, f): diff --git a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx index 72b4aea43ce..adf3df1cf95 100644 --- a/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_libsingular.pyx @@ -65,7 +65,7 @@ We show how to construct various multivariate polynomial rings:: sage: P. = Zmod(25213521351515232)[]; P Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 25213521351515232 sage: type(P) - + We construct the Frobenius morphism on `\GF{5}[x,y,z]` over `\GF{5}`:: @@ -170,6 +170,8 @@ AUTHORS: # * pNext and pIter don't need currRing # * p_Normalize apparently needs currRing +from warnings import warn + from cpython.object cimport Py_NE from cysignals.memory cimport sig_malloc, sig_free from cysignals.signals cimport sig_on, sig_off @@ -183,7 +185,6 @@ from sage.libs.singular.decl cimport (ring, poly, ideal, intvec, number, # singular functions from sage.libs.singular.decl cimport ( - errorreported, n_Invers, n_GetChar, p_ISet, rChangeCurrRing, p_Copy, p_Init, p_SetCoeff, p_Setm, p_SetExp, p_Add_q, p_NSet, p_GetCoeff, p_Delete, p_GetExp, pNext, rRingVar, omAlloc0, omStrDup, @@ -198,7 +199,7 @@ from sage.libs.singular.decl cimport ( prCopyR, prCopyR_NoSort) # singular conversion routines -from sage.libs.singular.singular cimport si2sa, sa2si, overflow_check +from sage.libs.singular.singular cimport si2sa, sa2si, overflow_check, start_catch_error, check_error # singular poly arith from sage.libs.singular.polynomial cimport ( @@ -212,13 +213,15 @@ from sage.libs.singular.polynomial cimport ( # singular rings from sage.libs.singular.ring cimport singular_ring_new, singular_ring_reference, singular_ring_delete +from sage.rings.finite_rings.finite_field_prime_modn import FiniteField_prime_modn + # polynomial imports from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_polydict, MPolynomialRing_polydict_domain from sage.rings.polynomial.multi_polynomial_ring_base import BooleanPolynomialRing_base from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal from sage.rings.polynomial.polydict cimport ETuple -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic # base ring imports import sage.rings.abc @@ -340,11 +343,11 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): Multivariate Polynomial Ring in x, y, z over Ring of integers modulo 25213521351515232 sage: type(P) - + sage: P. = PolynomialRing(Integers(2^32), order='lex') sage: P(2^32-1) - 4294967295 + -1 TESTS: @@ -508,7 +511,7 @@ cdef class MPolynomialRing_libsingular(MPolynomialRing_base): return True elif base_ring.has_coerce_map_from(other._mpoly_base_ring(self.variable_names())): return True - elif isinstance(other, PolynomialRing_general): + elif isinstance(other, PolynomialRing_generic): if base_ring.has_coerce_map_from(other._mpoly_base_ring(self.variable_names())): return True @@ -2997,7 +3000,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): return self._parent._base._zero_element - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return a dictionary representing ``self``. This dictionary is in the same format as the generic MPolynomial: The dictionary @@ -4047,7 +4050,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): _p = p_Head(self._poly, _ring) _n = p_GetCoeff(_p, _ring) - ret = si2sa(_n, _ring, self._parent._base) + ret = si2sa(_n, _ring, self._parent._base) p_Delete(&_p, _ring) return ret @@ -4151,6 +4154,37 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): True sage: p*q//p == q True + + Test many base rings:: + + sage: R. = GF(2^32+15)[] + sage: ((x+y)^3+x+z)//(x+y) + Traceback (most recent call last): + ... + NotImplementedError: Division of multivariate polynomials over non fields by non-monomials not implemented. + sage: R. = Zmod(2^29-3)[] + sage: ((x+y)^3+x+z)//(x+y) + Traceback (most recent call last): + ... + NotImplementedError: Division of multivariate polynomials over non fields by non-monomials not implemented. + sage: R. = GF(2^29+11)[] + sage: ((x+y)^3+x+z)//(x+y) + Traceback (most recent call last): + ... + NotImplementedError: Division of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = Zmod(2^29+10)[] + sage: ((x+y)^3+x+z)//(x+y) + Traceback (most recent call last): + ... + NotImplementedError: Division of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = GF((2^29-3)^2)[] + sage: ((x+y)^3+x+z)//(x+y) + x^2 + 2*x*y + y^2 + sage: R. = Zmod(7^2)[] + sage: ((x+y)^3+x+z)//(x+y) + Traceback (most recent call last): + ... + NotImplementedError: Division of multivariate polynomials over non fields by non-monomials not implemented. """ cdef MPolynomialRing_libsingular parent = self._parent cdef MPolynomial_libsingular _right = right @@ -4461,12 +4495,58 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: N = -a^4*z^8 + 2*a^2*b^2*z^8 - b^4*z^8 - 16*a^3*b*z^7 + 16*a*b^3*z^7 + 28*a^4*z^6 - 56*a^2*b^2*z^6 + 28*b^4*z^6 + 112*a^3*b*z^5 - 112*a*b^3*z^5 - 70*a^4*z^4 + 140*a^2*b^2*z^4 - 70*b^4*z^4 - 112*a^3*b*z^3 + 112*a*b^3*z^3 + 28*a^4*z^2 - 56*a^2*b^2*z^2 + 28*b^4*z^2 + 16*a^3*b*z - 16*a*b^3*z - a^4 + 2*a^2*b^2 - b^4 sage: N.factor() (-1) * (-a + b) * (a + b) * (-z^4*a + z^4*b - 4*z^3*a - 4*z^3*b + 6*z^2*a - 6*z^2*b + 4*z*a + 4*z*b - a + b) * (z^4*a + z^4*b - 4*z^3*a + 4*z^3*b - 6*z^2*a - 6*z^2*b + 4*z*a - 4*z*b + a + b) + + Test many base rings:: + + sage: R. = GF(2^32+15)[] + sage: ((x+y)^2*(x+z)^3).factor() + Traceback (most recent call last): + ... + NotImplementedError: Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = Zmod(2^29-3)[] + sage: ((x+y)^2*(x+z)^3).factor() + (x + y)^2 * (x + z)^3 + sage: R. = GF(2^29+11)[] + sage: ((x+y)^2*(x+z)^3).factor() + Traceback (most recent call last): + ... + NotImplementedError: Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = Zmod(2^29+10)[] + sage: ((x+y)^2*(x+z)^3).factor() + Traceback (most recent call last): + ... + NotImplementedError: Factorization of multivariate polynomials over Ring of integers modulo 536870922 is not implemented. + sage: R. = GF((2^29-3)^2)[] + sage: ((x+y)^2*(x+z)^3).factor() + (x + y)^2 * (x + z)^3 + sage: R. = Zmod(7^2)[] + sage: ((x+y)^2*(x+z)^3).factor() + Traceback (most recent call last): + ... + NotImplementedError: Factorization of multivariate polynomials over Ring of integers modulo 49 is not implemented. + + Ensure interrupt does not make the internal state inconsistent:: + + sage: R. = QQ[] + sage: n = 11 # chosen so that the computation takes > 1 second but not excessively long. + ....: # when Singular improves the algorithm or hardware gets faster, increase n. + sage: alarm(0.5); h = (x^2^n-y^2^n).factor() + Traceback (most recent call last): + ... + AlarmInterrupt + sage: alarm(0.5); h = (x^2^n-y^2^n).factor() + Traceback (most recent call last): + ... + AlarmInterrupt + sage: h = (x^2^n-y^2^n).factor() + sage: h + (x - y) * (x + y) * (x^2 + y^2) * (x^4 + y^4) * (x^8 + y^8) * (x^16 + y^16) * (x^32 + y^32) * (x^64 + y^64) * (x^128 + y^128) * (x^256 + y^256) * (x^512 + y^512) * (x^1024 + y^1024) """ cdef ring *_ring = self._parent_ring cdef poly *ptemp cdef intvec *iv cdef int *ivv - cdef ideal *I + cdef ideal *I = NULL cdef MPolynomialRing_libsingular parent = self._parent cdef int i @@ -4485,31 +4565,31 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): except Exception: raise NotImplementedError("Factorization of multivariate polynomials over %s is not implemented."%self._parent._base) - if n_GetChar(_ring.cf) > 1<<29: - raise NotImplementedError("Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") - - # I make a temporary copy of the poly in self because singclap_factorize appears to modify it's parameter - ptemp = p_Copy(self._poly, _ring) iv = NULL - sig_on() if _ring != currRing: rChangeCurrRing(_ring) # singclap_factorize - I = singclap_factorize(ptemp, &iv, 0, _ring) - sig_off() - - ivv = iv.ivGetVec() - v = [(new_MP(parent, p_Copy(I.m[i], _ring)), ivv[i]) - for i in range(1, I.ncols)] - v = [(f, m) for f, m in v if f != 0] # we might have zero in there - unit = new_MP(parent, p_Copy(I.m[0], _ring)) - - F = Factorization(v, unit) - F.sort() - - del iv - id_Delete(&I, _ring) - - return F + start_catch_error() + try: + try: + sig_on() + I = singclap_factorize(p_Copy(self._poly, _ring), &iv, 0, _ring) + sig_off() + finally: + if check_error(): + raise NotImplementedError("Factorization of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") + + ivv = iv.ivGetVec() + v = [(new_MP(parent, p_Copy(I.m[i], _ring)), ivv[i]) + for i in range(1, I.ncols)] + v = [(f, m) for f, m in v if f != 0] # we might have zero in there + unit = new_MP(parent, p_Copy(I.m[0], _ring)) + + F = Factorization(v, unit) + F.sort() + return F + finally: + del iv + id_Delete(&I, _ring) def lift(self, I): """ @@ -4559,7 +4639,6 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: M [y^7, x^7*y^2 + x^8 + x^5*y^3 + x^6*y + x^3*y^4 + x^4*y^2 + x*y^5 + x^2*y^3 + y^4] - TESTS: Check that :issue:`13714` is fixed:: @@ -4573,16 +4652,32 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: foo = I.complete_primary_decomposition() # indirect doctest sage: foo[0][0] Ideal (x1 + 1, x2^2 - 3) of Multivariate Polynomial Ring in x1, x2 over Rational Field - """ - global errorreported + Ensure interrupt does not make the internal state inconsistent:: + + sage: R. = QQ[] + sage: n = 17 # chosen so that the computation takes > 1 second but not excessively long. + ....: # when Singular improves the algorithm or hardware gets faster, increase n. + sage: I = R.ideal([(x-i)*(y-j) for i in (0..n) for j in (0..n)]) + sage: f = prod((x-i)*(y-j) for i in (0..n) for j in (0..n)) + sage: alarm(0.5); f.lift(I) + Traceback (most recent call last): + ... + AlarmInterrupt + sage: alarm(0.5); f.lift(I) + Traceback (most recent call last): + ... + AlarmInterrupt + sage: f.lift(I) + Polynomial Sequence with 324 Polynomials in 2 Variables + """ cdef ideal *fI = idInit(1, 1) cdef ideal *_I cdef MPolynomialRing_libsingular parent = self._parent cdef int i = 0 cdef int j cdef ring *r = self._parent_ring - cdef ideal *res + cdef ideal *res = NULL if isinstance(I, MPolynomialIdeal): I = I.gens() @@ -4606,24 +4701,25 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): if r != currRing: rChangeCurrRing(r) # idLift - sig_on() - res = idLift(_I, fI, NULL, 0, 0, 0) - sig_off() - if errorreported != 0: - errorcode = errorreported - errorreported = 0 - if errorcode == 1: + try: + start_catch_error() + try: + sig_on() + res = idLift(_I, fI, NULL, 0, 0, 0) + sig_off() + finally: + s = check_error() + if s: + if s != ('2nd module does not lie in the first',): + warn(f'unexpected error from singular: {s}') raise ValueError("polynomial is not in the ideal") - raise RuntimeError - - l = [] - for i from 0 <= i < IDELEMS(res): - for j from 1 <= j <= IDELEMS(_I): - l.append( new_MP(parent, pTakeOutComp(&res.m[i], 1)) ) - id_Delete(&fI, r) - id_Delete(&_I, r) - id_Delete(&res, r) + l = [new_MP(parent, pTakeOutComp(&res.m[i], 1)) + for i in range(IDELEMS(res)) for _ in range(IDELEMS(_I))] + finally: + id_Delete(&fI, r) + id_Delete(&_I, r) + id_Delete(&res, r) return Sequence(l, check=False, immutable=True) def reduce(self, I): @@ -4731,7 +4827,8 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): id_Delete(&_I,r) return new_MP(parent,res) - def divides(self, other): + @coerce_binop + def divides(self, MPolynomial_libsingular other): """ Return ``True`` if this polynomial divides ``other``. @@ -4763,27 +4860,21 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): rChangeCurrRing(r) _I = idInit(1, 1) - if not (isinstance(other,MPolynomial_libsingular) - and (other)._parent is parent): - try: - other = parent.coerce(other) - except TypeError as msg: - id_Delete(&_I,r) - raise TypeError(msg) - _I.m[0] = p_Copy(self._poly, r) if r != currRing: rChangeCurrRing(r) - sig_on() - rem = kNF(_I, NULL, (other)._poly, 0, 1) - sig_off() - id_Delete(&_I, r) + try: + sig_on() + rem = kNF(_I, NULL, other._poly, 0, 1) + sig_off() + finally: + id_Delete(&_I, r) res = new_MP(parent, rem).is_zero() return res @coerce_binop - def gcd(self, right, algorithm=None, **kwds): + def gcd(self, MPolynomial_libsingular right, algorithm=None, **kwds): """ Return the greatest common divisor of ``self`` and ``right``. @@ -4858,10 +4949,40 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: q = -3*x^2*y^7*z + 2*x*y^6*z^3 + 2*x^2*y^3*z^4 + x^2*y^5 - 7*x*y^5*z sage: (21^3*p^2*q).gcd(35^2*p*q^2) == -49*p*q True + + Test many base rings:: + + sage: R. = GF(2^32+15)[] + sage: ((x+y)^2*(x+z)^3).gcd((x+y)^3*(y+z)^5) + Traceback (most recent call last): + ... + NotImplementedError: GCD over rings not implemented. + sage: R. = Zmod(2^29-3)[] + sage: ((x+y)^2*(x+z)^3).gcd((x+y)^3*(y+z)^5) + Traceback (most recent call last): + ... + NotImplementedError: GCD over rings not implemented. + sage: R. = GF(2^29+11)[] + sage: ((x+y)^2*(x+z)^3).gcd((x+y)^3*(y+z)^5) + Traceback (most recent call last): + ... + NotImplementedError: GCD of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = Zmod(2^29+10)[] + sage: ((x+y)^2*(x+z)^3).gcd((x+y)^3*(y+z)^5) + Traceback (most recent call last): + ... + NotImplementedError: GCD over rings not implemented. + sage: R. = GF((2^29-3)^2)[] + sage: ((x+y)^2*(x+z)^3).gcd((x+y)^3*(y+z)^5) + x^2 + 2*x*y + y^2 + sage: R. = Zmod(7^2)[] + sage: ((x+y)^2*(x+z)^3).gcd((x+y)^3*(y+z)^5) + Traceback (most recent call last): + ... + NotImplementedError: GCD over rings not implemented. """ cdef poly *_res cdef ring *_ring = self._parent_ring - cdef MPolynomial_libsingular _right = right if algorithm is None or algorithm == "modular": On(SW_USE_CHINREM_GCD) @@ -4872,13 +4993,13 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): else: raise TypeError("algorithm %s not supported" % algorithm) - if _right._poly == NULL: + if right._poly == NULL: return self elif self._poly == NULL: return right elif p_IsOne(self._poly, _ring): return self - elif p_IsOne(_right._poly, _ring): + elif p_IsOne(right._poly, _ring): return right if _ring.cf.type != n_unknown: @@ -4889,10 +5010,10 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): raise NotImplementedError("GCD of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") cdef int count = singular_polynomial_length_bounded(self._poly, 20) \ - + singular_polynomial_length_bounded(_right._poly,20) + + singular_polynomial_length_bounded(right._poly, 20) if count >= 20: sig_on() - _res = singclap_gcd(p_Copy(self._poly, _ring), p_Copy(_right._poly, _ring), _ring ) + _res = singclap_gcd(p_Copy(self._poly, _ring), p_Copy(right._poly, _ring), _ring) if count >= 20: sig_off() @@ -4944,6 +5065,37 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): 2*x*y sage: lcm(2*x, 2*x*y) 2*x*y + + Test many base rings:: + + sage: R. = GF(2^32+15)[] + sage: ((x+y)^2*(x+z)^3).lcm((x+y)^3*(y+z)^5) + Traceback (most recent call last): + ... + TypeError: LCM over non-integral domains not available. + sage: R. = Zmod(2^29-3)[] + sage: ((x+y)^2*(x+z)^3).lcm((x+y)^3*(y+z)^5) + Traceback (most recent call last): + ... + TypeError: LCM over non-integral domains not available. + sage: R. = GF(2^29+11)[] + sage: ((x+y)^2*(x+z)^3).lcm((x+y)^3*(y+z)^5) + Traceback (most recent call last): + ... + NotImplementedError: LCM of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = Zmod(2^29+10)[] + sage: ((x+y)^2*(x+z)^3).lcm((x+y)^3*(y+z)^5) + Traceback (most recent call last): + ... + TypeError: LCM over non-integral domains not available. + sage: R. = GF((2^29-3)^2)[] + sage: ((x+y)^2*(x+z)^3).lcm((x+y)^3*(y+z)^5) + x^6*y^5 + 3*x^5*y^6 + 3*x^4*y^7 + x^3*y^8 + 5*x^6*y^4*z + 18*x^5*y^5*z + 24*x^4*y^6*z + 14*x^3*y^7*z + 3*x^2*y^8*z + 10*x^6*y^3*z^2 + 45*x^5*y^4*z^2 + 78*x^4*y^5*z^2 + 64*x^3*y^6*z^2 + 24*x^2*y^7*z^2 + 3*x*y^8*z^2 + 10*x^6*y^2*z^3 + 60*x^5*y^3*z^3 + 135*x^4*y^4*z^3 + 146*x^3*y^5*z^3 + 78*x^2*y^6*z^3 + 18*x*y^7*z^3 + y^8*z^3 + 5*x^6*y*z^4 + 45*x^5*y^2*z^4 + 135*x^4*y^3*z^4 + 190*x^3*y^4*z^4 + 135*x^2*y^5*z^4 + 45*x*y^6*z^4 + 5*y^7*z^4 + x^6*z^5 + 18*x^5*y*z^5 + 78*x^4*y^2*z^5 + 146*x^3*y^3*z^5 + 135*x^2*y^4*z^5 + 60*x*y^5*z^5 + 10*y^6*z^5 + 3*x^5*z^6 + 24*x^4*y*z^6 + 64*x^3*y^2*z^6 + 78*x^2*y^3*z^6 + 45*x*y^4*z^6 + 10*y^5*z^6 + 3*x^4*z^7 + 14*x^3*y*z^7 + 24*x^2*y^2*z^7 + 18*x*y^3*z^7 + 5*y^4*z^7 + x^3*z^8 + 3*x^2*y*z^8 + 3*x*y^2*z^8 + y^3*z^8 + sage: R. = Zmod(7^2)[] + sage: ((x+y)^2*(x+z)^3).lcm((x+y)^3*(y+z)^5) + Traceback (most recent call last): + ... + TypeError: LCM over non-integral domains not available. """ cdef ring *_ring = self._parent_ring cdef poly *ret @@ -5026,6 +5178,56 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): Traceback (most recent call last): ... ZeroDivisionError + + Test many base rings:: + + sage: R. = GF(2^32+15)[] + sage: ((x+y)^3+x+z).quo_rem(x+y) + Traceback (most recent call last): + ... + NotImplementedError: Division of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = Zmod(2^29-3)[] + sage: ((x+y)^3+x+z).quo_rem(x+y) + (x^2 + 2*x*y + y^2, x + z) + sage: R. = GF(2^29+11)[] + sage: ((x+y)^3+x+z).quo_rem(x+y) + Traceback (most recent call last): + ... + NotImplementedError: Division of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = Zmod(2^29+10)[] + sage: ((x+y)^3+x+z).quo_rem(x+y) + Traceback (most recent call last): + ... + NotImplementedError: Division of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = GF((2^29-3)^2)[] + sage: ((x+y)^3+x+z).quo_rem(x+y) + (x^2 + 2*x*y + y^2, x + z) + sage: R. = Zmod(7^2)[] + sage: ((x+y)^3+x+z).quo_rem(x+y) + Traceback (most recent call last): + ... + NotImplementedError: Division of multivariate polynomials over non fields by non-monomials not implemented. + + Ensure interrupt does not make the internal state inconsistent:: + + sage: R. = PolynomialRing(QQ, order="lex") + sage: n = 300 # chosen so that the computation takes > 1 second but not excessively long. + ....: # when Singular improves the algorithm or hardware gets faster, increase n. + sage: f = z^n-2 + sage: g = z^2-z-x^2*y-x*y^3 + sage: alarm(0.5); f.quo_rem(g) + Traceback (most recent call last): + ... + AlarmInterrupt + sage: alarm(0.5); f.quo_rem(g) + Traceback (most recent call last): + ... + AlarmInterrupt + sage: q, r = f.quo_rem(g) + sage: len(dict(q)) + 307638 + sage: len(dict(r)) + 11409 """ cdef poly *quo cdef poly *rem @@ -5041,17 +5243,17 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): py_rem = self - right*py_quo return py_quo, py_rem - if n_GetChar(r.cf) > 1<<29: - raise NotImplementedError("Division of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") - - cdef int count = singular_polynomial_length_bounded(self._poly, 15) - if count >= 15: # note that _right._poly must be of shorter length than self._poly for us to care about this call + if r != currRing: + rChangeCurrRing(r) # singclap_pdivide + start_catch_error() + try: sig_on() - if r!=currRing: rChangeCurrRing(r) # singclap_pdivide - quo = singclap_pdivide( self._poly, right._poly, r ) - rem = p_Add_q(p_Copy(self._poly, r), p_Neg(pp_Mult_qq(right._poly, quo, r), r), r) - if count >= 15: + quo = singclap_pdivide(self._poly, right._poly, r) sig_off() + finally: + if check_error(): + raise NotImplementedError("Division of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") + rem = p_Add_q(p_Copy(self._poly, r), p_Neg(pp_Mult_qq(right._poly, quo, r), r), r) return new_MP(parent, quo), new_MP(parent, rem) def _singular_init_(self, singular=None): @@ -5424,6 +5626,7 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): _p = p_Add_q(_p, mon, _ring) return new_MP(self._parent, _p) + @coerce_binop def resultant(self, MPolynomial_libsingular other, variable=None): """ Compute the resultant of this polynomial and the first @@ -5479,40 +5682,91 @@ cdef class MPolynomial_libsingular(MPolynomial_libsingular_base): sage: g=y^2+x sage: f.resultant(g,y) x^2 + x + + sage: R. = GF(2^32+15)[] + sage: (x-z).resultant(y-z,z) + Traceback (most recent call last): + ... + NotImplementedError: Resultants of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = Zmod(2^29-3)[] + sage: (x-z).resultant(y-z,z) + x + 536870908*y + sage: R. = GF(2^29+11)[] + sage: (x-z).resultant(y-z,z) + Traceback (most recent call last): + ... + NotImplementedError: Resultants of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented. + sage: R. = Zmod(2^29+10)[] + sage: (x-z).resultant(y-z,z) + Traceback (most recent call last): + ... + NotImplementedError: Resultants require base fields or integer base ring. + sage: R. = GF((2^29-3)^2)[] + sage: (x-z).resultant(y-z,z) + x - y + sage: R. = Zmod(7^2)[] + sage: (x-z).resultant(y-z,z) + Traceback (most recent call last): + ... + NotImplementedError: Resultants require base fields or integer base ring. + + Sometimes simple-looking computations can take a long time:: + + sage: R. = QQ[] + sage: n = 22 # chosen so that the computation takes > 1 second but not excessively long. + ....: # when Singular improves the algorithm or hardware gets faster, increase n. + sage: f = x^n+y^(n-1)+z^(n-2)+y^3*z^2 + sage: g = x^(n-3)+y^(n-4)+z^(n-5)+y*z + sage: h = f.resultant(g, x) + sage: len(dict(h)) + 89 + + As such we test the computation is interruptible (previously it wasn't):: + + sage: alarm(0.5); h = f.resultant(g, x) + Traceback (most recent call last): + ... + AlarmInterrupt + + Test again to ensure interrupt does not make the internal state inconsistent:: + + sage: alarm(0.5); h = f.resultant(g, x); cancel_alarm() + Traceback (most recent call last): + ... + AlarmInterrupt + sage: h = f.resultant(g, x) + sage: len(dict(h)) + 89 """ cdef ring *_ring = self._parent_ring cdef poly *rt if variable is None: variable = self.parent().gen(0) - - if self._parent is not other._parent: - raise TypeError("first parameter needs to be an element of self.parent()") - - if not variable.parent() is self.parent(): + elif variable.parent() is not self.parent(): raise TypeError("second parameter needs to be an element of self.parent() or None") - if n_GetChar(_ring.cf) > 1<<29: - raise NotImplementedError("Resultants of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") - if isinstance(self._parent._base, IntegerRing_class): ret = self.change_ring(QQ).resultant(other.change_ring(QQ), variable.change_ring(QQ)) return ret.change_ring(ZZ) - elif not self._parent._base.is_field(): - raise ValueError("Resultants require base fields or integer base ring.") - cdef int count = singular_polynomial_length_bounded(self._poly, 20) \ - + singular_polynomial_length_bounded(other._poly,20) - if count >= 20: + start_catch_error() + try: sig_on() - if _ring != currRing: rChangeCurrRing(_ring) # singclap_resultant - rt = singclap_resultant(p_Copy(self._poly, _ring), - p_Copy(other._poly, _ring), - p_Copy((variable)._poly, _ring ), - _ring) - if count >= 20: + if _ring != currRing: + rChangeCurrRing(_ring) # singclap_resultant + rt = singclap_resultant(p_Copy(self._poly, _ring), + p_Copy(other._poly, _ring), + p_Copy((variable)._poly, _ring), + _ring) sig_off() + finally: + if check_error(): + if isinstance(self._parent._base, FiniteField_prime_modn): + raise NotImplementedError("Resultants of multivariate polynomials over prime fields with characteristic > 2^29 is not implemented.") + raise NotImplementedError("Resultants require base fields or integer base ring.") + return new_MP(self._parent, rt) def coefficients(self): diff --git a/src/sage/rings/polynomial/multi_polynomial_ring.py b/src/sage/rings/polynomial/multi_polynomial_ring.py index 43f1c0f6294..26c32fe036c 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring.py +++ b/src/sage/rings/polynomial/multi_polynomial_ring.py @@ -60,14 +60,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** -from sage.rings.ring import IntegralDomain import sage.rings.fraction_field_element as fraction_field_element from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base, is_MPolynomialRing from sage.rings.polynomial.polynomial_singular_interface import PolynomialRing_singular_repr from sage.rings.polynomial.polydict import PolyDict, ETuple from sage.rings.polynomial.term_order import TermOrder - import sage.interfaces.abc try: @@ -558,9 +556,9 @@ def __call__(self, x=0, check=True): c = self.base_ring()(x) return MPolynomial_polydict(self, {self._zero_tuple: c}) -# The following methods are handy for implementing Groebner -# basis algorithms. They do only superficial type/sanity checks -# and should be called carefully. + # The following methods are handy for implementing Groebner + # basis algorithms. They do only superficial type/sanity checks + # and should be called carefully. def monomial_quotient(self, f, g, coeff=False): r""" @@ -930,21 +928,17 @@ def sum(self, terms): elt = PolyDict({}, check=False) for t in terms: elt += self(t).element() - # NOTE: here we should be using self.element_class but polynomial rings are not complient - # with categories... + # NOTE: here we should be using self.element_class but + # polynomial rings are not complient with categories... from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict return MPolynomial_polydict(self, elt) -class MPolynomialRing_polydict_domain(IntegralDomain, - MPolynomialRing_polydict): +class MPolynomialRing_polydict_domain(MPolynomialRing_polydict): def __init__(self, base_ring, n, names, order): order = TermOrder(order, n) MPolynomialRing_polydict.__init__(self, base_ring, n, names, order) - def is_integral_domain(self, proof=True): - return True - def is_field(self, proof=True): if self.ngens() == 0: return self.base_ring().is_field(proof) diff --git a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx index ac5e445908d..8baa8b40b24 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx +++ b/src/sage/rings/polynomial/multi_polynomial_ring_base.pyx @@ -90,14 +90,11 @@ cdef class MPolynomialRing_base(CommutativeRing): self._term_order = order self._has_singular = False # cannot convert to Singular by default self._magma_cache = {} - # Ring.__init__ already does assign the names. - # It would be a mistake to call ParentWithGens.__init__ - # as well, assigning the names twice. - # ParentWithGens.__init__(self, base_ring, names) if base_ring.is_zero(): category = categories.rings.Rings().Finite() else: category = polynomial_default_category(base_ring.category(), n) + # Ring.__init__ assigns the names. Ring.__init__(self, base_ring, names, category=category) from sage.combinat.integer_vector import IntegerVectors self._indices = IntegerVectors(self._ngens) @@ -142,7 +139,7 @@ cdef class MPolynomialRing_base(CommutativeRing): Multivariate Polynomial Ring in x, y over Rational Field """ base = self.base_ring() - if isinstance(base, MPolynomialRing_base) or isinstance(base, polynomial_ring.PolynomialRing_general): + if isinstance(base, (MPolynomialRing_base, polynomial_ring.PolynomialRing_generic)): from sage.rings.polynomial.flatten import FlatteningMorphism return FlatteningMorphism(self) else: @@ -432,8 +429,8 @@ cdef class MPolynomialRing_base(CommutativeRing): Also, if the solution is not unique, it spits out one solution, without any notice that there are more. - Lastly, the interpolation function for univariate polynomial rings - is called :meth:`lagrange_polynomial`. + For interpolation in the univariate case use + :meth:`~sage.rings.polynomial.polynomial_ring.PolynomialRing_field.lagrange_polynomial`. .. WARNING:: @@ -453,7 +450,7 @@ cdef class MPolynomialRing_base(CommutativeRing): .. SEEALSO:: - :meth:`lagrange_polynomial` + :meth:`~sage.rings.polynomial.polynomial_ring.PolynomialRing_field.lagrange_polynomial` """ from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector @@ -602,7 +599,7 @@ cdef class MPolynomialRing_base(CommutativeRing): elif self.base_ring().has_coerce_map_from(P._mpoly_base_ring(self.variable_names())): return self(x) - elif isinstance(P, polynomial_ring.PolynomialRing_general): + elif isinstance(P, polynomial_ring.PolynomialRing_generic): if P.variable_name() in self.variable_names(): if self.has_coerce_map_from(P.base_ring()): return self(x) diff --git a/src/sage/rings/polynomial/multi_polynomial_sequence.py b/src/sage/rings/polynomial/multi_polynomial_sequence.py index db276a75c25..ca6f864f807 100644 --- a/src/sage/rings/polynomial/multi_polynomial_sequence.py +++ b/src/sage/rings/polynomial/multi_polynomial_sequence.py @@ -221,10 +221,7 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): - ``immutable`` -- if ``True`` the sequence is immutable (default: ``False``) - - ``cr`` -- print a line break after each element (default: ``False``) - - - ``cr_str`` -- print a line break after each element if 'str' is - called (default: ``None``) + - ``cr``, ``cr_str`` -- see :func:`~sage.structure.sequence.Sequence` EXAMPLES:: @@ -301,7 +298,7 @@ def PolynomialSequence(arg1, arg2=None, immutable=False, cr=False, cr_str=None): except ImportError: BooleanMonomialMonoid = () - is_ring = lambda r: isinstance(r, MPolynomialRing_base) or isinstance(r, BooleanMonomialMonoid) or (isinstance(r, QuotientRing_nc) and isinstance(r.cover_ring(), MPolynomialRing_base)) + is_ring = lambda r: isinstance(r, (MPolynomialRing_base, BooleanMonomialMonoid)) or (isinstance(r, QuotientRing_nc) and isinstance(r.cover_ring(), MPolynomialRing_base)) if is_ring(arg1): ring, gens = arg1, arg2 @@ -391,10 +388,7 @@ def __init__(self, parts, ring, immutable=False, cr=False, cr_str=None): - ``immutable`` -- if ``True`` the sequence is immutable (default: ``False``) - - ``cr`` -- print a line break after each element (default: ``False``) - - - ``cr_str`` -- print a line break after each element if 'str' - is called (default: ``None``) + - ``cr``, ``cr_str`` -- see :func:`~sage.structure.sequence.Sequence` EXAMPLES:: @@ -905,16 +899,23 @@ def _magma_init_(self, magma): v = [x._magma_init_(magma) for x in list(self)] return 'ideal<%s|%s>' % (P, ','.join(v)) + def _is_short_for_repr(self): + """ + Return whether this system is considered short for :meth:`_repr_`. + """ + return len(self) < 20 + def _repr_(self): """ Return a string representation of this system. + Typically, :meth:`_repr_pretty_` is used instead of this method. EXAMPLES:: sage: # needs sage.libs.singular sage: P. = PolynomialRing(GF(127)) sage: I = sage.rings.ideal.Katsura(P) - sage: F = Sequence(I); F # indirect doctest + sage: F = Sequence(I); print(F._repr_()) [a + 2*b + 2*c + 2*d - 1, a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, 2*a*b + 2*b*c + 2*c*d - b, @@ -927,11 +928,38 @@ def _repr_(self): sage: F,s = sr.polynomial_system(); F # needs sage.rings.polynomial.pbori Polynomial Sequence with 36 Polynomials in 20 Variables """ - if len(self) < 20: - return Sequence_generic._repr_(self) + if self._is_short_for_repr(): + return super()._repr_() else: return "Polynomial Sequence with %d Polynomials in %d Variables" % (len(self),self.nvariables()) + def _repr_pretty_(self, p, cycle): + """ + For pretty printing in the Sage command prompt. + + EXAMPLES:: + + sage: # needs sage.libs.singular + sage: P. = PolynomialRing(GF(127)) + sage: I = sage.rings.ideal.Katsura(P) + sage: F = Sequence(I); F # indirect doctest + [a + 2*b + 2*c + 2*d - 1, + a^2 + 2*b^2 + 2*c^2 + 2*d^2 - a, + 2*a*b + 2*b*c + 2*c*d - b, + b^2 + 2*a*c + 2*b*d - c] + + If the system contains 20 or more polynomials, a short summary + is printed:: + + sage: sr = mq.SR(allow_zero_inversions=True, gf2=True) # needs sage.rings.polynomial.pbori + sage: F,s = sr.polynomial_system(); F # needs sage.rings.polynomial.pbori + Polynomial Sequence with 36 Polynomials in 20 Variables + """ + if self._is_short_for_repr(): + super()._repr_pretty_(p, cycle) + else: + p.text(repr(self)) + def __add__(self, right): """ Add polynomial systems together, i.e. create a union of their diff --git a/src/sage/rings/polynomial/omega.py b/src/sage/rings/polynomial/omega.py index 797200f4e40..3877321d1d1 100644 --- a/src/sage/rings/polynomial/omega.py +++ b/src/sage/rings/polynomial/omega.py @@ -49,11 +49,12 @@ # https://www.gnu.org/licenses/ # **************************************************************************** import operator + from sage.misc.cachefunc import cached_function def MacMahonOmega(var, expression, denominator=None, op=operator.ge, - Factorization_sort=False, Factorization_simplify=True): + Factorization_sort=False, Factorization_simplify=True): r""" Return `\Omega_{\mathrm{op}}` of ``expression`` with respect to ``var``. @@ -221,33 +222,33 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, sage: MacMahonOmega(mu, 1, [1 - x*mu], op=operator.lt) Traceback (most recent call last): ... - NotImplementedError: At the moment, only Omega_ge is implemented. + NotImplementedError: only Omega_ge is implemented sage: MacMahonOmega(mu, 1, Factorization([(1 - x*mu, -1)])) Traceback (most recent call last): ... - ValueError: Factorization (-mu*x + 1)^-1 of the denominator - contains negative exponents. + ValueError: factorization (-mu*x + 1)^-1 of the denominator + contains negative exponents sage: MacMahonOmega(2*mu, 1, [1 - x*mu]) Traceback (most recent call last): ... - ValueError: 2*mu is not a variable. + ValueError: 2*mu is not a variable sage: MacMahonOmega(mu, 1, Factorization([(0, 2)])) Traceback (most recent call last): ... - ZeroDivisionError: Denominator contains a factor 0. + ZeroDivisionError: denominator contains a factor 0 sage: MacMahonOmega(mu, 1, [2 - x*mu]) Traceback (most recent call last): ... - NotImplementedError: Factor 2 - x*mu is not normalized. + NotImplementedError: factor 2 - x*mu is not normalized sage: MacMahonOmega(mu, 1, [1 - x*mu - mu^2]) Traceback (most recent call last): ... - NotImplementedError: Cannot handle factor 1 - x*mu - mu^2. + NotImplementedError: cannot handle factor 1 - x*mu - mu^2 :: @@ -259,12 +260,14 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, from sage.arith.misc import factor from sage.misc.misc_c import prod from sage.rings.integer_ring import ZZ - from sage.rings.polynomial.laurent_polynomial_ring \ - import LaurentPolynomialRing, LaurentPolynomialRing_univariate + from sage.rings.polynomial.laurent_polynomial_ring import ( + LaurentPolynomialRing, + LaurentPolynomialRing_univariate, + ) from sage.structure.factorization import Factorization if op != operator.ge: - raise NotImplementedError('At the moment, only Omega_ge is implemented.') + raise NotImplementedError('only Omega_ge is implemented') if denominator is None: if isinstance(expression, Factorization): @@ -285,9 +288,9 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, if not isinstance(denominator, Factorization): denominator = factor(denominator) if not denominator.is_integral(): - raise ValueError('Factorization {} of the denominator ' - 'contains negative exponents.'.format(denominator)) - numerator *= ZZ(1) / denominator.unit() + raise ValueError(f'factorization {denominator} of ' + 'the denominator contains negative exponents') + numerator *= ZZ.one() / denominator.unit() factors_denominator = tuple(factor for factor, exponent in denominator for _ in range(exponent)) @@ -304,30 +307,30 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, L = LaurentPolynomialRing(L0, var) var = L.gen() else: - raise ValueError('{} is not a variable.'.format(var)) + raise ValueError(f'{var} is not a variable') other_factors = [] to_numerator = [] decoded_factors = [] - for factor in factors_denominator: - factor = L(factor) - D = factor.monomial_coefficients() + for fact in factors_denominator: + fac = L(fact) + D = fac.monomial_coefficients() if not D: - raise ZeroDivisionError('Denominator contains a factor 0.') + raise ZeroDivisionError('denominator contains a factor 0') elif len(D) == 1: exponent, coefficient = next(iter(D.items())) if exponent == 0: - other_factors.append(L0(factor)) + other_factors.append(L0(fac)) else: - to_numerator.append(factor) + to_numerator.append(fac) elif len(D) == 2: if D.get(0, 0) != 1: - raise NotImplementedError('Factor {} is not normalized.'.format(factor)) + raise NotImplementedError(f'factor {fac} is not normalized') D.pop(0) exponent, coefficient = next(iter(D.items())) decoded_factors.append((-coefficient, exponent)) else: - raise NotImplementedError('Cannot handle factor {}.'.format(factor)) + raise NotImplementedError(f'cannot handle factor {fac}') numerator = L(numerator) / prod(to_numerator) result_numerator, result_factors_denominator = \ @@ -336,13 +339,13 @@ def MacMahonOmega(var, expression, denominator=None, op=operator.ge, return Factorization([], unit=result_numerator) return Factorization([(result_numerator, 1)] + - list((f, -1) for f in other_factors) + - list((1-f, -1) for f in result_factors_denominator), + [(f, -1) for f in other_factors] + + [(1 - f, -1) for f in result_factors_denominator], sort=Factorization_sort, simplify=Factorization_simplify) -def _simplify_(numerator, terms): +def _simplify_(numerator, terms) -> tuple: r""" Cancels common factors of numerator and denominator. @@ -438,7 +441,7 @@ def _Omega_(A, decoded_factors): (x + 1) * (-x*y + 1)^-1 """ if not decoded_factors: - return sum(c for a, c in A.items() if a >= 0), tuple() + return sum(c for a, c in A.items() if a >= 0), () # Below we sort to make the caching more efficient. Doing this here # (in contrast to directly in Omega_ge) results in much cleaner @@ -459,7 +462,7 @@ def _Omega_(A, decoded_factors): numerator += c * n.subs(rules) if numerator == 0: - factors_denominator = tuple() + factors_denominator = () return _simplify_(numerator, tuple(f.subs(rules) for f in factors_denominator)) @@ -557,19 +560,18 @@ def Omega_ge(a, exponents): logger.info('Omega_ge: a=%s, exponents=%s', a, exponents) from sage.arith.functions import lcm - from sage.arith.srange import srange from sage.rings.integer_ring import ZZ - from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing from sage.rings.number_field.number_field import CyclotomicField + from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing if not exponents or any(e == 0 for e in exponents): raise NotImplementedError - rou = sorted(set(abs(e) for e in exponents) - set([1])) + rou = sorted({abse for e in exponents if (abse := abs(e)) != 1}) ellcm = lcm(rou) B = CyclotomicField(ellcm, 'zeta') zeta = B.gen() - z_names = tuple('z{}'.format(i) for i in range(len(exponents))) + z_names = tuple(f'z{i}' for i in range(len(exponents))) L = LaurentPolynomialRing(B, ('t',) + z_names, len(z_names) + 1) t = L.gens()[0] Z = LaurentPolynomialRing(ZZ, z_names, len(z_names)) @@ -577,7 +579,7 @@ def Omega_ge(a, exponents): powers[2] = L(-1) powers[1] = L(1) exponents_and_values = tuple( - (e, tuple(powers[abs(e)]**j * z for j in srange(abs(e)))) + (e, tuple(powers[abs(e)]**j * z for j in range(abs(e)))) for z, e in zip(L.gens()[1:], exponents)) x = tuple(v for e, v in exponents_and_values if e > 0) y = tuple(v for e, v in exponents_and_values if e < 0) @@ -597,9 +599,8 @@ def subs_e(e): e[p] = e[p] // exponent return tuple(e) parent = expression.parent() - result = parent({subs_e(e): c - for e, c in expression.monomial_coefficients().items()}) - return result + return parent({subs_e(e): c + for e, c in expression.monomial_coefficients().items()}) def de_power(expression): expression = Z(expression) @@ -719,8 +720,8 @@ def _Omega_numerator_(a, x, y, t): from sage.arith.srange import srange from sage.misc.misc_c import prod - x_flat = sum(x, tuple()) - y_flat = sum(y, tuple()) + x_flat = sum(x, ()) + y_flat = sum(y, ()) n = len(x_flat) m = len(y_flat) xy = x_flat + y_flat @@ -807,12 +808,13 @@ def _Omega_numerator_P_(a, x, y, t): p2 = Pprev.subs({t: x2}) logger.debug('Omega_numerator: P(%s): preparing...', n) dividend = x1 * (1-x2) * prod(1 - x2*yy for yy in y) * p1 - \ - x2 * (1-x1) * prod(1 - x1*yy for yy in y) * p2 + x2 * (1-x1) * prod(1 - x1*yy for yy in y) * p2 logger.debug('Omega_numerator: P(%s): dividing...', n) q, r = dividend.quo_rem(x1 - x2) assert r == 0 result = q - logger.debug('Omega_numerator: P(%s) has %s terms', n, result.number_of_terms()) + logger.debug('Omega_numerator: P(%s) has %s terms', n, + result.number_of_terms()) return result @@ -900,11 +902,11 @@ def _Omega_factors_denominator_(x, y): from sage.misc.misc_c import prod result = tuple(prod(1 - xx for xx in gx) for gx in x) + \ - sum(((prod(1 - xx*yy for xx in gx for yy in gy),) - if len(gx) != len(gy) - else tuple(prod(1 - xx*yy for xx in gx) for yy in gy) - for gx in x for gy in y), - tuple()) + sum(((prod(1 - xx*yy for xx in gx for yy in gy),) + if len(gx) != len(gy) + else tuple(prod(1 - xx*yy for xx in gx) for yy in gy) + for gx in x for gy in y), + ()) logger.info('Omega_denominator: %s factors', len(result)) return result diff --git a/src/sage/rings/polynomial/ore_function_element.py b/src/sage/rings/polynomial/ore_function_element.py index d858838f53c..a97eb60d268 100644 --- a/src/sage/rings/polynomial/ore_function_element.py +++ b/src/sage/rings/polynomial/ore_function_element.py @@ -16,14 +16,13 @@ # https://www.gnu.org/licenses/ # *************************************************************************** -from sage.structure.richcmp import richcmp, op_EQ, op_NE -from sage.misc.cachefunc import cached_method -from sage.misc.latex import latex - +from sage.categories.homset import Hom from sage.categories.map import Map from sage.categories.morphism import Morphism -from sage.categories.homset import Hom +from sage.misc.cachefunc import cached_method +from sage.misc.latex import latex from sage.structure.element import AlgebraElement +from sage.structure.richcmp import op_EQ, op_NE, richcmp class OreFunction(AlgebraElement): diff --git a/src/sage/rings/polynomial/ore_function_field.py b/src/sage/rings/polynomial/ore_function_field.py index 1c78217508b..4b509688450 100644 --- a/src/sage/rings/polynomial/ore_function_field.py +++ b/src/sage/rings/polynomial/ore_function_field.py @@ -128,6 +128,23 @@ sage: g^(-1) * f (d - 1/t)^(-1) * (d + (t^2 - 1)/t) +TESTS: + +The Ore function field is commutative if the twisting morphism is the +identity and the twisting derivation vanishes. :: + + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: K = S.fraction_field() + sage: K.is_commutative() + False + sage: T. = k['y', Frob^3] + sage: L = T.fraction_field() + sage: L.is_commutative() + True + AUTHOR: - Xavier Caruso (2020-05) @@ -144,21 +161,21 @@ # https://www.gnu.org/licenses/ # *************************************************************************** -import sage - -from sage.structure.richcmp import op_EQ -from sage.structure.category_object import normalize_names -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent from sage.categories.algebras import Algebras +from sage.categories.commutative_rings import CommutativeRings from sage.categories.fields import Fields - -from sage.rings.morphism import RingHomomorphism from sage.categories.homset import Hom from sage.categories.map import Section - +from sage.rings.morphism import RingHomomorphism +from sage.rings.polynomial.ore_function_element import ( + OreFunction_with_large_center, + OreFunctionBaseringInjection, +) from sage.rings.polynomial.ore_polynomial_ring import OrePolynomialRing -from sage.rings.polynomial.ore_function_element import OreFunctionBaseringInjection +from sage.structure.category_object import normalize_names +from sage.structure.parent import Parent +from sage.structure.richcmp import op_EQ +from sage.structure.unique_representation import UniqueRepresentation WORKING_CENTER_MAX_TRIES = 1000 @@ -200,7 +217,10 @@ def __init__(self, ring, category=None): self._simplification = False self._ring = ring base = ring.base_ring() - category = Algebras(base).or_subcategory(category) + if ring in CommutativeRings(): + category = Algebras(base).Commutative().or_subcategory(category) + else: + category = Algebras(base).or_subcategory(category) Parent.__init__(self, base=base, names=ring.variable_name(), normalize=True, category=category) @@ -614,27 +634,6 @@ def random_element(self, degree=2, monic=False, *args, **kwds): denominator = self._ring.random_element(degdenom, True, *args, **kwds) return self(numerator, denominator) - def is_commutative(self) -> bool: - r""" - Return ``True`` if this Ore function field is commutative, i.e. if the - twisting morphism is the identity and the twisting derivation vanishes. - - EXAMPLES:: - - sage: # needs sage.rings.finite_rings - sage: k. = GF(5^3) - sage: Frob = k.frobenius_endomorphism() - sage: S. = k['x', Frob] - sage: K = S.fraction_field() - sage: K.is_commutative() - False - sage: T. = k['y', Frob^3] - sage: L = T.fraction_field() - sage: L.is_commutative() - True - """ - return self._ring.is_commutative() - def is_field(self, proof=False) -> bool: r""" Return always ``True`` since Ore function field are (skew) fields. @@ -892,7 +891,7 @@ def __init__(self, ring, category=None): sage: TestSuite(K).run() """ if self.Element is None: - self.Element = sage.rings.polynomial.ore_function_element.OreFunction_with_large_center + self.Element = OreFunction_with_large_center OreFunctionField.__init__(self, ring, category) self._center = {} self._center_variable_name = 'z' diff --git a/src/sage/rings/polynomial/ore_polynomial_ring.py b/src/sage/rings/polynomial/ore_polynomial_ring.py index f28b90ad198..7866221cfad 100644 --- a/src/sage/rings/polynomial/ore_polynomial_ring.py +++ b/src/sage/rings/polynomial/ore_polynomial_ring.py @@ -7,6 +7,30 @@ which constructs a general dense univariate Ore polynomial ring over a commutative base with equipped with an endomorphism and/or a derivation. +TESTS: + +The Ore polynomial ring is commutative if the twisting morphism is the +identity and the twisting derivation vanishes. :: + + sage: # needs sage.rings.finite_rings + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: S.is_commutative() + False + sage: T. = k['y', Frob^3] + sage: T.is_commutative() + True + + sage: R. = GF(5)[] + sage: der = R.derivation() + sage: A. = R['d', der] + sage: A.is_commutative() + False + sage: B. = R['b', 5*der] + sage: B.is_commutative() + True + AUTHOR: - Xavier Caruso (2020-04) @@ -21,25 +45,21 @@ # https://www.gnu.org/licenses/ # *************************************************************************** -from sage.misc.prandom import randint +from sage.categories.algebras import Algebras +from sage.categories.commutative_rings import CommutativeRings +from sage.categories.morphism import Morphism from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import +from sage.misc.prandom import randint from sage.rings.infinity import Infinity +from sage.rings.integer import Integer +from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.ring import _Fields from sage.structure.category_object import normalize_names +from sage.structure.element import Element from sage.structure.parent import Parent - from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.integer import Integer -from sage.structure.element import Element - -from sage.categories.commutative_rings import CommutativeRings -from sage.categories.algebras import Algebras -from sage.rings.ring import _Fields - -from sage.categories.morphism import Morphism - -from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing -from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection lazy_import('sage.rings.derivation', 'RingDerivation') @@ -421,7 +441,11 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) self._morphism = morphism self._derivation = derivation self._fraction_field = None - category = Algebras(base_ring).or_subcategory(category) + if morphism is None and derivation is None: + cat = Algebras(base_ring).Commutative() + else: + cat = Algebras(base_ring) + category = cat.or_subcategory(category) Parent.__init__(self, base_ring, names=name, normalize=True, category=category) @@ -506,7 +530,7 @@ def build(check): pass if isinstance(a, str): try: - from sage.misc.parser import Parser, LookupNameMaker + from sage.misc.parser import LookupNameMaker, Parser R = self.base_ring() p = Parser(Integer, R, LookupNameMaker({self.variable_name(): self.gen()}, R)) return self(p.parse(a)) @@ -1095,36 +1119,6 @@ def random_irreducible(self, degree=2, monic=True, *args, **kwds): if irred.is_irreducible(): return irred - def is_commutative(self) -> bool: - r""" - Return ``True`` if this Ore polynomial ring is commutative. - - This holds if the twisting morphism is the identity and the - twisting derivation vanishes. - - EXAMPLES:: - - sage: # needs sage.rings.finite_rings - sage: k. = GF(5^3) - sage: Frob = k.frobenius_endomorphism() - sage: S. = k['x', Frob] - sage: S.is_commutative() - False - sage: T. = k['y', Frob^3] - sage: T.is_commutative() - True - - sage: R. = GF(5)[] - sage: der = R.derivation() - sage: A. = R['d', der] - sage: A.is_commutative() - False - sage: B. = R['b', 5*der] - sage: B.is_commutative() - True - """ - return self._morphism is None and self._derivation is None - def is_field(self, proof=False) -> bool: r""" Return always ``False`` since Ore polynomial rings are never fields. diff --git a/src/sage/rings/polynomial/pbori/pbori.pyx b/src/sage/rings/polynomial/pbori/pbori.pyx index 686edf8892d..14a929c3238 100644 --- a/src/sage/rings/polynomial/pbori/pbori.pyx +++ b/src/sage/rings/polynomial/pbori/pbori.pyx @@ -194,7 +194,7 @@ from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF from sage.rings.polynomial.polynomial_element cimport Polynomial from sage.rings.polynomial.multi_polynomial_ideal import MPolynomialIdeal from sage.rings.polynomial.term_order import TermOrder -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.ideal import FieldIdeal @@ -674,7 +674,7 @@ cdef class BooleanPolynomialRing(BooleanPolynomialRing_base): """ if self._base.has_coerce_map_from(S): return True - if isinstance(S, (MPolynomialRing_base, PolynomialRing_general, + if isinstance(S, (MPolynomialRing_base, PolynomialRing_generic, BooleanMonomialMonoid)): try: get_var_mapping(self, S) diff --git a/src/sage/rings/polynomial/polynomial_element.pxd b/src/sage/rings/polynomial/polynomial_element.pxd index a8f2cf3057b..45e64ce6744 100644 --- a/src/sage/rings/polynomial/polynomial_element.pxd +++ b/src/sage/rings/polynomial/polynomial_element.pxd @@ -61,4 +61,3 @@ cpdef Polynomial generic_power_trunc(Polynomial p, Integer n, long prec) cpdef list _dict_to_list(dict x, zero) cpdef bint polynomial_is_variable(x) noexcept - diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index feb0ef1b03b..b8445edeb20 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -118,7 +118,7 @@ from sage.arith.functions import lcm from sage.rings.polynomial import polynomial_fateman from sage.rings.ideal import Ideal_generic -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base from sage.rings.polynomial.multi_polynomial cimport MPolynomial from sage.rings.polynomial.polynomial_quotient_ring_element import PolynomialQuotientRingElement @@ -2280,7 +2280,7 @@ cdef class Polynomial(CommutativePolynomial): - ``degree`` -- ``None`` or positive integer (default: ``None``). Used for polynomials over finite fields. If ``None``, returns - the the first factor found (usually the smallest). Otherwise, + the first factor found (usually the smallest). Otherwise, attempts to return an irreducible factor of ``self`` of chosen degree ``degree``. @@ -4461,7 +4461,7 @@ cdef class Polynomial(CommutativePolynomial): if self.get_unsafe(n) else zero for n in range(self.degree() + 1)] return S(p) - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return a sparse dictionary representation of this univariate polynomial. @@ -7522,7 +7522,7 @@ cdef class Polynomial(CommutativePolynomial): raise TypeError("p2 must be a polynomial") p1, p2 = coercion_model.canonical_coercion(p1, p2) K = p1.parent() - assert isinstance(p1.parent(), PolynomialRing_general) + assert isinstance(p1.parent(), PolynomialRing_generic) S = K.base_ring() Sf = S.fraction_field() @@ -10038,7 +10038,7 @@ cdef class Polynomial(CommutativePolynomial): sage: f.is_irreducible() True - If the base ring implements `_is_irreducible_univariate_polynomial`, + If the base ring implements ``_is_irreducible_univariate_polynomial``, then this method gets used instead of the generic algorithm which just factors the input:: @@ -10285,7 +10285,7 @@ cdef class Polynomial(CommutativePolynomial): sage: f.is_squarefree.cache False - If the base ring implements `_is_squarefree_univariate_polynomial`, + If the base ring implements ``_is_squarefree_univariate_polynomial``, then this method gets used instead of the generic algorithm in :meth:`_is_squarefree_generic`:: @@ -11022,11 +11022,10 @@ cdef class Polynomial(CommutativePolynomial): x, = self.variables() - if isinstance(var, int) or isinstance(var, Integer): + if isinstance(var, (int, Integer)): if var: raise TypeError("Variable index %d must be < 1." % var) - else: - return sum(self.coefficients())*x**self.degree() + return sum(self.coefficients()) * x**self.degree() x_name = self.variable_name() var = str(var) diff --git a/src/sage/rings/polynomial/polynomial_element_generic.py b/src/sage/rings/polynomial/polynomial_element_generic.py index 7bbd4e611a9..db8139bddad 100644 --- a/src/sage/rings/polynomial/polynomial_element_generic.py +++ b/src/sage/rings/polynomial/polynomial_element_generic.py @@ -128,7 +128,7 @@ def __init__(self, parent, x=None, check=True, is_gen=False, construct=False): if check: self.__normalize() - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return a new copy of the dict of the underlying elements of ``self``. diff --git a/src/sage/rings/polynomial/polynomial_gf2x.pxd b/src/sage/rings/polynomial/polynomial_gf2x.pxd index 293715c0379..3a27019f77c 100644 --- a/src/sage/rings/polynomial/polynomial_gf2x.pxd +++ b/src/sage/rings/polynomial/polynomial_gf2x.pxd @@ -7,4 +7,3 @@ include "polynomial_template_header.pxi" cdef class Polynomial_GF2X(Polynomial_template): pass - diff --git a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx index 68605382f1f..c1a5474adf2 100644 --- a/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx +++ b/src/sage/rings/polynomial/polynomial_modn_dense_ntl.pyx @@ -656,7 +656,7 @@ def small_roots(self, X=None, beta=1.0, epsilon=None, **kwds): for j in range( g[i].degree()+1 ): B[i,j] = g[i][j]*X**j - B = B.LLL(**kwds) + B = B.LLL(**kwds) f = sum([ZZ(B[0,i]//X**i)*x**i for i in range(B.ncols())]) R = f.roots() @@ -1848,7 +1848,7 @@ cdef class Polynomial_dense_modn_ntl_ZZ(Polynomial_dense_mod_n): return Polynomial.__call__(self, *args, **kwds) arg = args[0] cdef ntl_ZZ_p fx = ntl_ZZ_p(0, self.c), x = None - if isinstance(arg, int) or isinstance(arg, Integer): + if isinstance(arg, (int, Integer)): x = ntl_ZZ_p(arg, self.c) elif isinstance(arg, Element): if self._parent._base == (arg)._parent: # c++ pointer hack diff --git a/src/sage/rings/polynomial/polynomial_quotient_ring.py b/src/sage/rings/polynomial/polynomial_quotient_ring.py index 9851c477abf..115647adadf 100644 --- a/src/sage/rings/polynomial/polynomial_quotient_ring.py +++ b/src/sage/rings/polynomial/polynomial_quotient_ring.py @@ -34,7 +34,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/ #***************************************************************************** @@ -42,7 +42,7 @@ import sage.rings.rational_field from sage.arith.misc import crt -from sage.rings.ring import Field, IntegralDomain, CommutativeRing +from sage.rings.ring import Field, CommutativeRing from sage.misc.cachefunc import cached_method from sage.rings.polynomial.polynomial_quotient_ring_element import PolynomialQuotientRingElement @@ -383,7 +383,7 @@ class of the category, and store the current class of the quotient 1 The test suite passes. However, we have to skip the test for its elements, - since `an_element` has been cached in the call above and its class does not + since ``an_element`` has been cached in the call above and its class does not match the new category's element class anymore:: sage: TestSuite(Q).run(skip=['_test_elements']) # needs sage.rings.number_field @@ -2277,7 +2277,7 @@ def _richcmp_(self, other, op): return richcmp(self.parent(), other.parent(), op) -class PolynomialQuotientRing_domain(PolynomialQuotientRing_generic, IntegralDomain): +class PolynomialQuotientRing_domain(PolynomialQuotientRing_generic, CommutativeRing): """ EXAMPLES:: diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pxd b/src/sage/rings/polynomial/polynomial_rational_flint.pxd index f4644f19d04..fab8ac5463c 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pxd +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pxd @@ -17,4 +17,3 @@ cdef class Polynomial_rational_flint(Polynomial): cpdef _mod_(self, right) cpdef _unsafe_mutate(self, unsigned long n, value) cpdef Polynomial truncate(self, long n) - diff --git a/src/sage/rings/polynomial/polynomial_rational_flint.pyx b/src/sage/rings/polynomial/polynomial_rational_flint.pyx index c11592cf2d6..979877606a7 100644 --- a/src/sage/rings/polynomial/polynomial_rational_flint.pyx +++ b/src/sage/rings/polynomial/polynomial_rational_flint.pyx @@ -236,7 +236,7 @@ cdef class Polynomial_rational_flint(Polynomial): elif isinstance(x, Rational): fmpq_poly_set_mpq(self._poly, ( x).value) - elif isinstance(x, list) or isinstance(x, tuple): + elif isinstance(x, (list, tuple)): if len(x) == 0: return diff --git a/src/sage/rings/polynomial/polynomial_ring.py b/src/sage/rings/polynomial/polynomial_ring.py index 0ab8074ec1e..82d8eae3361 100644 --- a/src/sage/rings/polynomial/polynomial_ring.py +++ b/src/sage/rings/polynomial/polynomial_ring.py @@ -141,6 +141,7 @@ import sys +from sage.misc.superseded import deprecation from sage.structure.element import Element from sage.structure.category_object import check_default_category @@ -149,7 +150,7 @@ from sage.categories.principal_ideal_domains import PrincipalIdealDomains from sage.categories.rings import Rings -from sage.rings.ring import (Ring, IntegralDomain) +from sage.rings.ring import Ring, CommutativeRing from sage.structure.element import RingElement import sage.rings.rational_field as rational_field from sage.rings.rational_field import QQ @@ -193,7 +194,7 @@ def is_PolynomialRing(x): sage: is_PolynomialRing(2) doctest:warning... DeprecationWarning: The function is_PolynomialRing is deprecated; - use 'isinstance(..., PolynomialRing_general)' instead. + use 'isinstance(..., PolynomialRing_generic)' instead. See https://github.com/sagemath/sage/issues/38266 for details. False @@ -229,16 +230,15 @@ def is_PolynomialRing(x): sage: type(R) """ - from sage.misc.superseded import deprecation deprecation(38266, "The function is_PolynomialRing is deprecated; " - "use 'isinstance(..., PolynomialRing_general)' instead.") - return isinstance(x, PolynomialRing_general) + "use 'isinstance(..., PolynomialRing_generic)' instead.") + return isinstance(x, PolynomialRing_generic) ######################################################################################### -class PolynomialRing_general(Ring): +class PolynomialRing_generic(Ring): """ Univariate polynomial ring over a ring. """ @@ -289,7 +289,7 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, sage: PolynomialRing(Zmod(1), 'x').category() Category of finite commutative rings - Check `is_finite` inherited from category (:issue:`24432`):: + Check ``is_finite`` inherited from category (:issue:`24432`):: sage: Zmod(1)['x'].is_finite() True @@ -534,12 +534,12 @@ def _implementation_names(cls, implementation, base_ring, sparse=False): EXAMPLES:: - sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - sage: PolynomialRing_general._implementation_names(None, ZZ, True) + sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + sage: PolynomialRing_generic._implementation_names(None, ZZ, True) [None, 'generic'] - sage: PolynomialRing_general._implementation_names("generic", ZZ, True) + sage: PolynomialRing_generic._implementation_names("generic", ZZ, True) [None, 'generic'] - sage: PolynomialRing_general._implementation_names("xyzzy", ZZ, True) + sage: PolynomialRing_generic._implementation_names("xyzzy", ZZ, True) Traceback (most recent call last): ... ValueError: unknown implementation 'xyzzy' for sparse polynomial rings over Integer Ring @@ -563,8 +563,8 @@ def _implementation_names_impl(implementation, base_ring, sparse): EXAMPLES:: - sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - sage: PolynomialRing_general._implementation_names_impl("xyzzy", ZZ, True) + sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + sage: PolynomialRing_generic._implementation_names_impl("xyzzy", ZZ, True) NotImplemented """ if implementation is None or implementation == "generic": @@ -642,7 +642,7 @@ def flattening_morphism(self): """ from .multi_polynomial_ring import MPolynomialRing_base base = self.base_ring() - if isinstance(base, PolynomialRing_general) or isinstance(base, MPolynomialRing_base): + if isinstance(base, (PolynomialRing_generic, MPolynomialRing_base)): from .flatten import FlatteningMorphism return FlatteningMorphism(self) else: @@ -827,7 +827,7 @@ def _coerce_map_from_(self, P): # polynomial rings in the same variable over a base that canonically # coerces into self.base_ring() - if isinstance(P, PolynomialRing_general): + if isinstance(P, PolynomialRing_generic): if self.construction()[0] != P.construction()[0]: # Construction (including variable names) must be the # same to allow coercion @@ -1262,7 +1262,7 @@ def gen(self, n=0): raise IndexError("generator n not defined") return self.element_class(self, [0,1], is_gen=True) - def gens_dict(self): + def gens_dict(self) -> dict: """ Return a dictionary whose entries are ``{name:variable,...}``, where ``name`` stands for the variable names of this @@ -1590,7 +1590,7 @@ def _polys_degree(self, of_degree): coeffs.reverse() yield self(coeffs) - def _polys_max( self, max_degree ): + def _polys_max(self, max_degree): """ Refer to polynomials() for full documentation. """ @@ -1617,7 +1617,7 @@ def _Karatsuba_threshold(self): 0 """ base_ring = self.base_ring() - if isinstance(base_ring, PolynomialRing_general): + if isinstance(base_ring, PolynomialRing_generic): return 0 try: from sage.matrix.matrix_space import MatrixSpace @@ -1669,7 +1669,7 @@ def set_karatsuba_threshold(self, Karatsuba_threshold): """ self._Karatsuba_threshold = int(Karatsuba_threshold) - def polynomials( self, of_degree=None, max_degree=None ): + def polynomials(self, of_degree=None, max_degree=None): """ Return an iterator over the polynomials of specified degree. @@ -1733,7 +1733,7 @@ def polynomials( self, of_degree=None, max_degree=None ): return self._polys_max( max_degree ) raise ValueError("you should pass exactly one of of_degree and max_degree") - def monics( self, of_degree=None, max_degree=None ): + def monics(self, of_degree=None, max_degree=None): """ Return an iterator over the monic polynomials of specified degree. @@ -1794,7 +1794,11 @@ def monics( self, of_degree=None, max_degree=None ): raise ValueError("you should pass exactly one of of_degree and max_degree") -class PolynomialRing_commutative(PolynomialRing_general): +# PolynomialRing_general is deprecated since 2024-12-03. See Issue #38207. +PolynomialRing_general = PolynomialRing_generic + + +class PolynomialRing_commutative(PolynomialRing_generic): """ Univariate polynomial ring over a commutative ring. """ @@ -1808,7 +1812,7 @@ def __init__(self, base_ring, name=None, sparse=False, implementation=None, else: defaultcat = polynomial_default_category(base_ring.category(), 1) category = check_default_category(defaultcat, category) - PolynomialRing_general.__init__(self, base_ring, name=name, + PolynomialRing_generic.__init__(self, base_ring, name=name, sparse=sparse, implementation=implementation, element_class=element_class, category=category) @@ -1923,8 +1927,7 @@ def _roots_univariate_polynomial(self, p, ring=None, multiplicities=True, algori return roots -class PolynomialRing_integral_domain(PolynomialRing_commutative, PolynomialRing_singular_repr, - IntegralDomain): +class PolynomialRing_integral_domain(PolynomialRing_commutative, PolynomialRing_singular_repr, CommutativeRing): def __init__(self, base_ring, name='x', sparse=False, implementation=None, element_class=None, category=None): """ diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index 5cbc74dd1d5..78074c8a1d2 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -798,7 +798,7 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non from sage.rings.semirings.tropical_polynomial import TropicalPolynomialSemiring constructor = TropicalPolynomialSemiring elif base_ring not in _CommutativeRings: - constructor = polynomial_ring.PolynomialRing_general + constructor = polynomial_ring.PolynomialRing_generic elif base_ring in _CompleteDiscreteValuationRings: constructor = polynomial_ring.PolynomialRing_cdvr elif base_ring in _CompleteDiscreteValuationFields: diff --git a/src/sage/rings/polynomial/polynomial_singular_interface.py b/src/sage/rings/polynomial/polynomial_singular_interface.py index 1bdca3af614..60d2dd74b52 100644 --- a/src/sage/rings/polynomial/polynomial_singular_interface.py +++ b/src/sage/rings/polynomial/polynomial_singular_interface.py @@ -430,8 +430,8 @@ def can_convert_to_singular(R): base_ring = R.base_ring() if (base_ring is ZZ - or isinstance(base_ring, RationalField) - or isinstance(base_ring, (sage.rings.abc.IntegerModRing, + or isinstance(base_ring, (RationalField, + sage.rings.abc.IntegerModRing, sage.rings.abc.RealField, sage.rings.abc.ComplexField, sage.rings.abc.RealDoubleField, sage.rings.abc.ComplexDoubleField))): return True diff --git a/src/sage/rings/polynomial/polynomial_template.pxi b/src/sage/rings/polynomial/polynomial_template.pxi index b76d62a9e92..35c260e67ea 100644 --- a/src/sage/rings/polynomial/polynomial_template.pxi +++ b/src/sage/rings/polynomial/polynomial_template.pxi @@ -117,16 +117,16 @@ cdef class Polynomial_template(Polynomial): celement_construct(&self.x, (self)._cparent) celement_set(&self.x, &(x).x, (self)._cparent) except NotImplementedError: - raise TypeError("%s not understood."%x) + raise TypeError("%s not understood." % x) - elif isinstance(x, int) or isinstance(x, Integer): + elif isinstance(x, (int, Integer)): try: celement_construct(&self.x, (self)._cparent) celement_set_si(&self.x, int(x), (self)._cparent) except NotImplementedError: raise TypeError("%s not understood."%x) - elif isinstance(x, list) or isinstance(x, tuple): + elif isinstance(x, (list, tuple)): celement_construct(&self.x, (self)._cparent) gen = celement_new((self)._cparent) monomial = celement_new((self)._cparent) @@ -629,7 +629,7 @@ cdef class Polynomial_template(Polynomial): 0 """ if not isinstance(self, Polynomial_template): - raise NotImplementedError("%s^%s not defined."%(ee,self)) + raise NotImplementedError("%s^%s not defined." % (ee, self)) cdef bint recip = 0, do_sig cdef long e diff --git a/src/sage/rings/polynomial/q_integer_valued_polynomials.py b/src/sage/rings/polynomial/q_integer_valued_polynomials.py new file mode 100644 index 00000000000..fdcca6d5fff --- /dev/null +++ b/src/sage/rings/polynomial/q_integer_valued_polynomials.py @@ -0,0 +1,1263 @@ +r""" +Quantum-valued polynomial rings + +This provides a `q`-analogue of the :class:`~sage.rings.polynomials.integer_valued_polynomials.IntegerValuedPolynomialRing`. + +AUTHORS: + +- Frédéric Chapoton (2024-03): Initial version +""" +# **************************************************************************** +# Copyright (C) 2024 Frédéric Chapoton +# +# 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.arith.misc import binomial +from sage.categories.algebras import Algebras +from sage.categories.realizations import Category_realization_of_parent +from sage.categories.rings import Rings +from sage.combinat.free_module import CombinatorialFreeModule +from sage.combinat.q_analogues import q_binomial, q_int +from sage.data_structures.blas_dict import linear_combination +from sage.matrix.constructor import matrix +from sage.misc.bindable_class import BindableClass +from sage.misc.cachefunc import cached_method +from sage.modules.free_module_element import vector +from sage.rings.integer_ring import ZZ +from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing +from sage.rings.polynomial.polynomial_ring import polygen +from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing +from sage.rings.rational_field import QQ +from sage.sets.family import Family +from sage.sets.non_negative_integers import NonNegativeIntegers +from sage.structure.element import parent +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation + + +def q_int_x(n, q=None): + """ + Return the interpolating polynomial of `q`-integers. + + INPUT: + + - ``n`` -- a positive integer + + - ``q`` -- optional variable + + EXAMPLES:: + + sage: from sage.rings.polynomial.q_integer_valued_polynomials import q_int_x + sage: q_int_x(3) + q^2*x + q + 1 + + TESTS:: + + sage: from sage.rings.polynomial.q_integer_valued_polynomials import q_int_x + sage: q_int_x(3, 1) + x + 2 + """ + if q is None: + ring_q = PolynomialRing(ZZ, 'q') + q = ring_q.gen() + else: + ring_q = q.parent() + x = polygen(ring_q, 'x') + return q_int(n - 1, q) + q**(n - 1) * x + + +def q_binomial_x(m, n, q=None): + r""" + Return a `q`-analogue of ``binomial(m + x, n)``. + + When evaluated at the `q`-integer `[k]_q`, this gives + the usual `q`-binomial coefficient `[m + k, n]_q`. + + INPUT: + + - ``m`` and ``n`` -- positive integers + + - ``q`` -- optional variable + + EXAMPLES:: + + sage: from sage.combinat.q_analogues import q_int + sage: from sage.rings.polynomial.q_integer_valued_polynomials import q_binomial_x, q_int_x + sage: q_binomial_x(4,2)(0) == q_binomial(4,2) + True + sage: q_binomial_x(3,2)(1) == q_binomial(4,2) + True + sage: q_binomial_x(3,1) == q_int_x(4) + True + sage: q_binomial_x(2,0).parent() + Univariate Polynomial Ring in x over Fraction Field of + Univariate Polynomial Ring in q over Integer Ring + + TESTS:: + + sage: from sage.rings.polynomial.q_integer_valued_polynomials import q_binomial_x + sage: q_binomial_x(4,2,1) + 1/2*x^2 + 7/2*x + 6 + """ + if q is None: + ring_q = PolynomialRing(ZZ, 'q') + else: + ring_q = q.parent() + ring = PolynomialRing(ring_q.fraction_field(), 'x') + if n == 0: + return ring.one() + return ring.prod(q_int_x(m + 2 - i, q) / q_int(i, q) + for i in range(1, n + 1)) + + +class QuantumValuedPolynomialRing(UniqueRepresentation, Parent): + r""" + The quantum-valued polynomial ring over a base ring. + + Quantum-valued polynomial rings are commutative and associative + algebras, with a basis indexed by nonnegative integers. + + The elements are polynomials in one variable `x` with coefficients in + the field of rational functions in `q`, such that the value at + every nonegative `q`-integer is a polynomial in `q`. + + This algebra is endowed with two bases, named ``B`` or ``Binomial`` + and ``S`` or ``Shifted``. + + INPUT: + + - ``R`` -- commutative ring + + - ``q`` -- optional variable + + There are two possible input formats: + + - If the argument ``q`` is not given, then the ring ``R`` is + taken as a base ring and the ring of Laurent polynomials in `q` + over ``R`` is built and used. + + - If the argument ``q`` is given, then it should belong to the ring ``R`` + and be invertible in this ring. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ).S(); F + Quantum-Valued Polynomial Ring over Rational Field + in the shifted basis + + sage: F.gen() + S[1] + + sage: S = QuantumValuedPolynomialRing(ZZ); S + Quantum-Valued Polynomial Ring over Integer Ring + sage: S.base_ring() + Univariate Laurent Polynomial Ring in q over Integer Ring + + Quantum-valued polynomial rings commute with their base ring:: + + sage: K = QuantumValuedPolynomialRing(QQ).S() + sage: a = K.gen() + sage: c = K.monomial(2) + + Quantum-valued polynomial rings are commutative:: + + sage: c^3 * a == c * a * c * c + True + + We can also manipulate elements in the basis and coerce elements from our + base field:: + + sage: F = QuantumValuedPolynomialRing(QQ).S() + sage: B = F.basis() + sage: B[2] * B[3] + (q^-5+q^-4+q^-3)*S[3] - (q^-6+2*q^-5+3*q^-4+3*q^-3+2*q^-2+q^-1)*S[4] + + (q^-6+q^-5+2*q^-4+2*q^-3+2*q^-2+q^-1+1)*S[5] + sage: 1 - B[2] * B[2] / 2 + S[0] - (1/2*q^-3)*S[2] + (1/2*q^-4+q^-3+q^-2+1/2*q^-1)*S[3] + - (1/2*q^-4+1/2*q^-3+q^-2+1/2*q^-1+1/2)*S[4] + """ + @staticmethod + def __classcall_private__(cls, R, q=None) -> None: + """ + Normalize the input. + + EXAMPLES:: + + sage: q = LaurentPolynomialRing(QQ, 'q').gen() + sage: F1 = QuantumValuedPolynomialRing(QQ) + sage: F2 = QuantumValuedPolynomialRing(q.parent(), q) + sage: F1 is F2 + True + """ + if R not in Rings().Commutative(): + msg = "argument R must be a commutative ring" + raise TypeError(msg) + + if q is None: + laurent = LaurentPolynomialRing(R, 'q') + q = laurent.gen() + else: + laurent = q.parent() + return super().__classcall__(cls, laurent, q) + + def __init__(self, R, q) -> None: + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ); F + Quantum-Valued Polynomial Ring over Rational Field + sage: TestSuite(F).run() + + sage: F = QuantumValuedPolynomialRing(QQ, 1); F + Quantum-Valued Polynomial Ring over Integer Ring + sage: TestSuite(F).run() + + TESTS:: + + sage: QuantumValuedPolynomialRing(24) + Traceback (most recent call last): + ... + TypeError: argument R must be a commutative ring + """ + self._ground_ring = R.base_ring() + self._q = q + cat = Algebras(R).Commutative().WithBasis() + Parent.__init__(self, base=R, category=cat.WithRealizations()) + + _shorthands = ["B", "S"] + + def _repr_(self) -> str: + r""" + Return the string representation. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ) + sage: F # indirect doctest + Quantum-Valued Polynomial Ring over Rational Field + + sage: QuantumValuedPolynomialRing(ZZ) + Quantum-Valued Polynomial Ring over Integer Ring + """ + base = self.base_ring().base_ring() + return f"Quantum-Valued Polynomial Ring over {base}" + + def a_realization(self): + """ + Return a default realization. + + The Shifted realization is chosen. + + EXAMPLES:: + + sage: QuantumValuedPolynomialRing(QQ).a_realization() + Quantum-Valued Polynomial Ring over Rational Field + in the shifted basis + """ + return self.Shifted() + + class Bases(Category_realization_of_parent): + def super_categories(self) -> list: + r""" + Return the super-categories of ``self``. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ); A + Quantum-Valued Polynomial Ring over Rational Field + sage: C = A.Bases(); C + Category of bases of Quantum-Valued Polynomial Ring + over Rational Field + sage: C.super_categories() + [Category of realizations of Quantum-Valued Polynomial Ring + over Rational Field, + Join of Category of algebras with basis + over Univariate Laurent Polynomial Ring in q over Rational Field and + Category of filtered algebras + over Univariate Laurent Polynomial Ring in q over Rational Field and + Category of commutative algebras + over Univariate Laurent Polynomial Ring in q over Rational Field and + Category of realizations of unital magmas] + """ + A = self.base() + category = Algebras(A.base_ring()).Commutative().Filtered() + return [A.Realizations(), + category.Realizations().WithBasis()] + + class ParentMethods: + def ground_ring(self): + """ + Return the ring of coefficients. + + This ring is not supposed to contain the variable `q`. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: A.ground_ring() + Rational Field + """ + return self.realization_of()._ground_ring + + def _repr_(self) -> str: + r""" + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ).S() + sage: F # indirect doctest + Quantum-Valued Polynomial Ring over Rational Field + in the shifted basis + """ + real = self.realization_of() + return f"{real} in the {self._realization_name()} basis" + + @cached_method + def one_basis(self): + r""" + Return the number 0, which index the unit of this algebra. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: A.one_basis() + 0 + sage: A.one() + S[0] + """ + return self.basis().keys()(0) + + def q(self): + """ + Return the variable `q`. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: A.q() + q + """ + return self.realization_of()._q + + def degree_on_basis(self, m): + r""" + Return the degree of the basis element indexed by ``m``. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: A.degree_on_basis(4) + 4 + """ + return ZZ(m) + + def from_polynomial(self, p): + r""" + Convert a polynomial into the ring of quantum-valued polynomials. + + This raises a :exc:`ValueError` if this is not possible. + + INPUT: + + - ``p`` -- a polynomial in ``x`` with coefficients in ``QQ(q)`` + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S() + sage: S = A.basis() + sage: A.from_polynomial((S[1]).polynomial()) + S[1] + sage: A.from_polynomial((S[2]+2*S[3]).polynomial()) + S[2] + 2*S[3] + + sage: A = QuantumValuedPolynomialRing(ZZ).B() + sage: B = A.basis() + sage: A.from_polynomial((B[1]).polynomial()) + B[1] + sage: A.from_polynomial((B[2]+2*B[3]).polynomial()) + B[2] + 2*B[3] + + TESTS:: + + sage: A = QuantumValuedPolynomialRing(QQ).B() + sage: q = polygen(QQ,'q') + sage: x = polygen(q.parent(),'x') + sage: A.from_polynomial(x**2/(q+1)+1) + Traceback (most recent call last): + ... + ValueError: not a polynomial with integer values : 1/(q + 1) is not a Laurent polynomial + """ + B = self.basis() + poly = self._poly + laurent_polys = self.base_ring() + remain = p.change_variable_name('x') + result = self.zero() + while remain: + N = remain.degree() + base_N = poly(N) + top_coeff = remain.leading_coefficient() / base_N.lc() + denom = top_coeff.denominator() + if denom.is_term(): + numer = top_coeff.numerator() + top_coeff_laurent = laurent_polys(numer) / laurent_polys(denom) + else: + msg = 'not a polynomial with integer values :' + msg += f' {top_coeff} is not a Laurent polynomial' + raise ValueError(msg) + remain += -top_coeff * base_N + result += top_coeff_laurent * B[N] + return result + + def gen(self, i=0): + r""" + Return the generator of the algebra. + + The optional argument is ignored. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: F.gen() + S[1] + """ + return self.basis()[1] + + @cached_method + def algebra_generators(self): + r""" + Return the generators of this algebra. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S(); A + Quantum-Valued Polynomial Ring over Integer Ring + in the shifted basis + sage: A.algebra_generators() + Family (S[1],) + """ + return Family([self.basis()[1]]) + + gens = algebra_generators + + class ElementMethods: + def __call__(self, v): + """ + Return the evaluation at some value ``v``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: f = B**2+4*B+6 + sage: f(1/3) + (q^2 + 18*q + 99)/9 + + sage: F = QuantumValuedPolynomialRing(ZZ).B() + sage: B = F.gen() + sage: f = F.monomial(2)+4*B+6 + sage: f(1/3) + (66*q^2 + 66*q - 2)/(9*q^2 + 9*q) + """ + return self.polynomial()(v) + + def polynomial(self): + """ + Convert to a polynomial in `x`. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: S = F.gen() + sage: (S+1).polynomial() + q*x + 2 + + sage: F = QuantumValuedPolynomialRing(ZZ).B() + sage: B = F.gen() + sage: (B+1).polynomial() + x + 1 + + TESTS:: + + sage: F.zero().polynomial().parent() + Univariate Polynomial Ring in x over Fraction Field + of Univariate Polynomial Ring in q over Integer Ring + """ + ring = self.parent().ground_ring() + fractions = PolynomialRing(ring, 'q').fraction_field() + R = PolynomialRing(fractions, 'x') + p = self.parent()._poly + return R.sum(c * p(i) for i, c in self) + + def shift(self, j=1): + """ + Shift all indices by `j`. + + INPUT: + + - `j` -- integer (default 1) + + In the binomial basis, the shift by 1 corresponds to + a summation operator from `0` to `x`. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: (B+1).shift() + S[1] + S[2] + """ + A = self.parent() + return A._from_dict({A._indices(i + j): c for i, c in self}) + + def sum_of_coefficients(self): + """ + Return the sum of coefficients. + + In the shifted basis, this is the evaluation at `x=0`. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: B = F.basis() + sage: (B[2]*B[4]).sum_of_coefficients() + 1 + """ + R = self.parent().base_ring() + return R.sum(self._monomial_coefficients.values()) + + class Shifted(CombinatorialFreeModule, BindableClass): + r""" + The quantum-valued polynomial ring in the shifted basis. + + The basis used here is given by `S[i] = \genfrac{[}{]}{0pt}{}{i+x}{i}_q` for `i \in \NN`. + + Assuming `n_1 \leq n_2`, the product of two monomials `S[n_1] \cdot S[n_2]` + is given by the sum + + .. MATH:: + + \sum_{k=0}^{n_1} (-1)^k q^{\binom{k}{2} - n_1 * n_2} \genfrac{[}{]}{0pt}{}{n_1}{k}_q \genfrac{[}{]}{0pt}{}{n_1+n_2-k}{n_1}_q S[n_1 + n_2 - k]. + """ + def __init__(self, A): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ).S(); F + Quantum-Valued Polynomial Ring over Rational Field + in the shifted basis + sage: TestSuite(F).run() # not tested + """ + CombinatorialFreeModule.__init__(self, A.base_ring(), + NonNegativeIntegers(), + category=A.Bases(), + prefix="S", + latex_prefix=r"\mathbb{S}") + + def _an_element_(self): + """ + Return a small element of ``self``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ).S() + sage: F.an_element() + 2*S[0] + 4*S[2] + """ + NonNeg = self.basis().keys() + ring = self.base_ring() + return self.element_class(self, {NonNeg(0): ring(2), + NonNeg(2): ring(4)}) + + def _realization_name(self) -> str: + r""" + TESTS:: + + sage: F = QuantumValuedPolynomialRing(QQ).S() + sage: F._realization_name() + 'shifted' + """ + return "shifted" + + def product_on_basis(self, n1, n2): + r""" + Return the product of basis elements ``n1`` and ``n2``. + + INPUT: + + - ``n1``, ``n2`` -- integers + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: A.product_on_basis(0, 1) + S[1] + """ + i = ZZ(n1) + j = ZZ(n2) + if j < i: + j, i = i, j + q = self.q() + return self._from_dict({i + j - k: (-1)**k + * q_binomial(i, k) + * q_binomial(i + j - k, i) + * q**(binomial(k, 2) - i * j) + for k in range(i + 1)}) + + def _from_binomial_basis(self, i): + """ + Convert from the ``binomial(x,k)`` basis. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: S = QuantumValuedPolynomialRing(ZZ).S() + sage: B = QuantumValuedPolynomialRing(ZZ).B() + sage: b = B.basis() + sage: S(b[3]+1) # indirect doctest + -(q^-6-1)*S[0] + (q^-8+q^-7+q^-6)*S[1] + - (q^-9+q^-8+q^-7)*S[2] + (q^-9)*S[3] + sage: B(_) + B[0] + B[3] + """ + i = ZZ(i) + R = self.base_ring() + q = self.q() + return self._from_dict({k: R((-1)**(i - k) * q_binomial(i, k)) + * q**(-i**2 + binomial(i - k, 2)) + for k in range(i + 1)}) + + def from_h_vector(self, hv): + """ + Convert from some `h`-vector. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S() + sage: B = A.basis() + sage: ex = B[2] + B[3] + sage: A.from_h_vector(ex.h_vector()) + S[2] + S[3] + + sage: q = A.base_ring().gen() + sage: ex = B[2] + q*B[3] + sage: A.from_h_vector(ex.h_vector()) + S[2] + q*S[3] + """ + B = self.basis() + ring = self.base_ring() + q = self.q() + d = len(hv) - 1 + m = matrix(ring, d + 1, d + 1, + [(-1)**(d - j) * q_binomial(d - i, d - j, q) * + q**(-d * (d - i) + binomial(d - j, 2)) + for j in range(d + 1) + for i in range(d + 1)]) + v = vector(ring, [hv[i] for i in range(d + 1)]) + return sum(ring(c) * B[i] for i, c in enumerate(m * v)) + + def _element_constructor_(self, x): + r""" + Convert ``x`` into ``self``. + + INPUT: + + - ``x`` -- an element of the base ring or something convertible + + EXAMPLES:: + + sage: R = QuantumValuedPolynomialRing(QQ).S() + sage: x = R.gen() + sage: R(3) + 3*S[0] + sage: R(x) + S[1] + """ + P = parent(x) + if isinstance(P, QuantumValuedPolynomialRing.Shifted): + if P is self: + return x + if P is not self.base_ring(): + return self.element_class(self, x.monomial_coefficients()) + + # ok, not a quantum-valued polynomial ring element + R = self.base_ring() + # coercion via base ring + x = R(x) + if not x: + return self.element_class(self, {}) + return self.from_base_ring_from_one_basis(x) + + def _coerce_map_from_(self, R) -> bool: + r""" + Return whether there is a coercion from ``R`` into ``self``. + + INPUT: + + - ``R`` -- a commutative ring + + The things that coerce into ``self`` are + + - Quantum-Valued Polynomial Rings over a base + with a coercion map into ``self.base_ring()``. + + - Anything with a coercion into ``self.base_ring()``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(GF(7)).S(); F + Quantum-Valued Polynomial Ring over Finite Field of size 7 + in the shifted basis + + Elements of the quantum-valued polynomial ring canonically coerce in:: + + sage: x = F.gen() + sage: F.coerce(x*x) # indirect doctest + (6*q^-1)*S[1] + (q^-1+1)*S[2] + + Elements of the integers coerce in, since there is a coerce map + from `\ZZ` to GF(7):: + + sage: F.coerce(1) # indirect doctest + S[0] + + 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 + Quantum-Valued Polynomial Ring over Finite Field of size 7 + in the shifted basis + + Elements of the base ring coerce in:: + + sage: F.coerce(GF(7)(5)) + 5*S[0] + + The quantum-valued polynomial ring over `\ZZ` on `x` coerces in, since + `\ZZ` coerces to `\GF{7}`:: + + sage: G = QuantumValuedPolynomialRing(ZZ).S() + sage: Gx = G.gen() + sage: z = F.coerce(Gx**2); z + -(q^-1)*S[1] + (q^-1+1)*S[2] + sage: z.parent() is F + True + + However, `\GF{7}` does not coerce to `\ZZ`, so the shuffle + algebra over `\GF{7}` does not coerce to the one over `\ZZ`:: + + sage: G.coerce(x^3+x) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from Quantum-Valued Polynomial + Ring over Finite Field of size 7 in the shifted basis + to Quantum-Valued Polynomial Ring over Integer Ring + in the shifted basis + + TESTS:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: G = QuantumValuedPolynomialRing(QQ).S() + sage: H = QuantumValuedPolynomialRing(ZZ).S() + sage: F._coerce_map_from_(G) + False + sage: G._coerce_map_from_(F) + True + sage: F._coerce_map_from_(H) + True + sage: F._coerce_map_from_(QQ) + False + sage: G._coerce_map_from_(QQ) + True + sage: F.has_coerce_map_from(PolynomialRing(ZZ, 'x')) + False + """ + # quantum-valued polynomial rings in the same variable + # over any base that coerces in: + if isinstance(R, QuantumValuedPolynomialRing.Shifted): + return self.base_ring().has_coerce_map_from(R.base_ring()) + if isinstance(R, QuantumValuedPolynomialRing.Binomial): + return R.module_morphism(self._from_binomial_basis, + codomain=self) + return self.base_ring().has_coerce_map_from(R) + + def _poly(self, i): + """ + Convert the basis element `S[i]` to a polynomial. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: F._poly(4).factor() + (1/(q^6 + 3*q^5 + 5*q^4 + 6*q^3 + 5*q^2 + 3*q + 1)) * + (q*x + 1) * (q^2*x + q + 1) * (q^3*x + q^2 + q + 1) * + (q^4*x + q^3 + q^2 + q + 1) + """ + return q_binomial_x(i, i) + + class Element(CombinatorialFreeModule.Element): + def umbra(self): + """ + Return the Bernoulli umbra. + + This is the derivative at `-1` of the shift by one. + + This is related to Carlitz's `q`-Bernoulli numbers. + + .. SEEALSO:: :meth:`derivative_at_minus_one` + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: (B+1).umbra() + (q + 2)/(q + 1) + """ + return self.shift().derivative_at_minus_one() + + def variable_shift(self, k=1): + r""" + Return the image by the shift on variables. + + The shift is the substitution operator + + .. MATH:: + + x \mapsto q x + 1. + + INPUT: + + - `k` -- integer (default: 1) + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S() + sage: S = A.basis() + sage: S[5].variable_shift() + S[0] + q*S[1] + q^2*S[2] + q^3*S[3] + q^4*S[4] + q^5*S[5] + + sage: S[5].variable_shift(-1) + -(q^-5)*S[4] + (q^-5)*S[5] + + TESTS:: + + sage: S[5].variable_shift(0) + S[5] + sage: S[5].variable_shift().variable_shift(-1) + S[5] + sage: S[5].variable_shift(2).variable_shift(-2) + S[5] + sage: S[3].variable_shift(-2) + (q^-5)*S[1] - (q^-6+q^-5)*S[2] + (q^-6)*S[3] + """ + if k == 0: + return self + + A = self.parent() + q = A.q() + + def on_basis(n): + return {A._indices(j): q**(k * j) + * q_binomial(k + n - 1 - j, n - j) + for j in range(n + 1)} + + mc = self._monomial_coefficients + ret = linear_combination((on_basis(index), coeff) + for index, coeff in mc.items()) + return A.element_class(A, ret) + + def derivative_at_minus_one(self): + """ + Return the 'derivative' at -1. + + .. SEEALSO:: :meth:`umbra` + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).S() + sage: B = F.gen() + sage: (B+1).derivative_at_minus_one() + 1 + """ + ring = q_int(1).parent() + return ring.sum(c / q_int(i) for i, c in self if i > 0) + + def h_vector(self): + """ + Return the numerator of the generating series of values. + + If ``self`` is an Ehrhart polynomial, this is the h-vector. + + .. SEEALSO:: :meth:`h_polynomial`, :meth:`fraction` + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S() + sage: ex = A.basis()[4] + sage: ex.h_vector() + (0, 0, 0, 0, 1) + + sage: q = polygen(QQ,'q') + sage: x = polygen(q.parent(),'x') + sage: ex = A.from_polynomial((1+q*x)**3) + sage: ex.h_vector() + (0, q^3, 2*q + 2*q^2, 1) + """ + d = max(self.support()) + ring = self.parent().base_ring() + q = self.parent().q() + + def fn(j, i): + return ((-1)**(d - j) * + q**(binomial(d - j + i + 1, 2) - + binomial(i + 1, 2)) * + q_binomial(d - i, d - j)) + m = matrix(ring, d + 1, d + 1, fn) + v = vector(ring, [self.coefficient(i) for i in range(d + 1)]) + return m * v + + def h_polynomial(self): + """ + Return the `h`-vector as a polynomial. + + .. SEEALSO:: :meth:`h_vector`, :meth:`fraction` + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).S() + sage: q = polygen(ZZ,'q') + sage: x = polygen(q.parent(),'x') + sage: ex = A.from_polynomial((1+q*x)**3) + sage: ex.h_polynomial() + z^3 + (2*q + 2*q^2)*z^2 + q^3*z + """ + ring = PolynomialRing(self.parent().base_ring(), 'z') + return ring(list(self.h_vector())) + + def fraction(self): + """ + Return the generating series of values as a fraction. + + .. SEEALSO:: :meth:`h_vector`, :meth:`h_polynomial` + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).S() + sage: ex = A.basis()[4] + sage: ex.fraction().factor() + (-1) * (t - 1)^-1 * (q*t - 1)^-1 * (q^2*t - 1)^-1 * (q^3*t - 1)^-1 * (q^4*t - 1)^-1 + + sage: q = polygen(QQ,'q') + sage: x = polygen(q.parent(), 'x') + sage: ex = A.from_polynomial((1+q*x)**3) + sage: ex.fraction().factor() + (t - 1)^-1 * (q*t - 1)^-1 * (q^2*t - 1)^-1 * (q^3*t - 1)^-1 * (q^3*t^2 + 2*q^2*t + 2*q*t + 1) + sage: ex.fraction().numerator() + q^3*t^2 + 2*q^2*t + 2*q*t + 1 + """ + v = self.h_vector() + d = len(v) + R = PolynomialRing(QQ, 'q,t') + frac_R = R.fraction_field() + q, t = R.gens() + denom = R.prod(1 - q**i * t for i in range(d)) + numer = sum(frac_R(v[i]) * t**(d - 1 - i) for i in range(d)) + return numer / denom + + S = Shifted + + # ===== Another basis for the same algebra ===== + + class Binomial(CombinatorialFreeModule, BindableClass): + r""" + The quantum-valued polynomial ring in the binomial basis. + + The basis used here is given by `B[i] = \genfrac{[}{]}{0pt}{}{x}{i}_q` for `i \in \NN`. + + Assuming `n_1 \leq n_2`, the product of two monomials `B[n_1] \cdot B[n_2]` + is given by the sum + + .. MATH:: + + \sum_{k=0}^{n_1} q^{(k-n_1)(k-n_2)} \genfrac{[}{]}{0pt}{}{n_1}{k}_q \genfrac{[}{]}{0pt}{}{n_1+n_2-k}{n_1}_q B[n_1 + n_2 - k]. + """ + def __init__(self, A) -> None: + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(QQ).B(); F + Quantum-Valued Polynomial Ring over Rational Field + in the binomial basis + sage: TestSuite(F).run() # not tested + """ + CombinatorialFreeModule.__init__(self, A.base_ring(), + NonNegativeIntegers(), + category=A.Bases(), + prefix="B", + latex_prefix=r"\mathbb{B}") + + def _realization_name(self) -> str: + r""" + TESTS:: + + sage: F = QuantumValuedPolynomialRing(QQ).B() + sage: F._realization_name() + 'binomial' + """ + return "binomial" + + def product_on_basis(self, n1, n2): + r""" + Return the product of basis elements ``n1`` and ``n2``. + + INPUT: + + - ``n1``, ``n2`` -- integers + + The formula is taken from Theorem 3.4 in [HaHo2017]_. + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(QQ).B() + sage: A.product_on_basis(0, 1) + B[1] + """ + i = ZZ(n1) + j = ZZ(n2) + if j < i: + j, i = i, j + + q = self.q() + return self._from_dict({i + j - k: + q_binomial(i, k) + * q_binomial(i + j - k, i) + * q**((k - i) * (k - j)) + for k in range(i + 1)}) + + def _from_shifted_basis(self, i): + """ + Convert from the shifted binomial(x+k,k) basis. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: S = QuantumValuedPolynomialRing(ZZ).S() + sage: B = QuantumValuedPolynomialRing(ZZ).B() + sage: s = S.basis() + sage: B(s[3]+1) # indirect doctest + 2*B[0] + (q+q^2+q^3)*B[1] + (q^4+q^5+q^6)*B[2] + q^9*B[3] + sage: S(_) + S[0] + S[3] + """ + i = ZZ(i) + R = self.base_ring() + q = self.q() + return self._from_dict({k: R(q_binomial(i, k)) + * q**(k**2) + for k in range(i + 1)}) + + def _element_constructor_(self, x): + r""" + Convert ``x`` into ``self``. + + EXAMPLES:: + + sage: R = QuantumValuedPolynomialRing(QQ).B() + sage: x = R.gen() + sage: R(3) + 3*B[0] + sage: R(x) + B[1] + """ + P = x.parent() + if isinstance(P, QuantumValuedPolynomialRing.Binomial): + if P is self: + return x + if P is not self.base_ring(): + return self.element_class(self, x.monomial_coefficients()) + + # ok, not a quantum-valued polynomial ring element + R = self.base_ring() + # coercion via base ring + x = R(x) + if not x: + return self.element_class(self, {}) + return self.from_base_ring_from_one_basis(x) + + def _coerce_map_from_(self, R): + r""" + Return whether there is a coercion from ``R`` into ``self``. + + INPUT: + + - ``R`` -- a commutative ring + + The things that coerce into ``self`` are + + - Quantum-Valued Polynomial Rings over a base + with a coercion map into ``self.base_ring()``. + + - Anything with a coercion into ``self.base_ring()``. + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(GF(7)).B(); F + Quantum-Valued Polynomial Ring over Finite Field of size 7 + in the binomial basis + + Elements of the integer-valued polynomial ring canonically coerce + in:: + + sage: x = F.gen() + sage: F.coerce(x*x) # indirect doctest + B[1] + (q+q^2)*B[2] + + Elements of the integers coerce in, since there is a coerce map + from `\ZZ` to `\GF(7)`:: + + sage: F.coerce(1) # indirect doctest + B[0] + + 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 + Quantum-Valued Polynomial Ring over Finite Field of size 7 + in the binomial basis + + Elements of the base ring coerce in:: + + sage: F.coerce(GF(7)(5)) + 5*B[0] + + The integer-valued polynomial ring over `\ZZ` on `x` coerces in, + since `\ZZ` coerces to `\GF{7}`:: + + sage: G = QuantumValuedPolynomialRing(ZZ).B() + sage: Gx = G.gen() + sage: z = F.coerce(Gx**2); z + B[1] + (q+q^2)*B[2] + sage: z.parent() is F + True + + However, `\GF{7}` does not coerce to `\ZZ`, so the + integer-valued polynomial algebra over `\GF{7}` does not + coerce to the one over `\ZZ`:: + + sage: G.coerce(x^3+x) + Traceback (most recent call last): + ... + TypeError: no canonical coercion from + Quantum-Valued Polynomial Ring over Finite Field of size 7 + in the binomial basis to Quantum-Valued Polynomial Ring + over Integer Ring in the binomial basis + + TESTS:: + + sage: F = QuantumValuedPolynomialRing(ZZ).B() + sage: G = QuantumValuedPolynomialRing(QQ).B() + sage: H = QuantumValuedPolynomialRing(ZZ).B() + sage: F._coerce_map_from_(G) + False + sage: G._coerce_map_from_(F) + True + sage: F._coerce_map_from_(H) + True + sage: F._coerce_map_from_(QQ) + False + sage: G._coerce_map_from_(QQ) + True + sage: F.has_coerce_map_from(PolynomialRing(ZZ,'x')) + False + """ + # quantum-valued polynomial rings over any base + # that coerces in: + if isinstance(R, QuantumValuedPolynomialRing.Binomial): + return self.base_ring().has_coerce_map_from(R.base_ring()) + if isinstance(R, QuantumValuedPolynomialRing.Shifted): + return R.module_morphism(self._from_shifted_basis, + codomain=self) + return self.base_ring().has_coerce_map_from(R) + + def _poly(self, i): + """ + Convert the basis element `B[i]` to a polynomial. + + INPUT: + + - ``i`` -- an integer + + EXAMPLES:: + + sage: F = QuantumValuedPolynomialRing(ZZ).B() + sage: F._poly(4).factor() + (1/(q^12 + 3*q^11 + 5*q^10 + 6*q^9 + 5*q^8 + 3*q^7 + q^6)) * + (x - 1) * x * (x - q - 1) * (x - q^2 - q - 1) + """ + return q_binomial_x(0, i) + + class Element(CombinatorialFreeModule.Element): + def variable_shift(self, k=1): + r""" + Return the image by the shift of variables. + + On polynomials, the action for `k=1` is the shift + on variables `x \mapsto 1 + qx`. + + This implementation follows formula (5.5) in [HaHo2017]_. + + INPUT: + + - `k` -- nonnegative integer (default: 1) + + EXAMPLES:: + + sage: A = QuantumValuedPolynomialRing(ZZ).B() + sage: B = A.basis() + sage: B[5].variable_shift() + B[4] + q^5*B[5] + + TESTS:: + + sage: B[5].variable_shift(0) + B[5] + """ + if k == 0: + return self + + A = self.parent() + q = A.q() + + def on_basis(n): + return {A._indices(j): q**((k + j - n) * j) + * q_binomial(k, n - j) + for j in range(n + 1)} + + mc = self._monomial_coefficients + ret = linear_combination((on_basis(index), coeff) + for index, coeff in mc.items()) + return A.element_class(A, ret) + + B = Binomial diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd b/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd index 438773a39ef..4c6a4b638c9 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pxd @@ -7,4 +7,3 @@ cdef class SkewPolynomial_finite_order_dense (SkewPolynomial_generic_dense): cdef _matphir_c(self) cdef _matmul_c(self) - diff --git a/src/sage/rings/polynomial/weil/meson.build b/src/sage/rings/polynomial/weil/meson.build index 2c9bd006919..77432ffef30 100644 --- a/src/sage/rings/polynomial/weil/meson.build +++ b/src/sage/rings/polynomial/weil/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'power_sums.h', subdir: 'sage/rings/polynomial/weil', diff --git a/src/sage/rings/polynomial/weil/weil_polynomials.pyx b/src/sage/rings/polynomial/weil/weil_polynomials.pyx old mode 100755 new mode 100644 index e2dd7bd04e7..4c5517ad6d1 --- a/src/sage/rings/polynomial/weil/weil_polynomials.pyx +++ b/src/sage/rings/polynomial/weil/weil_polynomials.pyx @@ -83,7 +83,7 @@ cdef class dfs_manager: """ Data structure to manage depth-first search. - Such a structure is created and managed by an instance of `WeilPolynomials_iter`. + Such a structure is created and managed by an instance of ``WeilPolynomials_iter``. There is generally no need for a user to manipulate it directly. """ cdef int d @@ -156,8 +156,8 @@ cdef class dfs_manager: """ Count nodes. - This method should not be called directly. Instead, use the `node_count` method - of an instance of `WeilPolynomials` or `WeilPolynomials_iter`. + This method should not be called directly. Instead, use the ``node_count`` method + of an instance of ``WeilPolynomials`` or ``WeilPolynomials_iter``. TESTS:: @@ -179,7 +179,7 @@ cdef class dfs_manager: Advance the tree exhaustion. This method should not be called directly. Instead, use the iterator - `WeilPolynomials_iter` or the iterable `WeilPolynomials`. + ``WeilPolynomials_iter`` or the iterable ``WeilPolynomials``. TESTS:: diff --git a/src/sage/rings/power_series_pari.pyx b/src/sage/rings/power_series_pari.pyx index 8f7ff769dd1..350362cadb7 100644 --- a/src/sage/rings/power_series_pari.pyx +++ b/src/sage/rings/power_series_pari.pyx @@ -416,7 +416,7 @@ cdef class PowerSeries_pari(PowerSeries): # to an ideal I, and the element a lies in I. Here we only # implement a few special cases. from sage.rings.padics.padic_generic import pAdicGeneric - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.power_series_ring import PowerSeriesRing_generic from sage.rings.laurent_series_ring import LaurentSeriesRing if isinstance(Q, pAdicGeneric): @@ -433,7 +433,7 @@ cdef class PowerSeries_pari(PowerSeries): # subst(1 + O(x), x, 1/y) yields O(y^-1). if a.valuation() <= 0: raise ValueError("can only substitute elements of positive valuation") - elif isinstance(Q, PolynomialRing_general): + elif isinstance(Q, PolynomialRing_generic): Q = Q.completion(Q.gen()) elif Q.is_exact() and not a: pass @@ -734,7 +734,7 @@ cdef class PowerSeries_pari(PowerSeries): else: return [R(g)] + [R.zero()] * (n - 1) - def monomial_coefficients(self): + def monomial_coefficients(self, copy=None): """ Return a dictionary of coefficients for ``self``. diff --git a/src/sage/rings/power_series_poly.pxd b/src/sage/rings/power_series_poly.pxd index e37e1fb26cf..82539afef3f 100644 --- a/src/sage/rings/power_series_poly.pxd +++ b/src/sage/rings/power_series_poly.pxd @@ -7,4 +7,3 @@ cdef class PowerSeries_poly(PowerSeries): cdef class BaseRingFloorDivAction(Action): pass - diff --git a/src/sage/rings/power_series_poly.pyx b/src/sage/rings/power_series_poly.pyx index 39b05cce069..c284b06a5e4 100644 --- a/src/sage/rings/power_series_poly.pyx +++ b/src/sage/rings/power_series_poly.pyx @@ -794,7 +794,7 @@ cdef class PowerSeries_poly(PowerSeries): """ return self.__f.list() - def monomial_coefficients(self): + def monomial_coefficients(self, copy=True): """ Return a dictionary of coefficients for ``self``. @@ -814,7 +814,7 @@ cdef class PowerSeries_poly(PowerSeries): sage: f.dict() {0: 1, 10: 1} """ - return self.__f.monomial_coefficients() + return self.__f.monomial_coefficients(copy=copy) dict = monomial_coefficients diff --git a/src/sage/rings/power_series_ring.py b/src/sage/rings/power_series_ring.py index e6c932aadff..42ca735e671 100644 --- a/src/sage/rings/power_series_ring.py +++ b/src/sage/rings/power_series_ring.py @@ -148,7 +148,7 @@ from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.infinity import infinity from sage.rings.polynomial.multi_polynomial_ring_base import MPolynomialRing_base -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.structure.category_object import normalize_names from sage.structure.element import Expression, parent @@ -717,7 +717,7 @@ def _coerce_map_from_(self, S): """ if self.base_ring().has_coerce_map_from(S): return True - if (isinstance(S, (PolynomialRing_general, PowerSeriesRing_generic, LazyPowerSeriesRing)) + if (isinstance(S, (PolynomialRing_generic, PowerSeriesRing_generic, LazyPowerSeriesRing)) and self.base_ring().has_coerce_map_from(S.base_ring()) and self.variable_names() == S.variable_names()): return True @@ -1323,7 +1323,9 @@ def laurent_series_ring(self): return self.__laurent_series_ring -class PowerSeriesRing_domain(PowerSeriesRing_generic, ring.IntegralDomain): +class PowerSeriesRing_domain(PowerSeriesRing_generic): + _default_category = _IntegralDomains + def fraction_field(self): """ Return the Laurent series ring over the fraction field of the base diff --git a/src/sage/rings/puiseux_series_ring_element.pyx b/src/sage/rings/puiseux_series_ring_element.pyx index 902ce96bd7c..6ce054b27db 100644 --- a/src/sage/rings/puiseux_series_ring_element.pyx +++ b/src/sage/rings/puiseux_series_ring_element.pyx @@ -201,7 +201,7 @@ cdef class PuiseuxSeries(AlgebraElement): l = l.add_bigoh(prec / d) self._l = l - self._e = long(abs(e)) + self._e = int(abs(e)) def __reduce__(self): """ @@ -854,7 +854,7 @@ cdef class PuiseuxSeries(AlgebraElement): sage: p.exponents() [3/4, 4/5, 5/6] """ - return [QQ(n) / self._e for n in self._l.exponents()] + return [QQ(n) / self._e for n in self._l.exponents()] def __setitem__(self, n, value): """ diff --git a/src/sage/rings/qqbar.py b/src/sage/rings/qqbar.py index 72df892337b..050ab750117 100644 --- a/src/sage/rings/qqbar.py +++ b/src/sage/rings/qqbar.py @@ -1313,7 +1313,7 @@ def _is_valid_homomorphism_(self, codomain, im_gens, base_map=False): except TypeError: return False - def gens(self): + def gens(self) -> tuple: r""" Return a set of generators for this field. @@ -1811,7 +1811,7 @@ def construction(self): from sage.rings.rational_field import QQ return (AlgebraicClosureFunctor(), QQ) - def gens(self): + def gens(self) -> tuple: r""" Return a set of generators for this field. @@ -2711,7 +2711,7 @@ def number_field_elements_from_algebraics(numbers, minimal=False, -1 sage: nfI^2 -1 - sage: sum = nfrt2 + nfrt3 + nfI + nfz3; sum + sage: sum = nfrt2 + nfrt3 + nfI + nfz3; sum # random a^5 + a^4 - a^3 + 2*a^2 - a - 1 sage: hom(sum) 2.646264369941973? + 1.866025403784439?*I @@ -7098,12 +7098,26 @@ def exactify(self): sage: cp.exactify() sage: cp._exact True + + TESTS: + + Check that interrupting ``exactify()`` does not lead to incoherent state:: + + sage: x = polygen(AA) + sage: p = AA(2)^(1/100) * x + AA(3)^(1/100) + sage: cp = AA.common_polynomial(p) + sage: alarm(0.5); cp.generator() + Traceback (most recent call last): + ... + AlarmInterrupt + sage: alarm(0.5); cp.generator() + Traceback (most recent call last): + ... + AlarmInterrupt """ if self._exact: return - self._exact = True - if self._poly.base_ring() is QQ: self._factors = [fac_exp[0] for fac_exp in self._poly.factor()] self._gen = qq_generator @@ -7128,6 +7142,8 @@ def exactify(self): self._factors = [fac_exp[0] for fac_exp in fp.factor()] + self._exact = True + def factors(self): r""" EXAMPLES:: diff --git a/src/sage/rings/quotient_ring.py b/src/sage/rings/quotient_ring.py index c867ba41bbc..1043333a63e 100644 --- a/src/sage/rings/quotient_ring.py +++ b/src/sage/rings/quotient_ring.py @@ -383,7 +383,7 @@ def is_QuotientRing(x): @richcmp_method -class QuotientRing_nc(ring.Ring, sage.structure.parent_gens.ParentWithGens): +class QuotientRing_nc(ring.Ring): """ The quotient ring of `R` by a twosided ideal `I`. @@ -495,14 +495,13 @@ def __init__(self, R, I, names, category=None): raise TypeError("The second argument must be an ideal of the given ring, but %s is not" % I) self.__R = R self.__I = I - #sage.structure.parent_gens.ParentWithGens.__init__(self, R.base_ring(), names) - ## + # Unfortunately, computing the join of categories, which is done in # check_default_category, is very expensive. # However, we don't just want to use the given category without mixing in # some quotient stuff - unless Parent.__init__ was called # previously, in which case the quotient ring stuff is just - # a vaste of time. This is the case for FiniteField_prime_modn. + # a waste of time. This is the case for FiniteField_prime_modn. if not self._is_category_initialized(): if category is None: try: @@ -589,7 +588,7 @@ def _latex_(self): """ return "%s/%s" % (latex.latex(self.cover_ring()), latex.latex(self.defining_ideal())) - def is_commutative(self): + def is_commutative(self) -> bool: """ Tell whether this quotient ring is commutative. diff --git a/src/sage/rings/rational.pyx b/src/sage/rings/rational.pyx index bc29e952b1a..68ee004a251 100644 --- a/src/sage/rings/rational.pyx +++ b/src/sage/rings/rational.pyx @@ -3030,7 +3030,7 @@ cdef class Rational(sage.structure.element.FieldElement): Convert this rational to a Python ``int``. This truncates ``self`` if ``self`` has a denominator (which is - consistent with Python's ``long(floats)``). + consistent with Python's ``int(floats)``). EXAMPLES:: @@ -4243,7 +4243,7 @@ cdef class int_to_Q(Morphism): import sage.categories.homset from sage.sets.pythonclass import Set_PythonType Morphism.__init__(self, sage.categories.homset.Hom( - Set_PythonType(long), rational_field.QQ)) + Set_PythonType(int), rational_field.QQ)) cpdef Element _call_(self, a): """ diff --git a/src/sage/rings/rational_field.py b/src/sage/rings/rational_field.py index f1b414089e2..a4ca268a0c6 100644 --- a/src/sage/rings/rational_field.py +++ b/src/sage/rings/rational_field.py @@ -634,10 +634,8 @@ def automorphisms(self): EXAMPLES:: sage: QQ.automorphisms() - [ - Ring endomorphism of Rational Field - Defn: 1 |--> 1 - ] + [Ring endomorphism of Rational Field + Defn: 1 |--> 1] """ return Sequence([self.hom(1, self)], cr=True, immutable=False, check=False) @@ -918,7 +916,7 @@ def phi(x): assert phi(a) == v, "oops" return a - def gens(self): + def gens(self) -> tuple: r""" Return a tuple of generators of `\QQ`, which is only ``(1,)``. diff --git a/src/sage/rings/real_double.pyx b/src/sage/rings/real_double.pyx index 129603749d3..5efa0c87b65 100644 --- a/src/sage/rings/real_double.pyx +++ b/src/sage/rings/real_double.pyx @@ -132,7 +132,8 @@ cdef class RealDoubleField_class(sage.rings.abc.RealDoubleField): sage: TestSuite(R).run() """ from sage.categories.fields import Fields - Field.__init__(self, self, category=Fields().Infinite().Metric().Complete()) + Field.__init__(self, self, + category=Fields().Infinite().Metric().Complete()) self._populate_coercion_lists_(init_no_parent=True, convert_method_name='_real_double_') diff --git a/src/sage/rings/real_double_element_gsl.pyx b/src/sage/rings/real_double_element_gsl.pyx index 001564dee37..7fea4dbc155 100644 --- a/src/sage/rings/real_double_element_gsl.pyx +++ b/src/sage/rings/real_double_element_gsl.pyx @@ -8,7 +8,16 @@ from cysignals.signals cimport sig_on, sig_off from sage.arith.constants cimport * -from sage.libs.gsl.all cimport * +from sage.libs.gsl.errno cimport gsl_set_error_handler_off +from sage.libs.gsl.math cimport * +from sage.libs.gsl.exp cimport * +from sage.libs.gsl.log cimport gsl_sf_log +from sage.libs.gsl.trig cimport * +from sage.libs.gsl.dilog cimport gsl_sf_dilog +from sage.libs.gsl.gamma cimport gsl_sf_fact, gsl_sf_gamma +from sage.libs.gsl.zeta cimport gsl_sf_zeta +from sage.libs.gsl.erf cimport gsl_sf_erf + gsl_set_error_handler_off() diff --git a/src/sage/rings/real_lazy.pxd b/src/sage/rings/real_lazy.pxd index 60a6580a550..c7aa82cd596 100644 --- a/src/sage/rings/real_lazy.pxd +++ b/src/sage/rings/real_lazy.pxd @@ -27,4 +27,3 @@ cdef class LazyUnop(LazyFieldElement): cdef class LazyNamedUnop(LazyUnop): cdef readonly _extra_args - diff --git a/src/sage/rings/real_lazy.pyx b/src/sage/rings/real_lazy.pyx index 8fe3a8281d0..b2212871dfa 100644 --- a/src/sage/rings/real_lazy.pyx +++ b/src/sage/rings/real_lazy.pyx @@ -174,7 +174,7 @@ cdef class LazyField(Field): True """ if isinstance(R, type): - if R in [int, long]: + if R is int: from sage.sets.pythonclass import Set_PythonType return LazyWrapperMorphism(Set_PythonType(R), self) elif R.is_exact(): diff --git a/src/sage/rings/real_mpfi.pyx b/src/sage/rings/real_mpfi.pyx index 11953a50ab5..ce9958ce7e7 100644 --- a/src/sage/rings/real_mpfi.pyx +++ b/src/sage/rings/real_mpfi.pyx @@ -120,6 +120,26 @@ satisfying, but we have chosen the latter. sage: a == 2 False +Some default printing options can be set by modifying module globals:: + + sage: from sage.rings import real_mpfi + sage: x = RIF(sqrt(2), sqrt(2)+1e-10); x + 1.4142135624? + sage: real_mpfi.printing_error_digits = 2 + sage: x + 1.414213562424?51 + sage: real_mpfi.printing_style = 'brackets' + sage: x + [1.4142135623730949 .. 1.4142135624730952] + sage: real_mpfi.printing_style = 'question'; real_mpfi.printing_error_digits = 0 # revert to default + +The default value of using scientific notation can be configured at field construction instead:: + + sage: RealIntervalField(53, sci_not=False)(0.5) + 0.50000000000000000? + sage: RealIntervalField(53, sci_not=True)(0.5) + 5.0000000000000000?e-1 + COMPARISONS: Comparison operations (``==``, ``!=``, ``<``, ``<=``, ``>``, ``>=``) @@ -816,9 +836,7 @@ cdef class RealIntervalField_class(sage.rings.abc.RealIntervalField): prec = self._prec # Direct and efficient conversions - if S is ZZ or S is QQ: - return True - if S is int or S is long: + if S is ZZ or S is QQ or S is int: return True if isinstance(S, RealIntervalField_class): return (S)._prec >= prec diff --git a/src/sage/rings/real_mpfr.pyx b/src/sage/rings/real_mpfr.pyx index 7e1ab748b55..31d0bb96aed 100644 --- a/src/sage/rings/real_mpfr.pyx +++ b/src/sage/rings/real_mpfr.pyx @@ -753,8 +753,6 @@ cdef class RealField_class(sage.rings.abc.RealField): return QQtoRR(QQ, self) elif (S is RDF or S is float) and self._prec <= 53: return double_toRR(S, self) - elif S is long: - return int_toRR(long, self) elif S is int: return int_toRR(int, self) elif isinstance(S, RealField_class) and S.prec() >= self._prec: @@ -1437,6 +1435,33 @@ cdef class RealNumber(sage.structure.element.RingElement): sage: RealNumber('1_3.1e-32_45') 1.31000000000000e-3244 + + Test conversion from base different from `10`:: + + sage: RR('0xabc') + Traceback (most recent call last): + ... + TypeError: unable to convert '0xabc' to a real number + sage: RR("0x123.e1", base=0) # rel tol 1e-12 + 291.878906250000 + sage: RR("0x123.@1", base=0) # rel tol 1e-12 + 4656.00000000000 + sage: RR("1Xx", base=36) # rel tol 1e-12 + 2517.00000000000 + sage: RR("-1Xx@-10", base=62) # rel tol 1e-12 + -7.08805492048139e-15 + sage: RR("1", base=1) + Traceback (most recent call last): + ... + ValueError: base (=1) must be 0 or between 2 and 62 + sage: RR("1", base=-1) + Traceback (most recent call last): + ... + ValueError: base (=-1) must be 0 or between 2 and 62 + sage: RR("1", base=63) + Traceback (most recent call last): + ... + ValueError: base (=63) must be 0 or between 2 and 62 """ if x is not None: self._set(x, base) @@ -1485,6 +1510,8 @@ cdef class RealNumber(sage.structure.element.RingElement): # Real Numbers are supposed to be immutable. cdef RealField_class parent parent = self._parent + if base != 0 and (base < 2 or base > 62): + raise ValueError(f"base (={base}) must be 0 or between 2 and 62") if isinstance(x, RealNumber): if isinstance(x, RealLiteral): s = (x).literal diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 28f272a18f0..04ed386e799 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -23,7 +23,7 @@ The class inheritance hierarchy is: - :class:`NoetherianRing` (deprecated and essentially removed) - :class:`CommutativeAlgebra` (deprecated and essentially removed) - - :class:`IntegralDomain` (deprecated) + - :class:`IntegralDomain` (deprecated and essentially removed) - :class:`DedekindDomain` (deprecated and essentially removed) - :class:`PrincipalIdealDomain` (deprecated and essentially removed) @@ -218,7 +218,7 @@ cdef class Ring(ParentWithGens): sage: CDF._repr_option('element_is_atomic') # needs sage.rings.complex_double False - Check that categories correctly implement `is_finite` and `cardinality`:: + Check that categories correctly implement ``is_finite`` and ``cardinality``:: sage: QQ.is_finite() False @@ -253,8 +253,6 @@ cdef class Ring(ParentWithGens): # yield an infinite recursion. But when we call it from here, it works. # This is done in order to ensure that __init_extra__ is called. # - # ParentWithGens.__init__(self, base, names=names, normalize=normalize) - # # This is a low-level class. For performance, we trust that the category # is fine, if it is provided. If it isn't, we use the category of rings. if category is None: @@ -761,11 +759,9 @@ cdef class CommutativeRing(Ring): sage: Integers(389)['x,y'] Multivariate Polynomial Ring in x, y over Ring of integers modulo 389 """ - try: - if not base_ring.is_commutative(): - raise TypeError("base ring %s is no commutative ring" % base_ring) - except AttributeError: + if base_ring is not self and base_ring not in _CommutativeRings: raise TypeError("base ring %s is no commutative ring" % base_ring) + # This is a low-level class. For performance, we trust that # the category is fine, if it is provided. If it isn't, we use # the category of commutative rings. @@ -773,25 +769,6 @@ cdef class CommutativeRing(Ring): Ring.__init__(self, base_ring, names=names, normalize=normalize, category=category) - def localization(self, additional_units, names=None, normalize=True, category=None): - """ - Return the localization of ``self`` at the given additional units. - - EXAMPLES:: - - sage: R. = GF(3)[] - sage: R.localization((x*y, x**2 + y**2)) # needs sage.rings.finite_rings - Multivariate Polynomial Ring in x, y over Finite Field of size 3 - localized at (y, x, x^2 + y^2) - sage: ~y in _ # needs sage.rings.finite_rings - True - """ - if not self.is_integral_domain(): - raise TypeError("self must be an integral domain.") - - from sage.rings.localization import Localization - return Localization(self, additional_units, names=names, normalize=normalize, category=category) - def fraction_field(self): """ Return the fraction field of ``self``. @@ -849,23 +826,6 @@ cdef class CommutativeRing(Ring): except (NotImplementedError,TypeError): return coercion_model.division_parent(self) - def is_commutative(self): - """ - Return ``True``, since this ring is commutative. - - EXAMPLES:: - - sage: QQ.is_commutative() - True - sage: ZpCA(7).is_commutative() # needs sage.rings.padics - True - sage: A = QuaternionAlgebra(QQ, -1, -3, names=('i','j','k')); A # needs sage.combinat sage.modules - Quaternion Algebra (-1, -3) with base ring Rational Field - sage: A.is_commutative() # needs sage.combinat sage.modules - False - """ - return True - def krull_dimension(self): """ Return the Krull dimension of this commutative ring. @@ -973,105 +933,12 @@ cdef class CommutativeRing(Ring): cdef class IntegralDomain(CommutativeRing): - """ - Generic integral domain class. - - This class is deprecated. Please use the - :class:`sage.categories.integral_domains.IntegralDomains` - category instead. - """ _default_category = IntegralDomains() - def __init__(self, base_ring, names=None, normalize=True, category=None): - """ - Initialize ``self``. - - INPUT: - - - ``category`` -- (default: ``None``) a category, or ``None`` - - This method is used by all the abstract subclasses of - :class:`IntegralDomain`, like :class:`Field`, ... in order to - avoid cascade calls Field.__init__ -> - IntegralDomain.__init__ -> - ... - - EXAMPLES:: - - sage: F = IntegralDomain(QQ) - sage: F.category() - Category of integral domains - - sage: F = Field(QQ) - sage: F.category() - Category of fields - - The default value for the category is specified by the class - attribute ``default_category``:: - - sage: IntegralDomain._default_category - Category of integral domains - - sage: Field._default_category - Category of fields - """ - CommutativeRing.__init__(self, base_ring, names=names, normalize=normalize, - category=category) - - def is_integrally_closed(self): - r""" - Return ``True`` if this ring is integrally closed in its field of - fractions; otherwise return ``False``. - - When no algorithm is implemented for this, then this - function raises a :exc:`NotImplementedError`. - - Note that ``is_integrally_closed`` has a naive implementation - in fields. For every field `F`, `F` is its own field of fractions, - hence every element of `F` is integral over `F`. - - EXAMPLES:: - - sage: ZZ.is_integrally_closed() - True - sage: QQ.is_integrally_closed() - True - sage: QQbar.is_integrally_closed() # needs sage.rings.number_field - True - sage: GF(5).is_integrally_closed() - True - sage: Z5 = Integers(5); Z5 - Ring of integers modulo 5 - sage: Z5.is_integrally_closed() - Traceback (most recent call last): - ... - AttributeError: 'IntegerModRing_generic_with_category' object has no attribute 'is_integrally_closed'... - """ - raise NotImplementedError - - def is_field(self, proof=True): - r""" - Return ``True`` if this ring is a field. - - EXAMPLES:: - - sage: GF(7).is_field() - True + def __init__(self, *args, **kwds): + deprecation(39227, "use the category IntegralDomains") + super().__init__(*args, **kwds) - The following examples have their own ``is_field`` implementations:: - - sage: ZZ.is_field(); QQ.is_field() - False - True - sage: R. = PolynomialRing(QQ); R.is_field() - False - """ - if self.is_finite(): - return True - if proof: - raise NotImplementedError("unable to determine whether or not is a field.") - else: - return False cdef class NoetherianRing(CommutativeRing): _default_category = NoetherianRings() @@ -1228,18 +1095,6 @@ cdef class Field(CommutativeRing): """ return True - def is_integrally_closed(self): - """ - Return ``True`` since fields are trivially integrally closed in - their fraction field (since they are their own fraction field). - - EXAMPLES:: - - sage: Frac(ZZ['x,y']).is_integrally_closed() - True - """ - return True - def krull_dimension(self): """ Return the Krull dimension of this field, which is 0. diff --git a/src/sage/rings/ring_extension_conversion.pxd b/src/sage/rings/ring_extension_conversion.pxd index e3815a411ba..5a7c871841e 100644 --- a/src/sage/rings/ring_extension_conversion.pxd +++ b/src/sage/rings/ring_extension_conversion.pxd @@ -13,5 +13,3 @@ cpdef from_backend_morphism(f, RingExtension_generic E) cpdef to_backend(arg) cpdef from_backend(arg, E) - - diff --git a/src/sage/rings/ring_extension_element.pxd b/src/sage/rings/ring_extension_element.pxd index 9bd662f3d0f..ca83f669643 100644 --- a/src/sage/rings/ring_extension_element.pxd +++ b/src/sage/rings/ring_extension_element.pxd @@ -18,5 +18,3 @@ cdef class RingExtensionWithBasisElement(RingExtensionElement): cdef _trace(self, Parent base) cdef _norm(self, Parent base) cpdef minpoly(self, base=*, var=*) - - diff --git a/src/sage/rings/ring_extension_morphism.pyx b/src/sage/rings/ring_extension_morphism.pyx index d4aad7f8253..7294e90c319 100644 --- a/src/sage/rings/ring_extension_morphism.pyx +++ b/src/sage/rings/ring_extension_morphism.pyx @@ -461,7 +461,7 @@ cdef class RingExtensionHomomorphism(RingMap): if self.base_map() is not None: s += "with map on base ring" ss = self.base_map()._repr_defn() - ss = re.sub('\nwith map on base ring:?$', '', ss, 0, re.MULTILINE) + ss = re.sub('\nwith map on base ring:?$', '', ss, flags=re.MULTILINE) if ss != "": s += ":\n" + ss if s != "" and s[-1] == "\n": s = s[:-1] diff --git a/src/sage/rings/semirings/meson.build b/src/sage/rings/semirings/meson.build index e1e4e627ba3..6cbfce4f84c 100644 --- a/src/sage/rings/semirings/meson.build +++ b/src/sage/rings/semirings/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'non_negative_integer_semiring.py', 'tropical_mpolynomial.py', diff --git a/src/sage/rings/semirings/tropical_mpolynomial.py b/src/sage/rings/semirings/tropical_mpolynomial.py index d8011d2b033..c1f1a744acb 100644 --- a/src/sage/rings/semirings/tropical_mpolynomial.py +++ b/src/sage/rings/semirings/tropical_mpolynomial.py @@ -33,9 +33,9 @@ # **************************************************************************** from sage.misc.cachefunc import cached_method +from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict class TropicalMPolynomial(MPolynomial_polydict): @@ -286,8 +286,9 @@ def plot3d(self, color='random'): multivariate polynomial in two variables """ from random import random - from sage.plot.graphics import Graphics + from sage.geometry.polyhedron.constructor import Polyhedron + from sage.plot.graphics import Graphics from sage.sets.real_set import RealSet from sage.symbolic.relation import solve @@ -399,7 +400,11 @@ def tropical_variety(self): sage: p1.tropical_variety() Tropical surface of 1*x*y + (-1/2)*x*z + 4*z^2 """ - from sage.rings.semirings.tropical_variety import TropicalCurve, TropicalSurface, TropicalVariety + from sage.rings.semirings.tropical_variety import ( + TropicalCurve, + TropicalSurface, + TropicalVariety, + ) if self.parent().ngens() == 2: return TropicalCurve(self) @@ -617,8 +622,8 @@ def dual_subdivision(self): A vertex at (1, 0, 1, 0), A vertex at (1, 1, 0, 0))] """ - from sage.geometry.polyhedron.constructor import Polyhedron from sage.geometry.polyhedral_complex import PolyhedralComplex + from sage.geometry.polyhedron.constructor import Polyhedron TV = self.tropical_variety() cycles = [] @@ -627,18 +632,14 @@ def dual_subdivision(self): for indices in TV._vertices_components().values(): cycle = [] for index in indices: - vertices = TV._keys[index[0]] - for v in vertices: - cycle.append(v) + cycle.extend(TV._keys[index[0]]) cycles.append(cycle) else: line_comps = TV.weight_vectors()[1] for indices in line_comps.values(): cycle = [] for index in indices: - vertices = TV._keys[index] - for v in vertices: - cycle.append(v) + cycle.extend(TV._keys[index]) cycles.append(cycle) polyhedron_lst = [] @@ -729,8 +730,8 @@ def __init__(self, base_semiring, n, names, order): sage: R = PolynomialRing(T, 5, 'x') sage: TestSuite(R).run() """ - from sage.rings.semirings.tropical_semiring import TropicalSemiring from sage.categories.semirings import Semirings + from sage.rings.semirings.tropical_semiring import TropicalSemiring if not isinstance(base_semiring, TropicalSemiring): raise ValueError(f"{base_semiring} is not a tropical semiring") Parent.__init__(self, base=base_semiring, names=names, category=Semirings()) @@ -915,7 +916,7 @@ def gen(self, n=0): return self.gens()[n] @cached_method - def gens(self): + def gens(self) -> tuple: r""" Return the generators of ``self``. diff --git a/src/sage/rings/semirings/tropical_polynomial.py b/src/sage/rings/semirings/tropical_polynomial.py index 4e4e239edd2..84240eb933f 100644 --- a/src/sage/rings/semirings/tropical_polynomial.py +++ b/src/sage/rings/semirings/tropical_polynomial.py @@ -35,9 +35,9 @@ # **************************************************************************** from sage.misc.cachefunc import cached_method -from sage.structure.unique_representation import UniqueRepresentation -from sage.structure.parent import Parent from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation class TropicalPolynomial(Polynomial_generic_sparse): @@ -107,7 +107,7 @@ class TropicalPolynomial(Polynomial_generic_sparse): [1, 1] Even though every tropical polynomials have tropical roots, this does not - neccessarily means it can be factored into its linear factors:: + necessarily means it can be factored into its linear factors:: sage: p1.factor() (0) * (0*x^3 + 4*x + 1) @@ -371,9 +371,9 @@ def piecewise_function(self): sage: p3.piecewise_function() 3*x + 1 """ - from sage.symbolic.ring import SR from sage.functions.piecewise import piecewise from sage.sets.real_set import RealSet + from sage.symbolic.ring import SR x = SR.var('x') data = self.monomial_coefficients() @@ -769,9 +769,9 @@ def gen(self, n=0): return self.gens()[n] @cached_method - def gens(self): + def gens(self) -> tuple: """ - Return a tuple whose entries are the generators for ``self``. + Return the generators for ``self``. EXAMPLES:: @@ -806,7 +806,7 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): .. SEEALSO:: - :meth:`sage.rings.polynomial.polynomial_ring.PolynomialRing_general.random_element` + :meth:`sage.rings.polynomial.polynomial_ring.PolynomialRing_generic.random_element` EXAMPLES: diff --git a/src/sage/rings/semirings/tropical_variety.py b/src/sage/rings/semirings/tropical_variety.py index dbc1b85cd52..3393a4416be 100644 --- a/src/sage/rings/semirings/tropical_variety.py +++ b/src/sage/rings/semirings/tropical_variety.py @@ -26,11 +26,11 @@ # https://www.gnu.org/licenses/ # **************************************************************************** +from sage.rings.infinity import infinity +from sage.rings.rational_field import QQ from sage.structure.sage_object import SageObject from sage.structure.unique_representation import UniqueRepresentation -from sage.rings.rational_field import QQ -from sage.rings.infinity import infinity class TropicalVariety(UniqueRepresentation, SageObject): r""" @@ -187,10 +187,11 @@ def __init__(self, poly): """ import operator from itertools import combinations - from sage.symbolic.ring import SR - from sage.symbolic.relation import solve + from sage.arith.misc import gcd from sage.rings.semirings.tropical_mpolynomial import TropicalMPolynomial + from sage.symbolic.relation import solve + from sage.symbolic.ring import SR if not isinstance(poly, TropicalMPolynomial): raise ValueError(f"{poly} is not a multivariate tropical polynomial") @@ -447,9 +448,10 @@ def _components_intersection(self): 5: [((0, t2, 0), {0 <= t2}), ((1/2*t2, t2, t2), {t2 <= 0})]} """ import operator + from sage.functions.min_max import max_symbolic, min_symbolic - from sage.symbolic.relation import solve from sage.sets.set import Set + from sage.symbolic.relation import solve def update_result(result): sol_param = solve(new_expr, vars) @@ -591,19 +593,20 @@ def weight_vectors(self): sage: all(a == vector([0,0,0,0]) for a in [sum(lst) for lst in vec]) True """ - from sage.symbolic.ring import SR - from sage.symbolic.relation import solve - from sage.calculus.functional import diff + from itertools import combinations + from sage.arith.misc import gcd + from sage.calculus.functional import diff from sage.matrix.constructor import matrix from sage.modules.free_module_element import vector, zero_vector - from itertools import combinations + from sage.symbolic.relation import solve + from sage.symbolic.ring import SR dim = self.dimension() t = SR.var('t') - t_vars = [SR.var('t{}'.format(i)) for i in range(dim)] - u_vars = [SR.var('u{}'.format(i)) for i in range(dim)] - convert_tu = {ti: ui for ti, ui in zip(t_vars, u_vars)} + t_vars = [SR.var(f't{i}') for i in range(dim)] + u_vars = [SR.var(f'u{i}') for i in range(dim)] + convert_tu = dict(zip(t_vars, u_vars)) CI = self._components_intersection() unique_line = set() index_line = {} @@ -656,9 +659,9 @@ def weight_vectors(self): if is_unique: new_eqn = tuple([eq.subs(convert_tu) for eq in eqn]) cdns = line[1] - new_cdn = set([cdn.subs(convert_tu) for cdn in cdns]) + new_cdn = {cdn.subs(convert_tu) for cdn in cdns} unique_line.add(new_eqn) - index_line[index] = tuple([new_eqn, new_cdn]) + index_line[index] = (new_eqn, new_cdn) line_comps[index] = [i] index += 1 else: @@ -675,9 +678,7 @@ def weight_vectors(self): for v in l.variables(): all_var.add(v) for vpar in all_var: - par_drv = [] - for l in line: - par_drv.append(QQ(diff(l, vpar))) + par_drv = [QQ(diff(l, vpar)) for l in line] par_drv = vector(par_drv) dir_vecs.append(par_drv) @@ -687,32 +688,24 @@ def weight_vectors(self): surface = self._hypersurface[i][0] drv_vectors = [] for vpar in self._vars: - temp_vec = [] - for s in surface: - temp_vec.append(QQ(diff(s, vpar))) + temp_vec = [QQ(diff(s, vpar)) for s in surface] temp_vec = vector(temp_vec) drv_vectors.append(temp_vec) temp = [t_vars] - for vec in drv_vectors: - temp.append(vec) + temp.extend(drv_vectors) vec_matrix = matrix(SR, temp) normal_vec = vec_matrix.det() - temp_nor = [] - for tvar in t_vars: - temp_nor.append(QQ(diff(normal_vec, tvar))) + temp_nor = [QQ(diff(normal_vec, tvar)) for tvar in t_vars] normal_vec = vector(temp_nor) normal_vec *= 1/gcd(normal_vec) # Calculate the weight vector temp_final = [t_vars] - for v in dir_vecs: - temp_final.append(v) + temp_final.extend(dir_vecs) temp_final.append(normal_vec) vec_matrix = matrix(SR, temp_final) weight_vec = vec_matrix.det() - temp_weight = [] - for tvar in t_vars: - temp_weight.append(QQ(diff(weight_vec, tvar))) + temp_weight = [QQ(diff(weight_vec, tvar)) for tvar in t_vars] weight_vec = vector(temp_weight) order = self._hypersurface[i][2] weight_vec *= order @@ -721,7 +714,7 @@ def weight_vectors(self): balance = False for i in range(1, len(WV[k])+1): for j in combinations(range(len(WV[k])), i): - test_vectors = [v for v in WV[k]] + test_vectors = list(WV[k]) for idx in j: test_vectors[idx] = -test_vectors[idx] if sum(test_vectors) == zero_vector(QQ, dim): @@ -790,8 +783,8 @@ def _axes(self): sage: p2.tropical_variety()._axes() [[-1, 2], [-1, 2], [-1, 2]] """ - from sage.symbolic.relation import solve from sage.arith.srange import srange + from sage.symbolic.relation import solve if not self._hypersurface: return [[-1, 1], [-1, 1], [-1, 1]] @@ -910,8 +903,8 @@ def _polygon_vertices(self): 7: {(-1/2, -1, -1), (-1/2, 2, -1), (0, 0, 0), (0, 2, 0)}, 8: {(1, 1, 1), (1, 2, 1), (2, 1, 1), (2, 2, 1)}} """ - from sage.symbolic.relation import solve from sage.sets.real_set import RealSet + from sage.symbolic.relation import solve poly_verts = {i: set() for i in range(self.number_of_components())} axes = self._axes() @@ -1056,8 +1049,9 @@ def plot(self, color='random'): sphinx_plot(p2.tropical_variety().plot()) """ from random import random - from sage.plot.graphics import Graphics + from sage.geometry.polyhedron.constructor import Polyhedron + from sage.plot.graphics import Graphics if color == 'random': colors = [] @@ -1282,17 +1276,17 @@ def _vertices_components(self): if lower != -infinity: x = parametric_function[0].subs(**{str(v): lower}) y = parametric_function[1].subs(**{str(v): lower}) - if (x,y) not in comp_vert: - comp_vert[(x,y)] = [(i, 1)] + if (x, y) not in comp_vert: + comp_vert[(x, y)] = [(i, 1)] else: - comp_vert[(x,y)].append((i, 1)) + comp_vert[(x, y)].append((i, 1)) if upper != infinity: x = parametric_function[0].subs(**{str(v): upper}) y = parametric_function[1].subs(**{str(v): upper}) - if (x,y) not in comp_vert: - comp_vert[(x,y)] = [(i, -1)] + if (x, y) not in comp_vert: + comp_vert[(x, y)] = [(i, -1)] else: - comp_vert[(x,y)].append((i, -1)) + comp_vert[(x, y)].append((i, -1)) return comp_vert def weight_vectors(self): @@ -1333,9 +1327,9 @@ def weight_vectors(self): (-1, 0): [(-1, 0), (0, -1), (1, 1)], (3, 4): [(-1, -1), (0, 1), (1, 0)]} """ + from sage.arith.misc import gcd from sage.calculus.functional import diff from sage.modules.free_module_element import vector - from sage.arith.misc import gcd if not self._vertices_components(): return {} @@ -1635,10 +1629,9 @@ def plot(self): + R(4)*x**3*y + x**2*y**2 + R(2)*x*y**3 + y**4) sphinx_plot(p3.tropical_variety().plot()) """ - from sage.plot.plot import plot - from sage.plot.text import text from sage.plot.graphics import Graphics - from sage.plot.plot import parametric_plot + from sage.plot.plot import parametric_plot, plot + from sage.plot.text import text if not self._hypersurface: return plot(lambda x: float('nan'), {-1, 1}) diff --git a/src/sage/rings/species.py b/src/sage/rings/species.py index bcda9a9f510..494e7020331 100644 --- a/src/sage/rings/species.py +++ b/src/sage/rings/species.py @@ -31,7 +31,7 @@ """ -from itertools import accumulate, chain +from itertools import accumulate, chain, product from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis from sage.categories.modules import Modules @@ -381,7 +381,7 @@ def __init__(self, names): TESTS: - We have to exclude `_test_graded_components`, because + We have to exclude ``_test_graded_components``, because :meth:`~sage.combinat.integer_vector.IntegerVectors.some_elements` yields degrees that are too large:: @@ -730,16 +730,17 @@ def _an_element_(self): Element = AtomicSpeciesElement -def _stabilizer_subgroups(G, X, a): +def _stabilizer_subgroups(G, X, a, side='right', check=True): r""" Return subgroups conjugate to the stabilizer subgroups of the - given (left) group action. + given group action. INPUT: - ``G`` -- the acting group - ``X`` -- the set ``G`` is acting on - - ``a`` -- the (left) action + - ``a`` -- the action, a function `G\times X\to X` if ``side`` is + ``'left'``, `X\times G\to X` if ``side`` is ``'right'`` EXAMPLES:: @@ -747,17 +748,17 @@ def _stabilizer_subgroups(G, X, a): sage: S = SymmetricGroup(4) sage: X = SetPartitions(S.degree(), [2,2]) sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x]) - sage: _stabilizer_subgroups(S, X, a) + sage: _stabilizer_subgroups(S, X, a, side='left') [Permutation Group with generators [(1,2), (1,3)(2,4)]] sage: S = SymmetricGroup(8) sage: X = SetPartitions(S.degree(), [3,3,2]) - sage: _stabilizer_subgroups(S, X, a) + sage: _stabilizer_subgroups(S, X, a, side='left', check=False) [Permutation Group with generators [(7,8), (6,7), (4,5), (1,3)(2,6)(4,7)(5,8), (1,3)]] sage: S = SymmetricGroup(4) sage: X = SetPartitions(S.degree(), 2) - sage: _stabilizer_subgroups(S, X, a) + sage: _stabilizer_subgroups(S, X, a, side='left') [Permutation Group with generators [(1,4), (1,3,4)], Permutation Group with generators [(1,3)(2,4), (1,4)]] @@ -766,19 +767,54 @@ def _stabilizer_subgroups(G, X, a): sage: S = SymmetricGroup([1,2,4,5,3,6]).young_subgroup([4, 2]) sage: X = [pi for pi in SetPartitions(6, [3,3]) if all(sum(1 for e in b if e % 3) == 2 for b in pi)] - sage: _stabilizer_subgroups(S, X, a) + sage: _stabilizer_subgroups(S, X, a, side='left') [Permutation Group with generators [(1,2), (4,5), (1,4)(2,5)(3,6)]] TESTS:: - sage: _stabilizer_subgroups(SymmetricGroup(2), [1], lambda pi, H: H) + sage: _stabilizer_subgroups(SymmetricGroup(2), [1], lambda pi, H: H, side='left') [Permutation Group with generators [(1,2)]] + + sage: _stabilizer_subgroups(SymmetricGroup(2), [1, 1], lambda pi, H: H, side='left') + Traceback (most recent call last): + ... + ValueError: The argument X must be a set, but [1, 1] contains duplicates + + sage: G = SymmetricGroup(3) + sage: X = [1, 2, 3] + sage: _stabilizer_subgroups(G, X, lambda pi, x: pi(x), side='left') + [Permutation Group with generators [(2,3)]] + sage: _stabilizer_subgroups(G, X, lambda x, pi: pi(x), side='right') + Traceback (most recent call last): + ... + ValueError: The given function is not a right group action: g=(1,3,2), h=(2,3), x=1 do not satisfy the condition """ to_gap = {x: i for i, x in enumerate(X, 1)} - X = set(X) # because orbit_decomposition turns X into a set - g_orbits = [orbit_decomposition(X, lambda x: a(g, x)) - for g in G.gens()] + X_set = set(X) # because orbit_decomposition turns X into a set + + if len(X_set) != len(X): + raise ValueError(f"The argument X must be a set, but {X} contains duplicates") + + if side == "left": + if check: + for g, h, x in product(G, G, X): + # Warning: the product in permutation groups is left-to-right composition + if not a(h * g, x) == a(g, a(h, x)): + raise ValueError(f"The given function is not a left group action: g={g}, h={h}, x={x} do not satisfy the condition") + + g_orbits = [orbit_decomposition(X_set, lambda x: a(g, x)) + for g in G.gens()] + elif side == "right": + if check: + for g, h, x in product(G, G, X): + if not a(x, h * g) == a(a(x, g), h): + raise ValueError(f"The given function is not a right group action: g={g}, h={h}, x={x} do not satisfy the condition") + + g_orbits = [orbit_decomposition(X_set, lambda x: a(x, g)) + for g in G.gens()] + else: + raise ValueError(f"The argument side must be 'left' or 'right' but is {side}") gens = [PermutationGroupElement([tuple([to_gap[x] for x in o]) for o in g_orbit]) @@ -834,7 +870,7 @@ def __init__(self, names): TESTS: - We have to exclude `_test_graded_components`, because + We have to exclude ``_test_graded_components``, because :meth:`~sage.combinat.integer_vector.IntegerVectors.some_elements` yields degrees that are too large:: @@ -873,13 +909,15 @@ def _element_constructor_(self, G, pi=None, check=True): INPUT: - ``G`` -- element of ``self`` (in this case ``pi`` must be - ``None``) permutation group, or pair ``(X, a)`` consisting - of a finite set and a transitive action + ``None``) or permutation group, or triple ``(X, a, side)`` + consisting of a finite set, a transitive action and + a string 'left' or 'right'; the side can be omitted, it is + then assumed to be 'right' - ``pi`` -- ``dict`` mapping sorts to iterables whose union is the domain of ``G`` (if ``G`` is a permutation group) or the domain of the acting symmetric group (if ``G`` is a - pair ``(X, a)``); if `k=1` and ``G`` is a permutation - group, ``pi`` can be omitted + triple ``(X, a, side)``); if `k=1` and ``G`` is a + permutation group, ``pi`` can be omitted - ``check`` -- boolean (default: ``True``); skip input checking if ``False`` @@ -901,11 +939,11 @@ def _element_constructor_(self, G, pi=None, check=True): sage: M = MolecularSpecies("X") sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x]) sage: X = SetPartitions(4, [2, 2]) - sage: M((X, a), {0: X.base_set()}) + sage: M((X, a, 'left'), {0: X.base_set()}) P_4 sage: X = SetPartitions(8, [4, 2, 2]) - sage: M((X, a), {0: X.base_set()}) + sage: M((X, a, 'left'), {0: X.base_set()}, check=False) E_4*P_4 TESTS:: @@ -922,7 +960,7 @@ def _element_constructor_(self, G, pi=None, check=True): sage: X = SetPartitions(4, 2) sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x]) - sage: M((X, a), {0: [1,2], 1: [3,4]}) + sage: M((X, a, 'left'), {0: [1,2], 1: [3,4]}) Traceback (most recent call last): ... ValueError: action is not transitive @@ -962,18 +1000,25 @@ def _element_constructor_(self, G, pi=None, check=True): ... ValueError: 0 must be a permutation group or a pair (X, a) specifying a group action of the symmetric group on pi=None + """ if parent(G) is self: # pi cannot be None because of framework raise ValueError("cannot reassign sorts to a molecular species") if isinstance(G, tuple): - X, a = G + if len(G) == 2: + X, a = G + side = 'right' + else: + X, a, side = G + if side not in ['left', 'right']: + raise ValueError(f"the side must be 'right' or 'left', but is {side}") dompart = [sorted(pi.get(s, [])) for s in range(self._arity)] S = PermutationGroup([tuple(b) for b in dompart if len(b) > 2] + [(b[0], b[1]) for b in dompart if len(b) > 1], domain=list(chain(*dompart))) - H = _stabilizer_subgroups(S, X, a) + H = _stabilizer_subgroups(S, X, a, side=side, check=check) if len(H) > 1: raise ValueError("action is not transitive") G = H[0] @@ -1575,6 +1620,55 @@ def is_atomic(self): """ return self.is_molecular() and len(self.support()[0]) == 1 + def tilde(self): + r""" + Return the tilde species of ``self``. + + The tilde species `\tilde F` of a species `F` has as + structures the set of pairs `(s, a)`, consisting of an + `F`-structure `s` and an automorphism `a` of `s`. + + We use https://mathoverflow.net/a/480852 to compute it. + + EXAMPLES:: + + sage: from sage.rings.species import AtomicSpecies, MolecularSpecies, PolynomialSpecies + sage: M = MolecularSpecies("X") + sage: P = PolynomialSpecies(QQ, "X") + sage: sortkey = lambda x: (len(x[1]), sum(x[1].coefficients()), str(x[0])) + sage: n=4; table(sorted([(m, P.monomial(m).tilde()) for m in M.subset(n)], key=sortkey)) + X^4 X^4 + X^2*E_2 2*X^2*E_2 + {((1,2)(3,4),)} 2*{((1,2)(3,4),)} + X*C_3 3*X*C_3 + C_4 4*C_4 + E_2^2 4*E_2^2 + Pb_4 4*Pb_4 + X*E_3 X*E_3 + X^2*E_2 + X*C_3 + Eo_4 Eo_4 + 2*X*C_3 + Pb_4 + P_4 2*P_4 + E_2^2 + Pb_4 + C_4 + E_4 E_4 + E_2^2 + X*C_3 + P_4 + C_4 + + sage: P. = PolynomialSpecies(QQ) + sage: E2 = PolynomialSpecies(QQ, "X")(SymmetricGroup(2)) + sage: E2(X*Y).tilde() + 2*E_2(XY) + """ + P = self.parent() + M = P._indices + P_one = P.one() + one = ZZ.one() + result = P.zero() + for m, c in self: + result_m = P_one + for a, e in m: + G, pi = a.permutation_group() + result_a = P.sum(P(G.centralizer(g), pi) + for g in G.conjugacy_classes_representatives()) + result_m *= result_a ** e + result += c * result_m + return result + def hadamard_product(self, other): r""" Compute the hadamard product of ``self`` and ``other``. @@ -2072,8 +2166,10 @@ def _element_constructor_(self, G, pi=None, check=True): INPUT: - ``G`` -- element of ``self`` (in this case ``pi`` must be - ``None``), permutation group, or pair ``(X, a)`` consisting - of a finite set and an action + ``None``) or permutation group, or triple ``(X, a, side)`` + consisting of a finite set, an action and a string 'left' + or 'right'; the side can be omitted, it is then assumed to + be 'right' - ``pi`` -- ``dict`` mapping sorts to iterables whose union is the domain of ``G`` (if ``G`` is a permutation group) or the domain of the acting symmetric group (if ``G`` is a @@ -2091,13 +2187,13 @@ def _element_constructor_(self, G, pi=None, check=True): sage: X = SetPartitions(4, 2) sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x]) - sage: P((X, a), {0: [1,2], 1: [3,4]}) + sage: P((X, a, 'left'), {0: [1,2], 1: [3,4]}) E_2(X)*E_2(Y) + X^2*E_2(Y) + E_2(XY) + Y^2*E_2(X) sage: P = PolynomialSpecies(ZZ, ["X"]) sage: X = SetPartitions(4, 2) sage: a = lambda g, x: SetPartition([[g(e) for e in b] for b in x]) - sage: P((X, a), {0: [1,2,3,4]}) + sage: P((X, a, 'left'), {0: [1,2,3,4]}) X*E_3 + P_4 The species of permutation groups:: @@ -2106,10 +2202,10 @@ def _element_constructor_(self, G, pi=None, check=True): sage: n = 4 sage: S = SymmetricGroup(n) sage: X = S.subgroups() - sage: def act(pi, G): # WARNING: returning H does not work because of equality problems + sage: def act(G, pi): # WARNING: returning H does not work because of equality problems ....: H = S.subgroup(G.conjugate(pi).gens()) ....: return next(K for K in X if K == H) - sage: P((X, act), {0: range(1, n+1)}) + sage: P((X, act), {0: range(1, n+1)}, check=False) 4*E_4 + 4*P_4 + E_2^2 + 2*X*E_3 Create a multisort species given an action:: @@ -2127,7 +2223,7 @@ def _element_constructor_(self, G, pi=None, check=True): ....: if r == t and c == b: ....: return r, c ....: raise ValueError - sage: P((X, lambda g, x: act(x[0], x[1], g)), pi) + sage: P((X, lambda g, x: act(x[0], x[1], g), 'left'), pi) 2*Y*E_2(X) TESTS:: @@ -2157,18 +2253,25 @@ def _element_constructor_(self, G, pi=None, check=True): ValueError: 1/2 must be an element of the base ring, a permutation group or a pair (X, a) specifying a group action of the symmetric group on pi=None + """ if parent(G) is self: # pi cannot be None because of framework raise ValueError("cannot reassign sorts to a polynomial species") if isinstance(G, tuple): - X, a = G + if len(G) == 2: + X, a = G + side = 'right' + else: + X, a, side = G + if side not in ['left', 'right']: + raise ValueError(f"the side must be 'right' or 'left', but is {side}") dompart = [sorted(pi.get(s, [])) for s in range(self._arity)] S = PermutationGroup([tuple(b) for b in dompart if len(b) > 2] + [(b[0], b[1]) for b in dompart if len(b) > 1], domain=list(chain(*dompart))) - Hs = _stabilizer_subgroups(S, X, a) + Hs = _stabilizer_subgroups(S, X, a, side=side, check=check) return self.sum_of_terms((self._indices(H, pi, check=check), ZZ.one()) for H in Hs) diff --git a/src/sage/rings/tate_algebra.py b/src/sage/rings/tate_algebra.py index d80060696be..43223432650 100644 --- a/src/sage/rings/tate_algebra.py +++ b/src/sage/rings/tate_algebra.py @@ -613,9 +613,9 @@ def ngens(self): """ return self._ngens - def gens(self): + def gens(self) -> tuple: r""" - Return the list of generators of this monoid of terms. + Return the generators of this monoid of terms. EXAMPLES:: @@ -934,9 +934,9 @@ def gen(self, n=0): except IndexError: raise ValueError("generator not defined") - def gens(self): + def gens(self) -> tuple: r""" - Return the list of generators of this Tate algebra. + Return the generators of this Tate algebra. EXAMPLES:: diff --git a/src/sage/rings/tate_algebra_element.pxd b/src/sage/rings/tate_algebra_element.pxd index 3cafe330fb0..a1566f0e053 100644 --- a/src/sage/rings/tate_algebra_element.pxd +++ b/src/sage/rings/tate_algebra_element.pxd @@ -46,4 +46,3 @@ cdef class TateAlgebraElement(CommutativeAlgebraElement): cdef _quo_rem_c(self, list divisors, bint quo, bint rem, bint integral) cdef _quo_rem_check(self, divisors, bint quo, bint rem) cdef TateAlgebraElement _Spoly_c(self, TateAlgebraElement other) - diff --git a/src/sage/rings/tests.py b/src/sage/rings/tests.py index 3796ef7b276..09e0d585078 100644 --- a/src/sage/rings/tests.py +++ b/src/sage/rings/tests.py @@ -501,4 +501,3 @@ def test_karatsuba_multiplication(base_ring, maxdeg1, maxdeg2, msg += "and\n" msg += f"{sage_input(g)}" raise ValueError(msg) - return diff --git a/src/sage/rings/valuation/augmented_valuation.py b/src/sage/rings/valuation/augmented_valuation.py index b9f0229f787..5b4666d45cb 100644 --- a/src/sage/rings/valuation/augmented_valuation.py +++ b/src/sage/rings/valuation/augmented_valuation.py @@ -538,8 +538,8 @@ def extensions(self, ring): if ring is self.domain(): return [self] - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if isinstance(ring, PolynomialRing_general): # univariate + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic): # univariate base_valuations = self._base_valuation.extensions(ring) phi = self.phi().change_ring(ring.base_ring()) @@ -578,8 +578,8 @@ def restriction(self, ring): base = self._base_valuation.restriction(ring) if ring.is_subring(self.domain().base_ring()): return base - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if isinstance(ring, PolynomialRing_general): # univariate + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic): # univariate return base.augmentation(self.phi().change_ring(ring.base_ring()), self._mu) return super().restriction(ring) @@ -790,8 +790,8 @@ def change_domain(self, ring): sage: v.change_domain(QQ['x']) [ Gauss valuation induced by 2-adic valuation, v(x) = 1 ] """ - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if isinstance(ring, PolynomialRing_general) and ring.variable_name() == self.domain().variable_name(): + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic) and ring.variable_name() == self.domain().variable_name(): return self._base_valuation.change_domain(ring).augmentation(self.phi().change_ring(ring.base_ring()), self._mu, check=False) return super().change_domain(ring) diff --git a/src/sage/rings/valuation/developing_valuation.py b/src/sage/rings/valuation/developing_valuation.py index 8b77224f591..a73130c9cea 100644 --- a/src/sage/rings/valuation/developing_valuation.py +++ b/src/sage/rings/valuation/developing_valuation.py @@ -81,8 +81,8 @@ def __init__(self, parent, phi): DiscretePseudoValuation.__init__(self, parent) domain = parent.domain() - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if not isinstance(domain, PolynomialRing_general) or not domain.ngens() == 1: + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if not isinstance(domain, PolynomialRing_generic) or not domain.ngens() == 1: raise TypeError("domain must be a univariate polynomial ring but %r is not" % (domain,)) phi = domain.coerce(phi) diff --git a/src/sage/rings/valuation/gauss_valuation.py b/src/sage/rings/valuation/gauss_valuation.py index 0e867e0a2f5..4fc1c555a79 100644 --- a/src/sage/rings/valuation/gauss_valuation.py +++ b/src/sage/rings/valuation/gauss_valuation.py @@ -88,8 +88,8 @@ def create_key(self, domain, v=None): ... ValueError: the domain of v must be the base ring of domain but 2-adic valuation is not defined over Integer Ring but over Rational Field """ - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if not isinstance(domain, PolynomialRing_general): + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if not isinstance(domain, PolynomialRing_generic): raise TypeError("GaussValuations can only be created over polynomial rings but %r is not a polynomial ring" % (domain,)) if not domain.ngens() == 1: raise NotImplementedError("domain must be univariate but %r is not univariate" % (domain,)) @@ -509,8 +509,8 @@ def change_domain(self, ring): sage: w.change_domain(QQ['x']) Gauss valuation induced by 2-adic valuation """ - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if isinstance(ring, PolynomialRing_general) and ring.ngens() == 1: + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic) and ring.ngens() == 1: base_valuation = self._base_valuation.change_domain(ring.base_ring()) return GaussValuation(self.domain().change_ring(ring.base_ring()), base_valuation) return super().change_domain(ring) @@ -527,8 +527,8 @@ def extensions(self, ring): sage: w.extensions(GaussianIntegers()['x']) # needs sage.rings.number_field [Gauss valuation induced by 2-adic valuation] """ - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if isinstance(ring, PolynomialRing_general) and ring.ngens() == 1: + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic) and ring.ngens() == 1: if self.domain().is_subring(ring): return [GaussValuation(ring, w) for w in self._base_valuation.extensions(ring.base_ring())] return super().extensions(ring) @@ -547,8 +547,8 @@ def restriction(self, ring): """ if ring.is_subring(self.domain().base_ring()): return self._base_valuation.restriction(ring) - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if isinstance(ring, PolynomialRing_general) and ring.ngens() == 1: + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic) and ring.ngens() == 1: if ring.base().is_subring(self.domain().base()): return GaussValuation(ring, self._base_valuation.restriction(ring.base())) return super().restriction(ring) diff --git a/src/sage/rings/valuation/limit_valuation.py b/src/sage/rings/valuation/limit_valuation.py index 86a64d23f99..19e5c71e95c 100644 --- a/src/sage/rings/valuation/limit_valuation.py +++ b/src/sage/rings/valuation/limit_valuation.py @@ -409,8 +409,8 @@ def extensions(self, ring): """ if self.domain() is ring: return [self] - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if isinstance(ring, PolynomialRing_general) and self.domain().base_ring().is_subring(ring.base_ring()): + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ring, PolynomialRing_generic) and self.domain().base_ring().is_subring(ring.base_ring()): if self.domain().base_ring().fraction_field() is ring.base_ring(): return [LimitValuation(self._initial_approximation.change_domain(ring), self._G.change_ring(ring.base_ring()))] @@ -661,8 +661,8 @@ def residue_ring(self): # the approximation ends in v(phi)=infty return R else: - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - assert (isinstance(R, PolynomialRing_general)) + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + assert (isinstance(R, PolynomialRing_generic)) return R.base_ring() def _ge_(self, other): diff --git a/src/sage/rings/valuation/valuation.py b/src/sage/rings/valuation/valuation.py index 2deeb100ffc..60c9df824e9 100644 --- a/src/sage/rings/valuation/valuation.py +++ b/src/sage/rings/valuation/valuation.py @@ -395,7 +395,7 @@ def mac_lane_approximants(self, G, assume_squarefree=False, require_final_EF=Tru - ``require_final_EF`` -- boolean (default: ``True``); whether to require the returned key polynomials to be in one-to-one - correspondance to the extensions of this valuation to ``L`` and + correspondence to the extensions of this valuation to ``L`` and require them to have the ramification index and residue degree of the valuations they correspond to. @@ -770,7 +770,7 @@ def reduce_tree(v, w): reduce_init=[]).run_serial() else: raise NotImplementedError(algorithm) - leafs = set([node.valuation for node in nodes]) + leafs = {node.valuation for node in nodes} for node in nodes: if node.parent is None: continue diff --git a/src/sage/rings/valuation/valuation_space.py b/src/sage/rings/valuation/valuation_space.py index 24e5f598624..7736f787600 100644 --- a/src/sage/rings/valuation/valuation_space.py +++ b/src/sage/rings/valuation/valuation_space.py @@ -515,8 +515,8 @@ def residue_field(self): from sage.categories.fields import Fields if ret in Fields(): return ret - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general - if isinstance(ret, PolynomialRing_general): + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic + if isinstance(ret, PolynomialRing_generic): from sage.rings.function_field.constructor import FunctionField return FunctionField(ret.base_ring().fraction_field(), names=(ret.variable_name(),)) return ret.fraction_field() @@ -1214,14 +1214,16 @@ def _test_mul(self, **options): sage: v = QQ.valuation(5) sage: v._test_mul() """ + from sage.rings.infinity import infinity + from itertools import product tester = self._tester(**options) S = self.domain().some_elements() - from itertools import product + infis = {infinity, -infinity} + for x, y in tester.some_elements(product(S, S)): - from sage.rings.infinity import infinity - if set([self(x), self(y)]) == set([infinity, -infinity]): + if {Sx := self(x), Sy := self(y)} == infis: continue - tester.assertEqual(self(x * y), self(x) + self(y)) + tester.assertEqual(self(x * y), Sx + Sy) def _test_no_infinite_units(self, **options): r""" diff --git a/src/sage/rings/valuation/value_group.py b/src/sage/rings/valuation/value_group.py index f3afd30c413..77b1178922e 100644 --- a/src/sage/rings/valuation/value_group.py +++ b/src/sage/rings/valuation/value_group.py @@ -439,7 +439,7 @@ def __classcall__(cls, generators): """ if generators in QQ: generators = [generators] - generators = list(set([QQ.coerce(g) for g in generators if g != 0])) + generators = list({QQ.coerce(g) for g in generators if g != 0}) generators.sort() simplified_generators = generators @@ -450,7 +450,7 @@ def __classcall__(cls, generators): if g == h: continue from sage.rings.semirings.non_negative_integer_semiring import NN - if h/g in NN: + if h / g in NN: simplified_generators.remove(h) break @@ -624,7 +624,7 @@ def _mul_(self, other, switch_sides=False): other = QQ.coerce(other) return DiscreteValueSemigroup([g*other for g in self._generators]) - def gens(self): + def gens(self) -> tuple: r""" Return the generators of this semigroup. diff --git a/src/sage/sandpiles/sandpile.py b/src/sage/sandpiles/sandpile.py index 6fb9720b945..6d685bcd6b7 100644 --- a/src/sage/sandpiles/sandpile.py +++ b/src/sage/sandpiles/sandpile.py @@ -318,7 +318,7 @@ # Copyright (C) 2011 David Perkinson # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ # **************************************************************************** from collections import Counter @@ -525,10 +525,10 @@ def __init__(self, g, sink=None): EXAMPLES: - Below, ``g`` represents a square with directed, multiple edges with three - vertices, ``a``, ``b``, ``c``, and ``d``. The vertex ``a`` has - outgoing edges to itself (weight 2), to vertex ``b`` (weight 1), and - vertex ``c`` (weight 3), for example. + Below, ``g`` represents a square with directed, multiple edges + with three vertices, ``a``, ``b``, ``c``, and ``d``. + The vertex ``a`` has outgoing edges to itself (weight 2), to + vertex ``b`` (weight 1), and vertex ``c`` (weight 3), for example. :: @@ -552,7 +552,9 @@ def __init__(self, g, sink=None): [-1 -2 3 0] [ 0 0 0 0] sage: s.dict() - {0: {1: 1, 2: 1, 3: 1}, 1: {0: 1, 1: 1, 2: 3}, 2: {0: 1, 1: 2, 2: 4}} + {0: {1: 1, 2: 1, 3: 1}, + 1: {0: 1, 1: 1, 2: 3}, + 2: {0: 1, 1: 2, 2: 4}} Sandpiles can be created from Graphs and DiGraphs. :: @@ -571,14 +573,16 @@ def __init__(self, g, sink=None): .. NOTE:: - Loops are allowed. There are four admissible input formats. Two of - these are dictionaries whose keys are the vertex names. In one, the - values are dictionaries with keys the names of vertices which are the - heads of outgoing edges and with values the weights of the edges. In - the other format, the values are lists of names of vertices which are - the heads of the outgoing edges, with weights determined by the number - of times a name of a vertex appears in the list. Both Graphs and - DiGraphs can also be used as inputs. + Loops are allowed. There are four admissible input + formats. Two of these are dictionaries whose keys are the + vertex names. In one, the values are dictionaries with + keys the names of vertices which are the heads of outgoing + edges and with values the weights of the edges. In the + other format, the values are lists of names of vertices + which are the heads of the outgoing edges, with weights + determined by the number of times a name of a vertex + appears in the list. Both Graphs and DiGraphs can also be + used as inputs. TESTS:: @@ -678,71 +682,71 @@ def __getattr__(self, name): if name == '_max_stable_div': self._set_max_stable_div() return deepcopy(self.__dict__[name]) - elif name == '_out_degrees': + if name == '_out_degrees': self._set_out_degrees() return deepcopy(self.__dict__[name]) - elif name == '_in_degrees': + if name == '_in_degrees': self._set_in_degrees() return deepcopy(self.__dict__[name]) - elif name == '_burning_config' or name == '_burning_script': + if name in ['_burning_config', '_burning_script']: self._set_burning_config() return deepcopy(self.__dict__[name]) - elif name == '_identity': + if name == '_identity': self._set_identity() return deepcopy(self.__dict__[name]) - elif name == '_recurrents': + if name == '_recurrents': self._set_recurrents() return deepcopy(self.__dict__[name]) - elif name == '_min_recurrents': + if name == '_min_recurrents': self._set_min_recurrents() return deepcopy(self.__dict__[name]) - elif name == '_superstables': + if name == '_superstables': self._set_superstables() return deepcopy(self.__dict__[name]) - elif name == '_group_gens': + if name == '_group_gens': self._set_group_gens() return deepcopy(self.__dict__[name]) elif name == '_group_order': self.__dict__[name] = det(self._reduced_laplacian.dense_matrix()) return self.__dict__[name] - elif name == '_invariant_factors': + if name == '_invariant_factors': self._set_invariant_factors() return deepcopy(self.__dict__[name]) - elif name == '_smith_form': + if name == '_smith_form': self._set_smith_form() return deepcopy(self.__dict__[name]) - elif name == '_jacobian_representatives': + if name == '_jacobian_representatives': self._set_jacobian_representatives() return deepcopy(self.__dict__[name]) - elif name == '_avalanche_polynomial': + if name == '_avalanche_polynomial': self._set_avalanche_polynomial() return deepcopy(self.__dict__[name]) - elif name == '_stationary_density': + if name == '_stationary_density': self._set_stationary_density() return self.__dict__[name] - elif name == '_betti_complexes': + if name == '_betti_complexes': self._set_betti_complexes() return deepcopy(self.__dict__[name]) elif name in ['_postulation', '_h_vector', '_hilbert_function']: self._set_hilbert_function() return deepcopy(self.__dict__[name]) - elif (name == '_ring' or name == '_unsaturated_ideal'): + if name in ['_ring', '_unsaturated_ideal']: self._set_ring() return self.__dict__[name] - elif name == '_ideal': + if name == '_ideal': self._set_ideal() return self.__dict__[name] - elif name in ['_resolution', '_betti', '_singular_resolution']: + if name in ['_resolution', '_betti', '_singular_resolution']: self._set_resolution() return self.__dict__[name] - elif name == '_groebner': + if name == '_groebner': self._set_groebner() return self.__dict__[name] - elif name == '_points': + if name == '_points': self._set_points() return self.__dict__[name] - else: - raise AttributeError(name) + + raise AttributeError(name) def __str__(self) -> str: r""" @@ -762,7 +766,7 @@ def __str__(self) -> str: """ return self.name() - def _repr_(self): + def _repr_(self) -> str: r""" String representation of ``self``. @@ -803,7 +807,8 @@ def show3d(self, **kwds): INPUT: - - ``kwds`` -- (optional) arguments passed to the show method for Graph or DiGraph + - ``kwds`` -- (optional) arguments passed to the show method + for Graph or DiGraph EXAMPLES:: @@ -856,7 +861,9 @@ def sink(self): def laplacian(self): r""" - The Laplacian matrix of the graph. Its *rows* encode the vertex firing rules. + The Laplacian matrix of the graph. + + Its *rows* encode the vertex firing rules. OUTPUT: matrix @@ -1125,12 +1132,12 @@ def burning_config(self): nonnegative entries and such that every vertex has a path from some vertex in its support. The corresponding *burning script* gives the integer-linear combination needed to obtain the burning - configuration. So if `b` is the burning configuration, `\sigma` is its - script, and `\tilde{L}` is the reduced Laplacian, then `\sigma\cdot - \tilde{L} = b`. The *minimal burning configuration* is the one - with the minimal script (its components are no larger than the - components of any other script - for a burning configuration). + configuration. So if `b` is the burning configuration, `\sigma` + is its script, and `\tilde{L}` is the reduced Laplacian, + then `\sigma\cdot \tilde{L} = b`. The *minimal burning + configuration* is the one with the minimal script (its + components are no larger than the components of any other + script for a burning configuration). The following are equivalent for a configuration `c` with burning configuration `b` having script `\sigma`: @@ -1266,7 +1273,9 @@ def _set_identity(self): def identity(self, verbose=True): r""" - The identity configuration. If ``verbose`` is ``False``, the + The identity configuration. + + If ``verbose`` is ``False``, the configuration is converted to a list of integers. INPUT: @@ -1339,7 +1348,9 @@ def recurrents(self, verbose=True): sage: r = Sandpile(graphs.HouseXGraph(),0).recurrents() sage: r[:3] - [{1: 2, 2: 3, 3: 3, 4: 1}, {1: 1, 2: 3, 3: 3, 4: 0}, {1: 1, 2: 3, 3: 3, 4: 1}] + [{1: 2, 2: 3, 3: 3, 4: 1}, + {1: 1, 2: 3, 3: 3, 4: 0}, + {1: 1, 2: 3, 3: 3, 4: 1}] sage: sandpiles.Complete(4).recurrents(False) # needs sage.combinat [[2, 2, 2], [2, 2, 1], @@ -1395,7 +1406,9 @@ def superstables(self, verbose=True): sage: sp = Sandpile(graphs.HouseXGraph(),0).superstables() sage: sp[:3] - [{1: 0, 2: 0, 3: 0, 4: 0}, {1: 1, 2: 0, 3: 0, 4: 1}, {1: 1, 2: 0, 3: 0, 4: 0}] + [{1: 0, 2: 0, 3: 0, 4: 0}, + {1: 1, 2: 0, 3: 0, 4: 1}, + {1: 1, 2: 0, 3: 0, 4: 0}] sage: sandpiles.Complete(4).superstables(False) # needs sage.combinat [[0, 0, 0], [0, 0, 1], @@ -1437,9 +1450,11 @@ def _set_group_gens(self): self._group_gens = [SandpileConfig(self, [Integer(j) for j in F.column(i)]).equivalent_recurrent() for i in range(F.nrows()) if D[i][i] != 1] - def group_gens(self, verbose=True): + def group_gens(self, verbose=True) -> list: r""" - A minimal list of generators for the sandpile group. If ``verbose`` is ``False`` + A minimal list of generators for the sandpile group. + + If ``verbose`` is ``False`` then the generators are represented as lists of integers. INPUT: @@ -1448,7 +1463,8 @@ def group_gens(self, verbose=True): OUTPUT: - list of SandpileConfig (or of lists of integers if ``verbose`` is ``False``) + list of SandpileConfig + (or of lists of integers if ``verbose`` is ``False``) EXAMPLES:: @@ -1683,7 +1699,7 @@ def avalanche_polynomial(self, multivariable=True): return self._avalanche_polynomial.subs({X[i]: X[0] for i in range(1, self.num_verts() - 1)}) - def nonspecial_divisors(self, verbose=True): + def nonspecial_divisors(self, verbose=True) -> list: r""" The nonspecial divisors. Only for undirected graphs. (See NOTE.) @@ -1708,11 +1724,12 @@ def nonspecial_divisors(self, verbose=True): .. NOTE:: - The "nonspecial divisors" are those divisors of degree `g-1` with - empty linear system. The term is only defined for undirected graphs. - Here, `g = |E| - |V| + 1` is the genus of the graph (not counting loops - as part of `|E|`). If ``verbose`` is ``False``, the divisors are converted - to lists of integers. + The "nonspecial divisors" are those divisors of degree + `g-1` with empty linear system. The term is only defined + for undirected graphs. Here, `g = |E| - |V| + 1` is the + genus of the graph (not counting loops as part of `|E|`). + If ``verbose`` is ``False``, the divisors are converted to + lists of integers. .. WARNING:: @@ -1750,7 +1767,8 @@ def canonical_divisor(self): The underlying graph must be undirected. """ if self.is_undirected(): - return SandpileDivisor(self, [self.laplacian()[i][i] - 2 for i in range(self.num_verts())]) + return SandpileDivisor(self, [self.laplacian()[i][i] - 2 + for i in range(self.num_verts())]) raise TypeError("only for undirected graphs") def _set_invariant_factors(self): @@ -1868,7 +1886,7 @@ def _set_smith_form(self): """ self._smith_form = self.laplacian().transpose().smith_form() - def smith_form(self): + def smith_form(self) -> list: r""" The Smith normal form for the Laplacian. In detail: a list of integer matrices `D, U, V` such that `ULV = D` where `L` is the transpose of the @@ -2000,7 +2018,7 @@ def jacobian_representatives(self, verbose=True): [{0: -5, 1: 3, 2: 2}, {0: -4, 1: 3, 2: 1}] Let `\tau` be the nonnegative generator of the kernel of the transpose of - the Laplacian, and let `tau_s` be it sink component, then the sandpile + the Laplacian, and let `\tau_s` be its sink component, then the sandpile group is isomorphic to the direct sum of the cyclic group of order `\tau_s` and the Jacobian group. In the example above, we have:: @@ -2011,8 +2029,8 @@ def jacobian_representatives(self, verbose=True): .. NOTE:: - The Jacobian group is the set of all divisors of degree zero modulo the - integer rowspan of the Laplacian matrix. + The Jacobian group is the set of all divisors of degree + zero modulo the integer rowspan of the Laplacian matrix. """ if verbose: return deepcopy(self._jacobian_representatives) @@ -2021,8 +2039,9 @@ def jacobian_representatives(self, verbose=True): def picard_representatives(self, d, verbose=True): r""" - Representatives of the divisor classes of degree `d` in the Picard group. (Also - see the documentation for ``jacobian_representatives``.) + Representatives of the divisor classes of degree `d` in the Picard group. + + (Also see the documentation for ``jacobian_representatives``.) INPUT: @@ -2051,10 +2070,12 @@ def picard_representatives(self, d, verbose=True): def stable_configs(self, smax=None): r""" - Generator for all stable configurations. If ``smax`` is provided, then - the generator gives all stable configurations less than or equal to - ``smax``. If ``smax`` does not represent a stable configuration, then each - component of ``smax`` is replaced by the corresponding component of the + Generator for all stable configurations. + + If ``smax`` is provided, then the generator gives all stable + configurations less than or equal to ``smax``. If ``smax`` + does not represent a stable configuration, then each component + of ``smax`` is replaced by the corresponding component of the maximal stable configuration. INPUT: @@ -2079,8 +2100,9 @@ def stable_configs(self, smax=None): smax = self.max_stable().values() else: c = SandpileConfig(self, smax) - if not c <= self.max_stable(): - smax = [min(c[v], self.max_stable()[v]) for v in self.nonsink_vertices()] + if c > self.max_stable(): + smax = [min(c[v], self.max_stable()[v]) + for v in self.nonsink_vertices()] else: smax = c.values() for c in IntegerVectorsIterator(smax): @@ -2145,20 +2167,25 @@ def markov_chain(self, state, distrib=None): .. NOTE:: - The ``closed sandpile Markov chain`` has state space consisting of the configurations - on a sandpile. It transitions from a state by choosing a vertex at random - (according to the probability distribution ``distrib``), dropping a grain of sand at - that vertex, and stabilizing. If the chosen vertex is the sink, the chain stays - at the current state. - - The ``open sandpile Markov chain`` has state space consisting of the recurrent elements, - i.e., the state space is the sandpile group. It transitions from the configuration `c` - by choosing a vertex `v` at random according to ``distrib``. The next state is the - stabilization of `c+v`. If `v` is the sink vertex, then the stabilization of `c+v` - is defined to be `c`. - - Note that in either case, if ``distrib`` is specified, its length is equal to - the total number of vertices (including the sink). + The ``closed sandpile Markov chain`` has state space + consisting of the configurations on a sandpile. It + transitions from a state by choosing a vertex at random + (according to the probability distribution ``distrib``), + dropping a grain of sand at that vertex, and stabilizing. + If the chosen vertex is the sink, the chain stays at the + current state. + + The ``open sandpile Markov chain`` has state space + consisting of the recurrent elements, i.e., the state + space is the sandpile group. It transitions from the + configuration `c` by choosing a vertex `v` at random + according to ``distrib``. The next state is the + stabilization of `c+v`. If `v` is the sink vertex, then + the stabilization of `c+v` is defined to be `c`. + + Note that in either case, if ``distrib`` is specified, its + length is equal to the total number of vertices (including + the sink). REFERENCES: @@ -2248,9 +2275,9 @@ def stationary_density(self): .. NOTE:: - The stationary density of a sandpile is the sum `\sum_c (\deg(c) + \deg(s))` - where `\deg(s)` is the degree of the sink and the sum is over all - recurrent configurations. + The stationary density of a sandpile is the sum `\sum_c + (\deg(c) + \deg(s))` where `\deg(s)` is the degree of the + sink and the sum is over all recurrent configurations. REFERENCES: @@ -2308,16 +2335,17 @@ def _set_betti_complexes(self): r = self.recurrents() for D in r: d = D.deg() - # change D to a dict since SandpileConfig will not allow adding a key - D = dict(D) - D[self.sink()] = -d - D = SandpileDivisor(self, D) + # change D to a dict since SandpileConfig will not allow + # adding a key + dD = dict(D) + dD[self.sink()] = -d + sD = SandpileDivisor(self, dD) test = True while test: - D[self.sink()] += 1 - complex = D.Dcomplex() + sD[self.sink()] += 1 + complex = sD.Dcomplex() if sum(complex.betti().values()) > 1: # change from 0 to 1 - results.append([deepcopy(D), complex]) + results.append([deepcopy(sD), complex]) if len(complex.maximal_faces()) == 1 and list(complex.maximal_faces()[0]) == verts: test = False self._betti_complexes = results @@ -2529,9 +2557,10 @@ def _set_resolution(self): def resolution(self, verbose=False): r""" - A minimal free resolution of the homogeneous toppling ideal. If - ``verbose`` is ``True``, then all of the mappings are returned. - Otherwise, the resolution is summarized. + A minimal free resolution of the homogeneous toppling ideal. + + If ``verbose`` is ``True``, then all of the mappings are + returned. Otherwise, the resolution is summarized. INPUT: @@ -2756,8 +2785,9 @@ def symmetric_recurrents(self, orbits): .. NOTE:: - The user is responsible for ensuring that the list of orbits comes from - a group of symmetries of the underlying graph. + The user is responsible for ensuring that the list of + orbits comes from a group of symmetries of the underlying + graph. """ sym_recurrents = [] active = [self._max_stable] @@ -2784,7 +2814,9 @@ class SandpileConfig(dict): @staticmethod def help(verbose=True): r""" - List of SandpileConfig methods. If ``verbose``, include short descriptions. + List of SandpileConfig methods. + + If ``verbose``, include short descriptions. INPUT: @@ -2920,8 +2952,9 @@ def __setitem__(self, key, item): .. NOTE:: - In the example, above, changing the value of ``c`` at some vertex makes - a call to setitem, which resets some of the stored variables for ``c``. + In the example, above, changing the value of ``c`` at some + vertex makes a call to setitem, which resets some of the + stored variables for ``c``. """ if key in self: dict.__setitem__(self, key, item) @@ -3086,7 +3119,8 @@ def __neg__(self): sage: -c {1: -1, 2: -2} """ - return SandpileConfig(self._sandpile, [-self[v] for v in self._vertices]) + return SandpileConfig(self._sandpile, + [-self[v] for v in self._vertices]) # recurrent addition or multiplication on the right by an integer def __mul__(self, other): @@ -3123,7 +3157,8 @@ def __mul__(self, other): if isinstance(other, SandpileConfig): return (self+other).equivalent_recurrent() if isinstance(other, Integer): - return SandpileConfig(self.sandpile(), [other*i for i in self.values()]) + return SandpileConfig(self.sandpile(), + [other*i for i in self.values()]) raise TypeError(other) def __rmul__(self, other): @@ -3149,7 +3184,7 @@ def __rmul__(self, other): """ return SandpileConfig(self.sandpile(), [other*i for i in self.values()]) - def __le__(self, other): + def __le__(self, other) -> bool: r""" Return ``True`` if every component of ``self`` is at most that of ``other``. @@ -3179,7 +3214,7 @@ def __le__(self, other): """ return all(self[v] <= other[v] for v in self._vertices) - def __lt__(self, other): + def __lt__(self, other) -> bool: r""" Return ``True`` if every component of ``self`` is at most that of ``other`` and the two configurations are not equal. @@ -3204,7 +3239,7 @@ def __lt__(self, other): """ return self <= other and self != other - def __ge__(self, other): + def __ge__(self, other) -> bool: r""" Return ``True`` if every component of ``self`` is at least that of ``other``. @@ -3234,7 +3269,7 @@ def __ge__(self, other): """ return all(self[v] >= other[v] for v in self._vertices) - def __gt__(self, other): + def __gt__(self, other) -> bool: r""" Return ``True`` if every component of ``self`` is at least that of ``other`` and the two configurations are not equal. @@ -3352,8 +3387,6 @@ def values(self): OUTPUT: list of integers - boolean - EXAMPLES:: sage: S = Sandpile({'a':['c','b'], 'b':['c','a'], 'c':['a']},'a') @@ -3444,7 +3477,7 @@ def fire_script(self, sigma): c[e[1]] += sigma[i]*e[2] return SandpileConfig(self._sandpile, c) - def unstable(self): + def unstable(self) -> list: r""" The unstable vertices. @@ -3457,8 +3490,8 @@ def unstable(self): sage: c.unstable() [2, 3] """ - return [v for v in self._vertices if - self[v] >= self._sandpile.out_degree(v)] + return [v for v in self._vertices + if self[v] >= self._sandpile.out_degree(v)] def fire_unstable(self): r""" @@ -3576,13 +3609,17 @@ def support(self): def add_random(self, distrib=None): r""" - Add one grain of sand to a random vertex. Optionally, a probability - distribution, ``distrib``, may be placed on the vertices or the nonsink vertices. + Add one grain of sand to a random vertex. + + Optionally, a probability distribution, ``distrib``, may be + placed on the vertices or the nonsink vertices. + See NOTE for details. INPUT: - - ``distrib`` -- (optional) list of nonnegative numbers summing to 1 (representing a prob. dist.) + - ``distrib`` -- (optional) list of nonnegative numbers + summing to 1 (representing a prob. dist.) OUTPUT: SandpileConfig @@ -3998,7 +4035,7 @@ def show(self, sink=True, colors=True, heights=False, directed=None, **kwds): a[i] = str(i)+":"+str(self[i]) T.relabel(a) if colors: - vc = {} # vertex colors + vc: dict[str, list] = {} # vertex colors r = rainbow(max_height) # colors # noqa: F821 for i in range(max_height): vc[r[i]] = [] @@ -4305,7 +4342,7 @@ def __mul__(self, other): sage: 3*D == D*3 True """ - return SandpileDivisor(self.sandpile(),[i*other for i in self.values()]) + return SandpileDivisor(self.sandpile(), [i*other for i in self.values()]) def __rmul__(self, other): r""" @@ -4328,7 +4365,7 @@ def __rmul__(self, other): sage: 3*D == D*3 True """ - return SandpileDivisor(self.sandpile(),[other*i for i in self.values()]) + return SandpileDivisor(self.sandpile(), [other*i for i in self.values()]) def __radd__(self, other): r""" @@ -4604,7 +4641,7 @@ def fire_vertex(self, v): D[v] -= self._sandpile.out_degree(v) for e in self._sandpile.outgoing_edge_iterator(v): D[e[1]] += e[2] - return SandpileDivisor(self._sandpile,D) + return SandpileDivisor(self._sandpile, D) def fire_script(self, sigma): r""" @@ -4673,7 +4710,7 @@ def fire_unstable(self): D[v] -= self._sandpile.out_degree(v) for e in self._sandpile.outgoing_edge_iterator(v): D[e[1]] += e[2] - return SandpileDivisor(self._sandpile,D) + return SandpileDivisor(self._sandpile, D) def _set_q_reduced(self): r""" @@ -4688,11 +4725,11 @@ def _set_q_reduced(self): True """ S = self.sandpile() - c = SandpileConfig(S,[self[i] for i in S.nonsink_vertices()]) + c = SandpileConfig(S, [self[i] for i in S.nonsink_vertices()]) c = c.equivalent_superstable() - D = {v:c[v] for v in S.nonsink_vertices()} + D = {v: c[v] for v in S.nonsink_vertices()} D[S.sink()] = self.deg() - c.deg() - self._q_reduced = SandpileDivisor(S,D) + self._q_reduced = SandpileDivisor(S, D) def q_reduced(self, verbose=True): r""" @@ -4758,7 +4795,7 @@ def is_q_reduced(self): True """ S = self.sandpile() - c = SandpileConfig(S,[self[v] for v in S.nonsink_vertices()]) + c = SandpileConfig(S, [self[v] for v in S.nonsink_vertices()]) return c.is_superstable() def is_linearly_equivalent(self, D, with_firing_vector=False): @@ -4800,12 +4837,12 @@ def is_linearly_equivalent(self, D, with_firing_vector=False): """ # First try to convert D into a vector. v = vector(self.values()) - if isinstance(D,SandpileDivisor): + if isinstance(D, SandpileDivisor): w = vector(D.values()) else: w = vector(D) # Now test for linear equivalence and find firing vector - D,U,V = self.sandpile()._smith_form + D, U, V = self.sandpile()._smith_form b = v - w ub = U*b if ub[-1] != 0: @@ -4815,7 +4852,7 @@ def is_linearly_equivalent(self, D, with_firing_vector=False): return False else: try: - x = vector(ZZ,[ub[i]/D[i][i] for i in range(D.nrows()-1)]+[0]) + x = vector(ZZ, [ub[i]/D[i][i] for i in range(D.nrows()-1)]+[0]) if with_firing_vector: return V*x else: @@ -4903,7 +4940,7 @@ def _set_linear_system(self): mat_file.write(str(n)+' ') mat_file.write(str(n)+'\n') for r in L: - mat_file.write(''.join(map(str,r))) + mat_file.write(''.join(map(str, r))) mat_file.write('\n') # relations file with open(lin_sys_rel, 'w') as rel_file: @@ -4977,7 +5014,7 @@ def _set_polytope(self): """ S = self.sandpile() myL = S.laplacian().transpose().delete_columns([S._sink_ind]) - my_ieqs = [[self[v]] + list(-myL[i]) for i,v in enumerate(S.vertices(sort=True))] + my_ieqs = [[self[v]] + list(-myL[i]) for i, v in enumerate(S.vertices(sort=True))] self._polytope = Polyhedron(ieqs=my_ieqs) def polytope(self): @@ -5067,7 +5104,7 @@ def _set_effective_div(self): S = self.sandpile() myL = S.laplacian().transpose().delete_columns([S._sink_ind]) dv = vector(ZZ, self.values()) - self._effective_div = [SandpileDivisor(S,list(dv - myL*i)) + self._effective_div = [SandpileDivisor(S, list(dv - myL*i)) for i in self._polytope_integer_pts] def effective_div(self, verbose=True, with_firing_vectors=False): @@ -5193,14 +5230,14 @@ def _set_rank(self, set_witness=False): while k >= 0: rk += 1 try: - d = next(i for i,j in enumerate(c) if i == j and i != 0) + d = next(i for i, j in enumerate(c) if i == j and i != 0) except Exception: d = n - 1 k = k - d if k >= 0: c[0] = n - 1 - d - b1 = [c[i] + n - d for i in range(1,d)] - b2 = [c[i] - d for i in range(d,n-1)] + b1 = [c[i] + n - d for i in range(1, d)] + b2 = [c[i] - d for i in range(d, n-1)] c = b2 + [c[0]] + b1 self._rank = rk # All other cases. @@ -5319,10 +5356,10 @@ def _set_r_of_D(self, verbose=False): if w not in new_level: new_level.append(w) C = d - w - C = SandpileDivisor(self._sandpile,list(C)) + C = SandpileDivisor(self._sandpile, list(C)) eff = C.effective_div() if not eff: - self._r_of_D = (r, SandpileDivisor(self._sandpile,list(w))) + self._r_of_D = (r, SandpileDivisor(self._sandpile, list(w))) return level = new_level @@ -5355,7 +5392,7 @@ def weierstrass_rank_seq(self, v='sink'): verts = s.vertices(sort=True) Ei = s.zero_div() Ei[verts.index(v)] = 1 - Ei = SandpileDivisor(s,Ei) + Ei = SandpileDivisor(s, Ei) r = D.rank() seq = [r] while r != -1: @@ -5916,28 +5953,28 @@ def triangle_sandpile(n): sage: T.group_order() 135418115000 """ - T = {(-1, -1):{}} + T = {(-1, -1): {}} for i in range(n): for j in range(n-i): - T[(i,j)] = {} + T[(i, j)] = {} if i < n-j-1: - T[(i,j)][(i+1,j)] = 1 - T[(i,j)][(i,j+1)] = 1 + T[(i, j)][(i+1, j)] = 1 + T[(i, j)][(i, j+1)] = 1 if i > 0: - T[(i,j)][(i-1,j+1)] = 1 - T[(i,j)][(i-1,j)] = 1 + T[(i, j)][(i-1, j+1)] = 1 + T[(i, j)][(i-1, j)] = 1 if j > 0: - T[(i,j)][(i,j-1)] = 1 - T[(i,j)][(i+1,j-1)] = 1 - d = len(T[(i,j)]) + T[(i, j)][(i, j-1)] = 1 + T[(i, j)][(i+1, j-1)] = 1 + d = len(T[(i, j)]) if d < 6: - T[(i,j)][(-1, -1)] = 6-d + T[(i, j)][(-1, -1)] = 6-d T = Sandpile(T, (-1, -1)) pos = {} for x in T.nonsink_vertices(): coords = list(x) coords[0] += QQ(1)/2*coords[1] - pos[x] = coords + pos[x] = tuple(coords) pos[(-1, -1)] = (-1, -1) T.set_pos(pos) return T @@ -6206,7 +6243,7 @@ def admissible_partitions(S, k): yield p -def partition_sandpile(S, p): +def partition_sandpile(S, p) -> Sandpile: r""" Each set of vertices in `p` is regarded as a single vertex, with and edge between `A` and `B` if some element of `A` is connected by an edge to some @@ -6252,7 +6289,7 @@ def partition_sandpile(S, p): return Sandpile(g, i) -def min_cycles(G, v): +def min_cycles(G, v) -> list: r""" Minimal length cycles in the digraph `G` starting at vertex `v`. @@ -6271,9 +6308,8 @@ def min_cycles(G, v): sage: [min_cycles(T, i) for i in T.vertices(sort=True)] [[], [[1, 3]], [[2, 3, 1], [2, 3]], [[3, 1], [3, 2]]] """ - pr = G.neighbors_in(v) sp = G.shortest_paths(v) - return [sp[i] for i in pr if i in sp] + return [sp[i] for i in G.neighbor_in_iterator(v) if i in sp] def wilmes_algorithm(M): @@ -6289,6 +6325,7 @@ def wilmes_algorithm(M): EXAMPLES:: + sage: from sage.sandpiles.sandpile import wilmes_algorithm sage: P = matrix([[2,3,-7,-3],[5,2,-5,5],[8,2,5,4],[-5,-9,6,6]]) sage: wilmes_algorithm(P) [ 3279 -79 -1599 -1600] @@ -6303,13 +6340,12 @@ def wilmes_algorithm(M): # find the gcd of the row-sums, and perform the corresponding row # operations on M if M.matrix_over_field().is_invertible(): - L = deepcopy(M) - L = matrix(ZZ, L) + L = matrix(ZZ, M) U = matrix(ZZ, [sum(i) for i in L]).smith_form()[2].transpose() L = U*M for k in range(1, M.nrows()-1): - smith = matrix(ZZ, [i[k-1] for i in L[k:]]).smith_form()[2].transpose() - U = identity_matrix(ZZ, k).block_sum(smith) + sm = matrix(ZZ, [i[k-1] for i in L[k:]]).smith_form()[2].transpose() + U = identity_matrix(ZZ, k).block_sum(sm) L = U*L L[k] = -L[k] if L[-1][-2] > 0: diff --git a/src/sage/sat/boolean_polynomials.py b/src/sage/sat/boolean_polynomials.py index bad6b33d4d3..ab6567d37fb 100644 --- a/src/sage/sat/boolean_polynomials.py +++ b/src/sage/sat/boolean_polynomials.py @@ -303,7 +303,7 @@ def solve(F, converter=None, solver=None, n=1, target_variables=None, **kwds): if S[0] is None: return None elif S[-1] is False: - return S[0:-1] + return S[0:-1] return S @@ -395,7 +395,7 @@ def learn(F, converter=None, solver=None, max_learnt_length=3, interreduction=Fa try: lc = solver.learnt_clauses() except (AttributeError, NotImplementedError): - # solver does not support recovering learnt clauses + # solver does not support recovering learnt clauses lc = [] for c in lc: if len(c) <= max_learnt_length: diff --git a/src/sage/sat/converters/polybori.py b/src/sage/sat/converters/polybori.py index 27437c472ec..860a8a7e093 100644 --- a/src/sage/sat/converters/polybori.py +++ b/src/sage/sat/converters/polybori.py @@ -128,7 +128,7 @@ def __init__(self, solver, ring, max_vars_sparse=6, use_xor_clauses=None, cuttin self.cutting_number = cutting_number if use_xor_clauses is None: - use_xor_clauses = hasattr(solver,"add_xor_clause") + use_xor_clauses = hasattr(solver, "add_xor_clause") self.use_xor_clauses = use_xor_clauses self.ring = ring @@ -222,7 +222,7 @@ def choose(s): indices.append(nav.value()) nav = t else: - if self.random_generator.randint(0,1): + if self.random_generator.randint(0, 1): indices.append(nav.value()) nav = t @@ -337,11 +337,11 @@ def clauses_dense(self, f): for fpart, this_equal_zero in self.split_xor(f, equal_zero): ll = len(fpart) for p in self.permutations(ll, this_equal_zero): - self.solver.add_clause([ p[i]*fpart[i] for i in range(ll) ]) + self.solver.add_clause([p[i] * fpart[i] for i in range(ll)]) else: ll = len(f) for p in self.permutations(ll, equal_zero): - self.solver.add_clause([ p[i]*f[i] for i in range(ll) ]) + self.solver.add_clause([p[i] * f[i] for i in range(ll)]) @cached_method def monomial(self, m): @@ -387,19 +387,19 @@ def monomial(self, m): For correctness, this function is cached. """ if m.deg() == 1: - return m.index()+1 - else: - # we need to encode the relationship between the monomial - # and its variables - variables = [self.monomial(v) for v in m.variables()] - monomial = self.var(m) + return m.index() + 1 - # (a | -w) & (b | -w) & (w | -a | -b) <=> w == a*b - for v in variables: - self.solver.add_clause( (v, -monomial) ) - self.solver.add_clause( tuple([monomial] + [-v for v in variables]) ) + # we need to encode the relationship between the monomial + # and its variables + variables = [self.monomial(v) for v in m.variables()] + monomial = self.var(m) + + # (a | -w) & (b | -w) & (w | -a | -b) <=> w == a*b + for v in variables: + self.solver.add_clause((v, -monomial)) + self.solver.add_clause(tuple([monomial] + [-v for v in variables])) - return monomial + return monomial @cached_function def permutations(length, equal_zero): diff --git a/src/sage/sat/meson.build b/src/sage/sat/meson.build index a1a0246dfce..85d9be286e2 100644 --- a/src/sage/sat/meson.build +++ b/src/sage/sat/meson.build @@ -1,4 +1,9 @@ -py.install_sources('all.py', 'boolean_polynomials.py', subdir: 'sage/sat') +py.install_sources( + '__init__.py', + 'all.py', + 'boolean_polynomials.py', + subdir: 'sage/sat', +) install_subdir('converters', install_dir: sage_install_dir / 'sat') subdir('solvers') diff --git a/src/sage/sat/solvers/picosat.py b/src/sage/sat/solvers/picosat.py index fb8c10afd80..736aeebd05a 100644 --- a/src/sage/sat/solvers/picosat.py +++ b/src/sage/sat/solvers/picosat.py @@ -160,8 +160,8 @@ def __call__(self, assumptions=None): sage: solver() # optional - pycosat False """ - #import pycosat - #self._solve = pycosat.solve + # import pycosat + # self._solve = pycosat.solve sol = self._solve(self._clauses, verbose=self._verbosity, prop_limit=self._prop_limit, vars=self._nvars) # sol = pycosat.solve(self._clauses) diff --git a/src/sage/sat/solvers/sat_lp.py b/src/sage/sat/solvers/sat_lp.py index 5a027f6ae9b..05aa4812230 100644 --- a/src/sage/sat/solvers/sat_lp.py +++ b/src/sage/sat/solvers/sat_lp.py @@ -57,7 +57,7 @@ def var(self): nvars = n = self._LP.number_of_variables() while nvars == self._LP.number_of_variables(): n += 1 - self._vars[n] # creates the variable if needed + self._vars[n] # creates the variable if needed return n def nvars(self): @@ -143,7 +143,7 @@ def __call__(self): b = self._LP.get_values(self._vars, convert=bool, tolerance=self._integrality_tolerance) n = max(b) - return [None]+[b.get(i, False) for i in range(1,n+1)] + return [None] + [b.get(i, False) for i in range(1, n + 1)] def __repr__(self): """ diff --git a/src/sage/schemes/affine/affine_homset.py b/src/sage/schemes/affine/affine_homset.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/affine/affine_point.py b/src/sage/schemes/affine/affine_point.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/affine/affine_rational_point.py b/src/sage/schemes/affine/affine_rational_point.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py old mode 100755 new mode 100644 index 42aeae0e2f9..702381f6ea4 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -15,7 +15,7 @@ from sage.rings.integer_ring import ZZ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import RationalField -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base from sage.rings.finite_rings.finite_field_base import FiniteField from sage.categories.map import Map @@ -109,7 +109,7 @@ def AffineSpace(n, R=None, names=None, ambient_projective_space=None, ... NameError: variable names passed to AffineSpace conflict with names in ring """ - if isinstance(n, (MPolynomialRing_base, PolynomialRing_general)) and R is None: + if isinstance(n, (MPolynomialRing_base, PolynomialRing_generic)) and R is None: R = n if names is not None: # Check for the case that the user provided a variable name diff --git a/src/sage/schemes/affine/affine_subscheme.py b/src/sage/schemes/affine/affine_subscheme.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/berkovich/berkovich_cp_element.py b/src/sage/schemes/berkovich/berkovich_cp_element.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/berkovich/berkovich_space.py b/src/sage/schemes/berkovich/berkovich_space.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/curves/affine_curve.py b/src/sage/schemes/curves/affine_curve.py old mode 100755 new mode 100644 index 0b647c8411b..127530a9bb7 --- a/src/sage/schemes/curves/affine_curve.py +++ b/src/sage/schemes/curves/affine_curve.py @@ -141,7 +141,6 @@ from sage.rings.polynomial.multi_polynomial_element import degree_lowest_rational_function from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import RationalField -from sage.rings.infinity import infinity from sage.schemes.affine.affine_space import AffineSpace, AffineSpace_generic from sage.schemes.affine.affine_subscheme import (AlgebraicScheme_subscheme_affine, diff --git a/src/sage/schemes/curves/closed_point.py b/src/sage/schemes/curves/closed_point.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/curves/constructor.py b/src/sage/schemes/curves/constructor.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/curves/curve.py b/src/sage/schemes/curves/curve.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/curves/plane_curve_arrangement.py b/src/sage/schemes/curves/plane_curve_arrangement.py old mode 100755 new mode 100644 index 63e8d03f556..a13faab50bc --- a/src/sage/schemes/curves/plane_curve_arrangement.py +++ b/src/sage/schemes/curves/plane_curve_arrangement.py @@ -513,7 +513,7 @@ def fundamental_group(self, simplified=True, vertical=True, {0: [x1, x2], 1: [x0], 2: [x3], 3: [x3^-1*x2^-1*x1^-1*x0^-1]} sage: A.fundamental_group(vertical=False) Finitely presented group - < x0, x1, x2 | x2^-1*x1^-1*x2*x1, x1*x0*x1^-1*x0^-1, (x0*x2)^2*(x0^-1*x2^-1)^2 > + < x0, x1, x2 | x2*x1^-1*x2^-1*x1, x1*x0*x1^-1*x0^-1, (x0*x2)^2*(x0^-1*x2^-1)^2 > sage: A.meridians(vertical=False) {0: [x2, x0*x2*x0^-1], 1: [x1], 2: [x0], 3: [x0*x2^-1*x0^-1*x2^-1*x1^-1*x0^-1]} sage: G = A.fundamental_group(simplified=False, vertical=False) @@ -834,7 +834,7 @@ def fundamental_group(self, simplified=True): sage: A.fundamental_group().sorted_presentation() Finitely presented group < x0, x1 | x1^-1*x0^-1*x1*x0 > sage: A.meridians() - {0: [x1], 1: [x0], 2: [x1^-1*x0^-1*x1^-1]} + {0: [x1], 1: [x0], 2: [x0^-1*x1^-2]} sage: G = A.fundamental_group(simplified=False) sage: G.sorted_presentation() Finitely presented group @@ -945,7 +945,7 @@ def meridians(self, simplified=True): sage: A.fundamental_group().sorted_presentation() Finitely presented group < x0, x1 | x1^-1*x0^-1*x1*x0 > sage: A.meridians() - {0: [x1], 1: [x0], 2: [x1^-1*x0^-1*x1^-1]} + {0: [x1], 1: [x0], 2: [x0^-1*x1^-2]} sage: A = H(y^2 + x*z, z, x) sage: A.fundamental_group() Finitely presented group < x0, x1 | (x1*x0)^2*(x1^-1*x0^-1)^2 > diff --git a/src/sage/schemes/curves/point.py b/src/sage/schemes/curves/point.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py old mode 100755 new mode 100644 index 0729c5a98ad..09fb3ffd3db --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -1775,8 +1775,9 @@ def fundamental_group(self): sage: C = P.curve(x^2*z - y^3) sage: C.fundamental_group() # needs sirocco Finitely presented group < x0 | x0^3 > - sage: P.curve(z*(x^2*z - y^3)).fundamental_group() # needs sirocco - Finitely presented group < x0, x1 | x1*x0*x1*x0^-1*x1^-1*x0^-1 > + sage: g = P.curve(z*(x^2*z - y^3)).fundamental_group() # needs sirocco + sage: g.sorted_presentation() # needs sirocco + Finitely presented group < x0, x1 | x1^-1*x0^-1*x1^-1*x0*x1*x0 > In the case of number fields, they need to have an embedding into the algebraic field:: @@ -1805,7 +1806,6 @@ def fundamental_group(self): ....: + (x-18*z)*(z^2+11*x*z-x^2)^2) sage: G0 = C.fundamental_group() # needs sirocco sage: G.is_isomorphic(G0) # needs sirocco - #I Forcing finiteness test True sage: C = P.curve(z) sage: C.fundamental_group() # needs sirocco @@ -2301,7 +2301,7 @@ def __init__(self, A, f): self._open_affine_index = i break else: - assert "no projective curve defined" + raise ValueError("no projective curve defined") def function_field(self): """ diff --git a/src/sage/schemes/curves/zariski_vankampen.py b/src/sage/schemes/curves/zariski_vankampen.py old mode 100755 new mode 100644 index 47485b86340..f7a7cb28921 --- a/src/sage/schemes/curves/zariski_vankampen.py +++ b/src/sage/schemes/curves/zariski_vankampen.py @@ -1416,7 +1416,7 @@ def conjugate_positive_form(braid): A list of `r` lists. Each such list is another list with two elements, a positive braid `\alpha_i` and a list of permutation braids - `\gamma_{1}^{i},\dots,\gamma_{r}^{n_i}` such that if + `\gamma_{1}^{i},\dots,\gamma_{n_i}^{i}` such that if `\gamma_i=\prod_{j=1}^{n_i} \gamma_j^i` then the braids `\tau_i=\gamma_i\alpha_i\gamma_i^{-1}` pairwise commute and `\alpha=\prod_{i=1}^{r} \tau_i`. @@ -1426,17 +1426,15 @@ def conjugate_positive_form(braid): sage: from sage.schemes.curves.zariski_vankampen import conjugate_positive_form sage: B = BraidGroup(4) sage: t = B((1, 3, 2, -3, 1, 1)) - sage: conjugate_positive_form(t) - [[(s1*s0)^2, [s2]]] + sage: cpf = conjugate_positive_form(t); cpf + [[(s0*s1)^2, [s0*s2*s1*s0]]] + sage: t == prod(prod(b) * a / prod(b) for a, b in cpf) + True sage: B = BraidGroup(5) sage: t = B((1, 2, 3, 4, -1, -2, 3, 3, 2, -4)) sage: L = conjugate_positive_form(t); L - [[s1^2, [s3*s2]], [s1*s2, [s0]]] - sage: s = B.one() - sage: for a, l in L: - ....: b = prod(l) - ....: s *= b * a / b - sage: s == t + [[s0^2, [s0*s1*s2*s1*s3*s2*s1*s0]], [s3*s2, [s0*s1*s2*s1*s3*s2*s1*s0]]] + sage: t == prod(prod(b) * a / prod(b) for a, b in L) True sage: s1 = B.gen(1)^3 sage: conjugate_positive_form(s1) @@ -1444,33 +1442,40 @@ def conjugate_positive_form(braid): """ B = braid.parent() d = B.strands() - braid1 = braid.super_summit_set()[0] - L1 = braid1.Tietze() - sg0 = braid.conjugating_braid(braid1) - gns = set(L1) - cuts = [j for j in range(d + 1) if j not in gns] - blocks = [] - for i in range(len(cuts) - 1): - block = [j for j in L1 if cuts[i] < j < cuts[i + 1]] - if block: - blocks.append(block) + rnf = rightnormalform(braid) + ex = rnf[-1][0] + if ex >= 0: + A1 = [B(a) for a in rnf[:-1]] + braid1 = prod(A1, B.delta() ** ex) + sg0 = B.one() + else: + braid1, sg0 = braid.super_summit_set_element() + if ex > 0: + blocks = [list(braid1.Tietze())] + else: + L1 = braid1.Tietze() + gns = set(L1) + cuts = [j for j in range(d + 1) if j not in gns] + blocks = [] + for i in range(len(cuts) - 1): + block = [j for j in L1 if cuts[i] < j < cuts[i + 1]] + if block: + blocks.append(block) shorts = [] for a in blocks: - A = B(a).super_summit_set() - res = None - for tau in A: - sg = (sg0 * B(a) / sg0).conjugating_braid(tau) + if sg0 == B.one(): + res0 = [B(a), []] + else: + bra = sg0 * B(a) / sg0 + br1, sg = bra.super_summit_set_element() A1 = rightnormalform(sg) par = A1[-1][0] % 2 - A1 = [B(a) for a in A1[:-1]] - b = prod(A1, B.one()) - b1 = len(b.Tietze()) / (len(A1) + 1) - if res is None or b1 < res[3]: - res = [tau, A1, par, b1] - if res[2] == 1: - r0 = res[0].Tietze() - res[0] = B([i.sign() * (d - abs(i)) for i in r0]) - res0 = res[:2] + A1 = [B(a0) for a0 in A1[:-1]] + res = [br1, A1, par] + if res[2]: + r0 = res[0].Tietze() + res[0] = B([d - i for i in r0]) + res0 = res[:2] shorts.append(res0) return shorts @@ -1596,9 +1601,10 @@ def fundamental_group_from_braid_mon(bm, degree=None, sage: bm = [s1*s2*s0*s1*s0^-1*s1^-1*s0^-1, ....: s0*s1^2*s0*s2*s1*(s0^-1*s1^-1)^2*s0^-1, ....: (s0*s1)^2] - sage: g = fundamental_group_from_braid_mon(bm, projective=True); g # needs sirocco + sage: g = fundamental_group_from_braid_mon(bm, projective=True) # needs sirocco + sage: g.sorted_presentation() # needs sirocco Finitely presented group - < x1, x3 | x3^2*x1^2, x1^-1*x3^-1*x1*x3^-1*x1^-1*x3^-1 > + < x0, x1 | x1^-2*x0^-2, x1^-1*(x0^-1*x1)^2*x0 > sage: print(g.order(), g.abelian_invariants()) # needs sirocco 12 (4,) sage: B2 = BraidGroup(2) @@ -1697,8 +1703,8 @@ def fundamental_group(f, simplified=True, projective=False, puiseux=True): sage: from sage.schemes.curves.zariski_vankampen import fundamental_group, braid_monodromy sage: R. = QQ[] sage: f = x^2 + y^3 - sage: fundamental_group(f) - Finitely presented group < x0, x1 | x0*x1^-1*x0^-1*x1^-1*x0*x1 > + sage: fundamental_group(f).sorted_presentation() + Finitely presented group < x0, x1 | x1^-1*x0^-1*x1^-1*x0*x1*x0 > sage: fundamental_group(f, simplified=False, puiseux=False).sorted_presentation() Finitely presented group < x0, x1, x2 | x2^-1*x1^-1*x0*x1, x2^-1*x0*x1*x0^-1, @@ -1859,7 +1865,7 @@ def fundamental_group_arrangement(flist, simplified=True, projective=False, sage: G.sorted_presentation() Finitely presented group < x0, x1, x2, x3 | x3^-1*x2^-1*x3*x2, x3^-1*x1^-1*x0^-1*x1*x3*x0, - x3^-1*x1^-1*x3*x0*x1*x0^-1, x2^-1*x0^-1*x2*x0 > + x3^-1*x1^-1*x0^-1*x3*x0*x1, x2^-1*x0^-1*x2*x0 > sage: dic {0: [x1], 1: [x3], 2: [x2], 3: [x0], 4: [x3^-1*x2^-1*x1^-1*x0^-1]} sage: fundamental_group_arrangement(L, vertical=True) diff --git a/src/sage/schemes/cyclic_covers/charpoly_frobenius.py b/src/sage/schemes/cyclic_covers/charpoly_frobenius.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/cyclic_covers/constructor.py b/src/sage/schemes/cyclic_covers/constructor.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/cyclic_covers/cycliccover_finite_field.py b/src/sage/schemes/cyclic_covers/cycliccover_finite_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/cyclic_covers/cycliccover_generic.py b/src/sage/schemes/cyclic_covers/cycliccover_generic.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/Qcurves.py b/src/sage/schemes/elliptic_curves/Qcurves.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/addition_formulas_ring.py b/src/sage/schemes/elliptic_curves/addition_formulas_ring.py new file mode 100644 index 00000000000..3846f9f0c7d --- /dev/null +++ b/src/sage/schemes/elliptic_curves/addition_formulas_ring.py @@ -0,0 +1,89 @@ + +def _add(E, P, Q): + r""" + Addition formulas for elliptic curves over general rings + with trivial Picard group. + + This function returns a generator which yields tuples of projective + coordinates. Some linear combination of those coordinate tuples is + guaranteed to form a valid projective point. + + .. NOTE:: + + This function is for internal use. To add two elliptic-curve + points, users should simply use the `+` operator. + + REFERENCES: + + These formulas were derived by Bosma and Lenstra [BL1995]_, + with corrections by Best [Best2021]_ (Appendix A). + + EXAMPLES:: + + sage: from sage.schemes.elliptic_curves.addition_formulas_ring import _add + sage: M = Zmod(13*17*19) + sage: R. = M[] + sage: S. = R.quotient(U*V - 17) + sage: E = EllipticCurve(S, [1,2,3,4,5]) + sage: P = E(817, 13, 19) + sage: Q = E(425, 123, 17) + sage: PQ1, PQ2 = _add(E, P, Q) + sage: PQ1 + (1188, 1674, 540) + sage: PQ2 + (582, 2347, 1028) + sage: E(PQ1) == E(PQ2) + True + + TESTS: + + We ensure that these formulas return the same result as the ones over a field:: + + sage: from sage.schemes.elliptic_curves.addition_formulas_ring import _add + sage: F = GF(2^127-1) + sage: E = EllipticCurve(j=F.random_element()) + sage: E = choice(E.twists()) + sage: P = E.random_point() + sage: Q = E.random_point() + sage: PQ1, PQ2 = _add(E, P, Q) + sage: assert E(*PQ1) == P + Q + sage: assert E(*PQ2) == P + Q + """ + a1, a2, a3, a4, a6 = E.a_invariants() + b2, b4, b6, b8 = E.b_invariants() + + if P not in E: + raise ValueError('P must be in E') + if Q not in E: + raise ValueError('Q must be in E') + X1, Y1, Z1 = P + X2, Y2, Z2 = Q + + # TODO: I've made a half-hearted attempt at simplifying the formulas + # by caching common subexpressions. This could almost certainly be + # sped up significantly with some more serious optimization effort. + + XYdif = X1*Y2 - X2*Y1 + XYsum = X1*Y2 + X2*Y1 + XZdif = X1*Z2 - X2*Z1 + XZsum = X1*Z2 + X2*Z1 + YZdif = Y1*Z2 - Y2*Z1 + YZsum = Y1*Z2 + Y2*Z1 + + a1sq, a2sq, a3sq, a4sq = (a**2 for a in (a1, a2, a3, a4)) + + X31 = XYdif*YZsum+XZdif*Y1*Y2+a1*X1*X2*YZdif+a1*XYdif*XZsum-a2*X1*X2*XZdif+a3*XYdif*Z1*Z2+a3*XZdif*YZsum-a4*XZsum*XZdif-3*a6*XZdif*Z1*Z2 + + Y31 = -3*X1*X2*XYdif-Y1*Y2*YZdif-2*a1*XZdif*Y1*Y2+(a1sq+3*a2)*X1*X2*YZdif-(a1sq+a2)*XYsum*XZdif+(a1*a2-3*a3)*X1*X2*XZdif-(2*a1*a3+a4)*XYdif*Z1*Z2+a4*XZsum*YZdif+(a1*a4-a2*a3)*XZsum*XZdif+(a3sq+3*a6)*YZdif*Z1*Z2+(3*a1*a6-a3*a4)*XZdif*Z1*Z2 + + Z31 = 3*X1*X2*XZdif-YZsum*YZdif+a1*XYdif*Z1*Z2-a1*XZdif*YZsum+a2*XZsum*XZdif-a3*YZdif*Z1*Z2+a4*XZdif*Z1*Z2 + + yield (X31, Y31, Z31) + + X32 = Y1*Y2*XYsum+a1*(2*X1*Y2+X2*Y1)*X2*Y1+a1sq*X1*X2**2*Y1-a2*X1*X2*XYsum-a1*a2*X1**2*X2**2+a3*X2*Y1*(YZsum+Y2*Z1)+a1*a3*X1*X2*YZdif-a1*a3*XYsum*XZdif-a4*X1*X2*YZsum-a4*XYsum*XZsum-a1sq*a3*X1**2*X2*Z2-a1*a4*X1*X2*(X1*Z2+XZsum)-a2*a3*X1*X2**2*Z1-a3sq*X1*Z2*(Y2*Z1+YZsum)-3*a6*XYsum*Z1*Z2-3*a6*XZsum*YZsum-a1*a3sq*X1*Z2*(XZsum+X2*Z1)-3*a1*a6*X1*Z2*(XZsum+X2*Z1)-a3*a4*(X1*Z2+XZsum)*X2*Z1-b8*YZsum*Z1*Z2-a1*b8*X1*Z1*Z2**2-a3**3*XZsum*Z1*Z2-3*a3*a6*(XZsum+X2*Z1)*Z1*Z2-a3*b8*Z1**2*Z2**2 + + Y32 = Y1**2*Y2**2+a1*X2*Y1**2*Y2+(a1*a2-3*a3)*X1*X2**2*Y1+a3*Y1**2*Y2*Z2-(a2sq-3*a4)*X1**2*X2**2+(a1*a4-a2*a3)*(2*X1*Z2+X2*Z1)*X2*Y1+(a1sq*a4-2*a1*a2*a3+3*a3sq)*X1**2*X2*Z2-(a2*a4-9*a6)*X1*X2*XZsum+(3*a1*a6-a3*a4)*(XZsum+X2*Z1)*Y1*Z2+(3*a1sq*a6-2*a1*a3*a4+a2*a3sq+3*a2*a6-a4sq)*X1*Z2*(XZsum+X2*Z1)+(3*a2*a6-a4sq)*X2*Z1*(2*X1*Z2+Z1*X2)+(a1**3*a6-a1sq*a3*a4+a1*a2*a3sq-a1*a4sq+4*a1*a2*a6-a3**3-3*a3*a6)*Y1*Z1*Z2**2+(a1**4*a6-a1**3*a3*a4+5*a1sq*a2*a6+a1sq*a2*a3sq-a1*a2*a3*a4-a1*a3**3-3*a1*a3*a6-a1sq*a4sq+a2sq*a3sq-a2*a4sq+4*a2sq*a6-a3**2*a4-3*a4*a6)*X1*Z1*Z2**2+(a1sq*a2*a6-a1*a2*a3*a4+3*a1*a3*a6+a2sq*a3sq-a2*a4sq+4*a2sq*a6-2*a3sq*a4-3*a4*a6)*X2*Z1**2*Z2+(a1**3*a3*a6-a1sq*a3sq*a4+a1sq*a4*a6+a1*a2*a3**3+4*a1*a2*a3*a6-2*a1*a3*a4sq+a2*a3sq*a4+4*a2*a4*a6-a3**4-6*a3**2*a6-a4**3-9*a6**2)*Z1**2*Z2**2 + + Z32 = 3*X1*X2*XYsum+Y1*Y2*YZsum+3*a1*X1**2*X2**2+a1*(2*X1*Y2+Y1*X2)*Y1*Z2+a1sq*X1*Z2*(2*X2*Y1+X1*Y2)+a2*X1*X2*YZsum+a2*XYsum*XZsum+a1**3*X1**2*X2*Z2+a1*a2*X1*X2*(2*X1*Z2+X2*Z1)+3*a3*X1*X2**2*Z1+a3*Y1*Z2*(YZsum+Y2*Z1)+2*a1*a3*X1*Z2*YZsum+2*a1*a3*X2*Y1*Z1*Z2+a4*XYsum*Z1*Z2+a4*XZsum*YZsum+(a1sq*a3+a1*a4)*X1*Z2*(XZsum+X2*Z1)+a2*a3*X2*Z1*(2*X1*Z2+X2*Z1)+a3sq*Y1*Z1*Z2**2+(a3sq+3*a6)*YZsum*Z1*Z2+a1*a3sq*(2*X1*Z2+X2*Z1)*Z1*Z2+3*a1*a6*X1*Z1*Z2**2+a3*a4*(XZsum+X2*Z1)*Z1*Z2+(a3**3+3*a3*a6)*Z1**2*Z2**2 + + yield (X32, Y32, Z32) diff --git a/src/sage/schemes/elliptic_curves/cm.py b/src/sage/schemes/elliptic_curves/cm.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/constructor.py b/src/sage/schemes/elliptic_curves/constructor.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx b/src/sage/schemes/elliptic_curves/descent_two_isogeny.pyx old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/ec_database.py b/src/sage/schemes/elliptic_curves/ec_database.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py old mode 100755 new mode 100644 index f25fbc20a7d..1363543bf3b --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -3319,12 +3319,13 @@ def dual(self): else: # trac 7096 - # this should take care of the case when the isogeny is not normalized. + # this should take care of the case when the isogeny is + # not normalized. u = self.scaling_factor() E2 = E2pr.change_weierstrass_model(u/F(d), 0, 0, 0) phi_hat = EllipticCurveIsogeny(E1, None, E2, d) -# assert phi_hat.scaling_factor() == 1 + # assert phi_hat.scaling_factor() == 1 for pre_iso in self._codomain.isomorphisms(E1): for post_iso in E2.isomorphisms(self._domain): @@ -3335,7 +3336,7 @@ def dual(self): continue break else: - assert "bug in dual()" + raise RuntimeError("bug in dual()") phi_hat._set_pre_isomorphism(pre_iso) phi_hat._set_post_isomorphism(post_iso) diff --git a/src/sage/schemes/elliptic_curves/ell_egros.py b/src/sage/schemes/elliptic_curves/ell_egros.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py old mode 100755 new mode 100644 index 4f694e0f252..920fd99dfed --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -1364,7 +1364,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al From: Elliptic Curve defined by y^2 + x*y = x^3 + x + 2 over Finite Field of size 31 To: Elliptic Curve defined by y^2 + x*y = x^3 + 2*x + 26 over Finite Field of size 31 - Multiple ways to set the `velu_sqrt_bound`:: + Multiple ways to set the ``velu_sqrt_bound``:: sage: E = EllipticCurve_from_j(GF(97)(42)) sage: P = E.gens()[0]*4 @@ -1427,7 +1427,7 @@ def isogeny(self, kernel, codomain=None, degree=None, model=None, check=True, al sage: phi.codomain()._order 170141183460469231746191640949390434666 - Check that ``'factored'`` recursively apply `velu_sqrt_bound`:: + Check that ``factored`` recursively apply ``velu_sqrt_bound``:: sage: from sage.schemes.elliptic_curves.hom_velusqrt import _velu_sqrt_bound sage: _velu_sqrt_bound.get() @@ -1529,6 +1529,55 @@ def isogeny_codomain(self, kernel): E._fetch_cached_order(self) return E + def period_lattice(self): + r""" + Return the period lattice of the elliptic curve for the given + embedding of its base field with respect to the differential + `dx/(2y + a_1x + a_3)`. + + Only supported for some base rings. + + EXAMPLES:: + + sage: EllipticCurve(RR, [1, 6]).period_lattice() + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 6.00000000000000 over Real Field with 53 bits of precision + + TESTS:: + + sage: EllipticCurve(QQ, [1, 6]).period_lattice() + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x + 6 over Rational Field + sage: EllipticCurve(RR, [1, 6]).period_lattice() + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 6.00000000000000 over Real Field with 53 bits of precision + sage: EllipticCurve(RealField(100), [1, 6]).period_lattice() + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.0000000000000000000000000000*x + 6.0000000000000000000000000000 over Real Field with 100 bits of precision + sage: EllipticCurve(CC, [1, 6]).period_lattice() + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.00000000000000*x + 6.00000000000000 over Complex Field with 53 bits of precision + sage: EllipticCurve(ComplexField(100), [1, 6]).period_lattice() + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + 1.0000000000000000000000000000*x + 6.0000000000000000000000000000 over Complex Field with 100 bits of precision + sage: EllipticCurve(AA, [1, 6]).period_lattice() + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x + 6 over Algebraic Real Field + sage: EllipticCurve(QQbar, [1, 6]).period_lattice() + Period lattice associated to Elliptic Curve defined by y^2 = x^3 + x + 6 over Algebraic Field + + Unsupported cases (the exact error being raised may change in the future):: + + sage: EllipticCurve(ZZ, [1, 6]).period_lattice() + Traceback (most recent call last): + ... + AttributeError: 'EllipticCurve_generic_with_category' object has no attribute 'period_lattice' + sage: QQt. = QQ[] + sage: EllipticCurve(QQt.fraction_field(), [1, 6]).period_lattice() + Traceback (most recent call last): + ... + AttributeError: 'FractionField_1poly_field_with_category' object has no attribute ... + sage: EllipticCurve(GF(7), [1, 6]).period_lattice() + Traceback (most recent call last): + ... + IndexError: list index out of range + """ + from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell + return PeriodLattice_ell(self) + def kernel_polynomial_from_point(self, P, *, algorithm=None): r""" Given a point `P` on this curve which generates a rational subgroup, @@ -1705,7 +1754,7 @@ def kernel_polynomial_from_divisor(self, f, l, *, check=True): if not f.is_irreducible(): raise NotImplementedError('currently, kernel_polynomial_from_divisor() only supports irreducible polynomials') if f.parent().base_ring() != self.base_ring(): - raise TypeError(f'given polynomial is not defined over the base ring of the curve') + raise TypeError('given polynomial is not defined over the base ring of the curve') if self.division_polynomial(l, x=f.parent().quotient_ring(f).gen()): raise ValueError(f'given polynomial does not divide the {l}-division polynomial') @@ -2141,7 +2190,7 @@ def isogenies_degree(self, n, *, _intermediate=False): """ def compute_key(phi): """ - Data used in ``hash(phi)`` excluding the expensive `.kernel_polynomial`. + Data used in ``hash(phi)`` excluding the expensive ``.kernel_polynomial``. """ return (phi.domain(), phi.codomain(), phi.degree(), phi.scaling_factor()) diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py old mode 100755 new mode 100644 index 905cc63e149..34de89b7f12 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -2810,18 +2810,8 @@ def special_supersingular_curve(F, q=None, *, endomorphism=False): try: endo = iso * E.isogeny(None, iso.domain(), degree=q) except (NotImplementedError, ValueError): #FIXME catching ValueError here is a workaround for #38481 - #FIXME this code could be simplified/optimized after #37388 and/or #35949 - def _isogs(E, d): - if d.is_one(): - yield E.identity_morphism() - return - l = d.prime_factors()[-1] - for phi in E.isogenies_prime_degree(l): - for psi in _isogs(phi.codomain(), d//l): - yield psi * phi - endos = (iso*phi for phi in _isogs(E, q) for iso in phi.codomain().isomorphisms(E)) -# endos = (iso*phi for phi in E.isogenies_degree(q) -# for iso in phi.codomain().isomorphisms(E)) + endos = (iso*phi for phi in E.isogenies_degree(q) + for iso in phi.codomain().isomorphisms(E)) endo = next(endo for endo in endos if endo.trace().is_zero()) endo._degree = ZZ(q) @@ -2942,6 +2932,7 @@ def find_q(m, m4_fac, D): seen.add(Et) yield Et + def EllipticCurve_with_prime_order(N): r""" Given a prime number ``N``, find another prime number `p` and construct an diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py old mode 100755 new mode 100644 index 6f2532e2b3b..bfecebf1f86 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -55,8 +55,6 @@ import math from sage.arith.misc import valuation -import sage.rings.abc -from sage.rings.finite_rings.integer_mod import mod from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.polynomial.polynomial_ring import polygen, polygens from sage.rings.polynomial.polynomial_element import polynomial_is_variable @@ -175,15 +173,49 @@ def __init__(self, K, ainvs, category=None): self.__divpolys = ({}, {}, {}) - # See #1975: we deliberately set the class to - # EllipticCurvePoint_finite_field for finite rings, so that we - # can do some arithmetic on points over Z/NZ, for teaching - # purposes. - if isinstance(K, sage.rings.abc.IntegerModRing): - self._point = ell_point.EllipticCurvePoint_finite_field - _point = ell_point.EllipticCurvePoint + def assume_base_ring_is_field(self, flag=True): + r""" + Set a flag to pretend that this elliptic curve is defined over a + field while doing arithmetic, which is useful in some algorithms. + + + .. WARNING:: + + The flag affects all points created while the flag is set. Note + that elliptic curves are unique parents, hence setting this flag + may break seemingly unrelated parts of Sage. + + .. NOTE:: + + This method is a **hack** provided for educational purposes. + + EXAMPLES:: + + sage: E = EllipticCurve(Zmod(35), [1,1]) + sage: P = E(-5, 9) + sage: 4*P + (23 : 26 : 1) + sage: 9*P + (10 : 11 : 5) + sage: E.assume_base_ring_is_field() + sage: P = E(-5, 9) + sage: 4*P + (23 : 26 : 1) + sage: 9*P + Traceback (most recent call last): + ... + ZeroDivisionError: Inverse of 5 does not exist (characteristic = 35 = 5*7) + """ + if flag: + if self.__base_ring.is_finite(): + self._point = ell_point.EllipticCurvePoint_finite_field + else: + self._point = ell_point.EllipticCurvePoint_field + else: + self._point = ell_point.EllipticCurvePoint + def _defining_params_(self): r""" Internal function. Return a tuple of the base ring of this @@ -582,7 +614,7 @@ def __call__(self, *args, **kwds): # infinity. characteristic = self.base_ring().characteristic() if characteristic != 0 and isinstance(args[0][0], Rational) and isinstance(args[0][1], Rational): - if mod(args[0][0].denominator(),characteristic) == 0 or mod(args[0][1].denominator(),characteristic) == 0: + if characteristic.divides(args[0][0].denominator()) or characteristic.divides(args[0][1].denominator()): return self._reduce_point(args[0], characteristic) args = tuple(args[0]) @@ -914,7 +946,7 @@ def lift_x(self, x, all=False, extend=False): b = (a1*x + a3) f = ((x + a2) * x + a4) * x + a6 - # If possible find the associated y coorindates in L: + # If possible find the associated y coordinates in L: if K.characteristic() == 2: R = PolynomialRing(L, 'y') diff --git a/src/sage/schemes/elliptic_curves/ell_local_data.py b/src/sage/schemes/elliptic_curves/ell_local_data.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/ell_number_field.py b/src/sage/schemes/elliptic_curves/ell_number_field.py old mode 100755 new mode 100644 index 8af221880b6..518fda03481 --- a/src/sage/schemes/elliptic_curves/ell_number_field.py +++ b/src/sage/schemes/elliptic_curves/ell_number_field.py @@ -290,7 +290,8 @@ def simon_two_descent(self, verbose=0, lim1=2, lim3=4, limtriv=2, # time (when known_points may have increased) will not cause # another execution of simon_two_descent. try: - result = self._simon_two_descent_data[lim1,lim3,limtriv,maxprob,limbigprime] + result = self._simon_two_descent_data[lim1, lim3, limtriv, + maxprob, limbigprime] if verbose == 0: return result except AttributeError: @@ -2343,7 +2344,7 @@ def gens(self, **kwds): sage: gg=E.gens(lim3=13); gg # long time (about 4s) [(... : 1)] - Check that the the point found has infinite order, and that it is on the curve:: + Check that the point found has infinite order, and that it is on the curve:: sage: P=gg[0]; P.order() # long time +Infinity @@ -2447,7 +2448,7 @@ def period_lattice(self, embedding): -0.14934463314391922099120107422 - 2.0661954627294548995621225062*I) """ from sage.schemes.elliptic_curves.period_lattice import PeriodLattice_ell - return PeriodLattice_ell(self,embedding) + return PeriodLattice_ell(self, embedding) def real_components(self, embedding): """ diff --git a/src/sage/schemes/elliptic_curves/ell_padic_field.py b/src/sage/schemes/elliptic_curves/ell_padic_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py old mode 100755 new mode 100644 index 6aa63fc6370..1d980d60666 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -1,14 +1,16 @@ r""" Points on elliptic curves -The base class :class:`EllipticCurvePoint` currently provides little -functionality of its own. Its derived class -:class:`EllipticCurvePoint_field` provides support for points on -elliptic curves over general fields. The derived classes -:class:`EllipticCurvePoint_number_field` and -:class:`EllipticCurvePoint_finite_field` provide further support for -points on curves over number fields (including the rational field -`\QQ`) and over finite fields. +The base class :class:`EllipticCurvePoint` provides support for +points on elliptic curves defined over general rings, including +generic addition formulas. + +The derived classes :class:`EllipticCurvePoint_field` and its +child classes :class:`EllipticCurvePoint_number_field` and +:class:`EllipticCurvePoint_finite_field` provide further support +for points on curves defined over arbitrary fields, as well as +specialized functionality for points on curves over number fields +(including the rational field `\QQ`) and finite fields. EXAMPLES: @@ -73,15 +75,24 @@ sage: P*(n+1)-P*n == P True -Arithmetic over `\ZZ/N\ZZ` with composite `N` is supported. When an -operation tries to invert a non-invertible element, a -:exc:`ZeroDivisionError` is raised and a factorization of the modulus appears -in the error message:: +Arithmetic over `\Zmod{N}` with composite `N` is supported:: sage: N = 1715761513 sage: E = EllipticCurve(Integers(N), [3,-13]) sage: P = E(2,1) sage: LCM([2..60])*P + (1643112467 : 9446995 : 26927) + +However, some algorithms (e.g., toy examples of ECM) involve performing +elliptic-curve operations as if the base ring were a field even when it +is not, and exploit the failures when attempting to invert a non-unit. +Sage provides a *hack* to support such educational examples via the +:meth:`EllipticCurve_generic.assume_base_ring_is_field` method. +Example:: + + sage: E.assume_base_ring_is_field() + sage: P = E(2,1) + sage: LCM([2..60])*P Traceback (most recent call last): ... ZeroDivisionError: Inverse of 26927 does not exist @@ -104,6 +115,8 @@ - Mariah Lenox (March 2011) -- Added ``tate_pairing`` and ``ate_pairing`` functions to ``EllipticCurvePoint_finite_field`` class + +- Lorenz Panny (2022): point addition over general rings """ # **************************************************************************** @@ -128,14 +141,18 @@ from sage.rings.padics.precision_error import PrecisionError from sage.rings.rational_field import QQ from sage.rings.real_mpfr import RealField, RR +from sage.rings.quotient_ring import QuotientRing_generic + +from sage.structure.element import AdditiveGroupElement +from sage.structure.sequence import Sequence +from sage.structure.richcmp import richcmp + +from sage.structure.coerce_actions import IntegerMulAction + from sage.schemes.curves.projective_curve import Hasse_bounds from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.schemes.projective.projective_point import (SchemeMorphism_point_projective_ring, SchemeMorphism_point_abelian_variety_field) -from sage.structure.coerce_actions import IntegerMulAction -from sage.structure.element import AdditiveGroupElement -from sage.structure.richcmp import richcmp -from sage.structure.sequence import Sequence lazy_import('sage.rings.padics.factory', 'Qp') lazy_import('sage.schemes.generic.morphism', 'SchemeMorphism') @@ -151,6 +168,28 @@ class EllipticCurvePoint(AdditiveGroupElement, """ A point on an elliptic curve. """ + def __init__(self, *args, **kwds): + r""" + Initialize this elliptic-curve point. + + EXAMPLES:: + + sage: E = EllipticCurve(Zmod(77), [1,1,1,1,1]) + sage: E(0) + (0 : 1 : 0) + sage: E(3, 9) + (3 : 9 : 1) + sage: E(6, 18, 2) + (3 : 9 : 1) + sage: E(66, 23, 22) + (33 : 50 : 11) + """ + super().__init__(*args, **kwds) + try: + self.normalize_coordinates() + except NotImplementedError: + pass + def curve(self): """ Return the curve that this point is on. @@ -179,6 +218,259 @@ def curve(self): """ return self.scheme() + def _add_(self, other): + r""" + Add this point to another point on the same elliptic curve. + + This method computes point additions for fairly general rings. + + ALGORITHM: + + Over quotient rings of Euclidean domains modulo principal ideals: + The standard formulas for fields, extended to non-fields via the + Chinese remainder theorem. + + In more general rings: Formulas due to Bosma and Lenstra [BL1995]_ + with corrections by Best [Best2021]_ (Appendix A). + See :mod:`sage.schemes.elliptic_curves.addition_formulas_ring`. + + EXAMPLES:: + + sage: N = 1113121 + sage: E = EllipticCurve(Zmod(N), [1,0]) + sage: R1 = E(301098, 673883, 644675) + sage: R2 = E(411415, 758555, 255837) + sage: R3 = E(983009, 342673, 207687) + sage: R1 + R2 == R3 + True + + TESTS: + + We check on random examples that the results are compatible modulo + all divisors of the characteristic. (In particular, this includes + prime divisors, for which the result is computed using the "old", + much simpler formulas for fields.) :: + + sage: N = ZZ(randrange(2, 10**5)) + sage: E = None + sage: while True: + ....: try: + ....: E = EllipticCurve(list((Zmod(N)^5).random_element())) + ....: except ArithmeticError: + ....: pass + ....: else: + ....: if E.discriminant().is_unit(): + ....: break + sage: pts = [] + sage: X = polygen(Zmod(N^2)) + sage: while len(pts) < 2: + ....: y, z = (Zmod(N)^2).random_element() + ....: f = E.defining_polynomial()(X, y, z) + ....: xs = f.roots(multiplicities=False) + ....: xs = [x for x in xs if 1 in Zmod(N).ideal([x,y,z])] + ....: if xs: + ....: pts.append(E(choice(xs), y, z)) + sage: P, Q = pts + sage: R = P + Q + sage: for d in N.divisors(): + ....: if d > 1: + ....: assert R.change_ring(Zmod(d)) == P.change_ring(Zmod(d)) + Q.change_ring(Zmod(d)) + """ + if self.is_zero(): + return other + if other.is_zero(): + return self + + E = self.curve() + R = E.base_ring() + + # We handle Euclidean domains modulo principal ideals separately. + # Important special cases of this include quotient rings of the + # integers as well as of univariate polynomial rings over fields. + if isinstance(R, QuotientRing_generic): + from sage.categories.euclidean_domains import EuclideanDomains + if R.cover_ring() in EuclideanDomains(): + I = R.defining_ideal() + if I.ngens() == 1: + mod, = I.gens() + + a1, a2, a3, a4, a6 = E.ainvs() + x1, y1, z1 = map(R, self) + x2, y2, z2 = map(R, other) + + mod_1st = mod.gcd(z2.lift()) + mod //= mod_1st + mod_2nd = mod.gcd(z1.lift()) + mod //= mod_2nd + + xz, zx = x1*z2, x2*z1 + yz, zy = y1*z2, y2*z1 + zz = z1*z2 + + # addition + num_add = yz - zy + den_add = xz - zx + mod_dbl = mod.gcd(num_add.lift()).gcd(den_add.lift()) + mod_add = mod // mod_dbl + + # doubling + if not mod_dbl.is_one(): + num_dbl = (3*x1 + 2*a2*z1) * x1 + (a4*z1 - a1*y1) * z1 + den_dbl = (2*y1 + a1*x1 + a3*z1) * z1 + else: + num_dbl = den_dbl = 0 + + if mod_dbl.gcd(mod_add).is_one(): + from sage.arith.misc import CRT_vectors + if mod_dbl.is_one(): + num, den = num_add, den_add + elif mod_add.is_one(): + num, den = num_dbl, den_dbl + else: + num, den = CRT_vectors([(num_add, den_add), (num_dbl, den_dbl)], [mod_add, mod_dbl]) + + den2 = den**2 + x3 = ((num + a1*den)*zz*num - (xz + zx + a2*zz)*den2) * den + y3 = ((2*xz + zx + (a2 - a1**2)*zz)*num + (a1*(xz + zx + a2*zz) - a3*zz - yz)*den) * den2 - (num + 2*a1*den)*zz*num**2 + z3 = zz * den * den2 + + pt = x3.lift(), y3.lift(), z3.lift() + if not mod_1st.is_one(): + pt = CRT_vectors([pt, [x1.lift(), y1.lift(), z1.lift()]], [mod, mod_1st]) + mod = mod.lcm(mod_1st) + if not mod_2nd.is_one(): + pt = CRT_vectors([pt, [x2.lift(), y2.lift(), z2.lift()]], [mod, mod_2nd]) + + return E.point(Sequence(pt, E.base_ring()), check=False) + + from sage.schemes.elliptic_curves.addition_formulas_ring import _add + from sage.modules.free_module_element import vector + + pts = [] + for pt in filter(any, _add(E, self, other)): + if R.one() in R.ideal(pt): + return E.point(pt) + pts.append(pt) + assert len(pts) == 2, 'bug in elliptic-curve point addition' + + #TODO: If the base ring has trivial Picard group, it is known + # that some linear combination of the two vectors is a valid + # projective point (whose coordinates generate the unit ideal). + # Below, we simply try random linear combinations until we + # find a good choice. Is there a general method that doesn't + # involve guessing? + + pts = [vector(R, pt) for pt in pts] + for _ in range(1000): + result = tuple(sum(R.random_element() * pt for pt in pts)) + if R.one() in R.ideal(result): + return E.point(result, check=False) + + assert False, 'bug: failed to compute elliptic-curve point addition' + + def _neg_(self): + """ + Return the negative of this elliptic-curve point, over a general ring. + + EXAMPLES:: + + sage: E = EllipticCurve('389a') + sage: P = E([-1,1]) + sage: Q = -P; Q + (-1 : -2 : 1) + sage: Q + P + (0 : 1 : 0) + + :: + + sage: N = 1113121 + sage: E = EllipticCurve(Zmod(N), [1,0]) + sage: R = E(301098, 673883, 644675) + sage: -R + (136211 : 914033 : 107) + sage: ((-R) + R) == 0 + True + """ + if self.is_zero(): + return self + E = self.curve() + a1, _, a3, _, _ = E.a_invariants() + x, y, z = self + return E.point([x, -y - a1*x - a3*z, z], check=False) + + def _sub_(self, other): + """ + Subtract ``other`` from ``self``. + + ALGORITHM: :meth:`_add_` and :meth:`_neg_`. + + EXAMPLES:: + + sage: E = EllipticCurve('389a') + sage: P = E([-1,1]); Q = E([0,0]) + sage: P - Q + (4 : 8 : 1) + sage: P - Q == P._sub_(Q) + True + sage: (P - Q) + Q + (-1 : 1 : 1) + sage: P + (-1 : 1 : 1) + + :: + + sage: N = 1113121 + sage: E = EllipticCurve(Zmod(N), [1,0]) + sage: R1 = E(301098, 673883, 644675) + sage: R2 = E(411415, 758555, 255837) + sage: R3 = E(983009, 342673, 207687) + sage: R1 == R3 - R2 + True + """ + return self + (-other) + + def _acted_upon_(self, other, side): + r""" + We implement ``_acted_upon_`` to provide scalar multiplications. + + EXAMPLES:: + + sage: # needs sage.rings.finite_rings + sage: N = 1113121 + sage: E = EllipticCurve(Zmod(N), [1,0]) + sage: R = E(301098, 673883, 644675) + sage: 123*R + (703739 : 464106 : 107) + sage: 70200*R + (0 : 1 : 0) + """ + return IntegerMulAction(ZZ, self.parent())._act_(other, self) + + def __bool__(self): + r""" + Test whether this elliptic-curve point equals the neutral + element of the group (i.e., the point at infinity). + + EXAMPLES:: + + sage: E = EllipticCurve(GF(7), [1,1]) + sage: bool(E(0)) + False + sage: bool(E.lift_x(2)) + True + + sage: + + sage: E = EllipticCurve(Zmod(77), [1,1,1,1,1]) + sage: bool(E(0)) + False + sage: P = E(66, 23, 22); P + (33 : 50 : 11) + sage: bool(P) + True + """ + return bool(self[2]) + class EllipticCurvePoint_field(EllipticCurvePoint, SchemeMorphism_point_abelian_variety_field): @@ -680,9 +972,11 @@ def plot(self, **args): else: return point((self[0], self[1]), **args) - def _add_(self, right): - """ - Add ``self`` to ``right``. + def _add_(self, other): + r""" + Add this point to another point on the same elliptic curve. + + This method is specialized to elliptic curves over fields. EXAMPLES:: @@ -693,6 +987,8 @@ def _add_(self, right): sage: P._add_(Q) == P + Q True + TESTS: + Example to show that bug :issue:`4820` is fixed:: sage: [type(c) for c in 2*EllipticCurve('37a1').gen(0)] @@ -704,6 +1000,7 @@ def _add_(self, right): sage: N = 1715761513 sage: E = EllipticCurve(Integers(N), [3,-13]) + sage: E.assume_base_ring_is_field() sage: P = E(2,1) sage: LCM([2..60])*P Traceback (most recent call last): @@ -713,6 +1010,7 @@ def _add_(self, right): sage: N = 35 sage: E = EllipticCurve(Integers(N), [5,1]) + sage: E.assume_base_ring_is_field() sage: P = E(0,1) sage: 4*P Traceback (most recent call last): @@ -727,72 +1025,52 @@ def _add_(self, right): sage: 2*P (15 : 14 : 1) """ - # Use Prop 7.1.7 of Cohen "A Course in Computational Algebraic - # Number Theory" + # Use Prop 7.1.7 of Cohen "A Course in Computational Algebraic Number Theory" + if self.is_zero(): - return right - if right.is_zero(): + return other + if other.is_zero(): return self + E = self.curve() a1, a2, a3, a4, a6 = E.ainvs() - x1, y1 = self[0], self[1] - x2, y2 = right[0], right[1] + x1, y1 = self.xy() + x2, y2 = other.xy() + if x1 == x2 and y1 == -y2 - a1*x2 - a3: return E(0) # point at infinity - if x1 == x2 and y1 == y2: - try: + try: + if x1 == x2 and y1 == y2: m = (3*x1*x1 + 2*a2*x1 + a4 - a1*y1) / (2*y1 + a1*x1 + a3) - except ZeroDivisionError: - R = E.base_ring() - if R.is_finite(): - N = R.characteristic() - N1 = N.gcd(Integer(2*y1 + a1*x1 + a3)) - N2 = N//N1 - raise ZeroDivisionError("Inverse of %s does not exist (characteristic = %s = %s*%s)" % (2*y1 + a1*x1 + a3, N, N1, N2)) - else: - raise ZeroDivisionError("Inverse of %s does not exist" % (2*y1 + a1*x1 + a3)) - else: + else: + m = (y1 - y2) / (x1 - x2) + except ZeroDivisionError as ex: try: - m = (y1-y2)/(x1-x2) - except ZeroDivisionError: - R = E.base_ring() - if R.is_finite(): - N = R.characteristic() - N1 = N.gcd(Integer(x1-x2)) - N2 = N//N1 - raise ZeroDivisionError("Inverse of %s does not exist (characteristic = %s = %s*%s)" % (x1-x2, N, N1, N2)) - else: - raise ZeroDivisionError("Inverse of %s does not exist" % (x1-x2)) + d = next(d for d in (x1 - x2, 2*y1 + a1*x1 + a3) if d and not d.is_unit()) + m, = d.parent().defining_ideal().gens() + f1 = d.lift().gcd(m) + f2 = m // f1 + assert m == f1 * f2 + except Exception: + raise ex + else: + raise ZeroDivisionError(f'Inverse of {d} does not exist (characteristic = {m} = {f1}*{f2})') x3 = -x1 - x2 - a2 + m*(m+a1) y3 = -y1 - a3 - a1*x3 + m*(x1-x3) # See trac #4820 for why we need to coerce 1 into the base ring here: return E.point([x3, y3, E.base_ring().one()], check=False) - def _sub_(self, right): - """ - Subtract ``right`` from ``self``. + _sub_ = EllipticCurvePoint._sub_ - EXAMPLES:: - - sage: E = EllipticCurve('389a') - sage: P = E([-1,1]); Q = E([0,0]) - sage: P - Q - (4 : 8 : 1) - sage: P - Q == P._sub_(Q) - True - sage: (P - Q) + Q - (-1 : 1 : 1) - sage: P - (-1 : 1 : 1) - """ - return self + (-right) - - def __neg__(self): + def _neg_(self): """ Return the additive inverse of this point. + Same as :meth:`EllipticCurvePoint._neg_`, but specialized + to points over fields, which are normalized to satisfy `z=1`. + EXAMPLES:: sage: E = EllipticCurve('389a') @@ -2575,7 +2853,7 @@ def _has_order_at_least(self, bound, *, attempts=999): sage: P = next(filter(bool, E.torsion_points())) sage: P._has_order_at_least(5) True - sage: P._has_order_at_least(6) + sage: P._has_order_at_least(6) # long time -- 5s sage: P.order() 5 sage: Q = E.lift_x(10^42, extend=True) @@ -3992,8 +4270,9 @@ def _magma_init_(self, magma): def _acted_upon_(self, other, side): r""" - We implement ``_acted_upon_`` to keep track of cached - point orders when scalar multiplications are applied. + We implement ``_acted_upon_`` to make use of the specialized faster + scalar multiplication from PARI, and to keep track of cached point + orders when scalar multiplications are applied. EXAMPLES:: @@ -4323,8 +4602,8 @@ def padic_elliptic_logarithm(self, Q, p): if Q.is_zero(): k = 0 else: - for k in range(0,p): - Eqp = EllipticCurve(Qp(p, 2), [ ZZ(t) + k * p for t in E.a_invariants() ]) + for k in range(p): + Eqp = EllipticCurve(Qp(p, 2), [ZZ(t) + k * p for t in E.a_invariants()]) P_Qps = Eqp.lift_x(ZZ(self.x()), all=True) for P_Qp in P_Qps: diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py old mode 100755 new mode 100644 index 2f2868d37ca..134531ad1a5 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -808,16 +808,28 @@ def two_descent(self, verbose=True, - ``selmer_only`` -- boolean (default: ``False``); selmer_only switch - - ``first_limit`` -- (default: 20) firstlim is bound - on x+z second_limit- (default: 8) secondlim is bound on log max - x,z , i.e. logarithmic - - - ``n_aux`` -- (default: -1) n_aux only relevant for - general 2-descent when 2-torsion trivial; n_aux=-1 causes default - to be used (depends on method) - - - ``second_descent`` -- (default: ``True``) - second_descent only relevant for descent via 2-isogeny + - ``first_limit`` -- integer (default: 20); naive height bound on + first point search on quartic homogeneous spaces (before + testing local solubility; very simple search with no + overheads). + + - ``second_limit`` -- integer (default: 8); logarithmic height bound on + second point search on quartic homogeneous spaces (after + testing local solubility; sieve-assisted search) + + - ``n_aux`` -- integer (default: -1); if positive, the number of + auxiliary primes used in sieve-assisted search for quartics. + If -1 (the default) use a default value (set in the eclib + code in ``src/qrank/mrank1.cc`` in DEFAULT_NAUX: currently 8). + Only relevant for curves with no 2-torsion, where full + 2-descent is carried out. Worth increasing for curves + expected to be of rank > 6 to one or two more than the + expected rank. + + - ``second_descent`` -- boolean (default: ``True``); flag specifying + whether or not a second descent will be carried out. Only relevant + for curves with 2-torsion. Recommended left as the default except for + experts interested in details of Selmer groups. OUTPUT: @@ -2256,9 +2268,9 @@ def gens(self, proof=None, **kwds): - ``algorithm`` -- one of the following: - - ``'mwrank_shell'`` -- default; call mwrank shell command + - ``'mwrank_lib'`` -- default; call mwrank C library - - ``'mwrank_lib'`` -- call mwrank C library + - ``'mwrank_shell'`` -- call mwrank shell command - ``'pari'`` -- use ellrank in pari @@ -2268,7 +2280,11 @@ def gens(self, proof=None, **kwds): - ``use_database`` -- boolean (default: ``True``); if ``True``, attempts to find curve and gens in the (optional) database - - ``descent_second_limit`` -- (default: 12) used in 2-descent + - ``descent_second_limit`` -- (default: 12); logarithmic height bound on + second point search on quartic homogeneous spaces (after + testing local solubility; sieve-assisted search). Used in 2-descent. + See also ``second_limit`` + in :meth:`~sage.libs.eclib.interface.mwrank_EllipticCurve.two_descent` - ``sat_bound`` -- (default: 1000) bound on primes used in saturation. If the computed bound on the index of the diff --git a/src/sage/schemes/elliptic_curves/ell_tate_curve.py b/src/sage/schemes/elliptic_curves/ell_tate_curve.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/ell_torsion.py b/src/sage/schemes/elliptic_curves/ell_torsion.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/ell_wp.py b/src/sage/schemes/elliptic_curves/ell_wp.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/formal_group.py b/src/sage/schemes/elliptic_curves/formal_group.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/gal_reps.py b/src/sage/schemes/elliptic_curves/gal_reps.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/hom.py b/src/sage/schemes/elliptic_curves/hom.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/hom_composite.py b/src/sage/schemes/elliptic_curves/hom_composite.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/hom_sum.py b/src/sage/schemes/elliptic_curves/hom_sum.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/jacobian.py b/src/sage/schemes/elliptic_curves/jacobian.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/kodaira_symbol.py b/src/sage/schemes/elliptic_curves/kodaira_symbol.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/kraus.py b/src/sage/schemes/elliptic_curves/kraus.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/lseries_ell.py b/src/sage/schemes/elliptic_curves/lseries_ell.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/meson.build b/src/sage/schemes/elliptic_curves/meson.build index 3448c5d1c0a..b2a3dda08c9 100644 --- a/src/sage/schemes/elliptic_curves/meson.build +++ b/src/sage/schemes/elliptic_curves/meson.build @@ -1,6 +1,8 @@ py.install_sources( 'BSD.py', 'Qcurves.py', + '__init__.py', + 'addition_formulas_ring.py', 'all.py', 'cardinality.py', 'cm.py', diff --git a/src/sage/schemes/elliptic_curves/mod_poly.py b/src/sage/schemes/elliptic_curves/mod_poly.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/mod_sym_num.pyx b/src/sage/schemes/elliptic_curves/mod_sym_num.pyx old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/modular_parametrization.py b/src/sage/schemes/elliptic_curves/modular_parametrization.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/padic_lseries.py b/src/sage/schemes/elliptic_curves/padic_lseries.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/padics.py b/src/sage/schemes/elliptic_curves/padics.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py old mode 100755 new mode 100644 index e6008a09279..54cd135dea9 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -111,11 +111,12 @@ from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import from sage.modules.free_module import FreeModule_generic_pid -from sage.rings.complex_mpfr import ComplexField, ComplexNumber +from sage.rings.complex_mpfr import ComplexField, ComplexNumber, ComplexField_class from sage.rings.infinity import Infinity from sage.rings.integer_ring import ZZ +from sage.rings.qqbar import AA, QQbar from sage.rings.rational_field import QQ -from sage.rings.real_mpfr import RealField, RealNumber +from sage.rings.real_mpfr import RealField, RealField_class, RealNumber from sage.schemes.elliptic_curves.constructor import EllipticCurve from sage.structure.richcmp import richcmp_method, richcmp, richcmp_not_equal @@ -212,9 +213,16 @@ def __init__(self, E, embedding=None): sage: L = PeriodLattice_ell(E,emb) sage: L == loads(dumps(L)) True - """ - from sage.rings.qqbar import AA, QQbar + Elliptic curve over imaginary number field without ``embedding`` specified:: + + sage: E = EllipticCurve(QQ[I], [5, -3*I]) + sage: L = PeriodLattice_ell(E, embedding=None) + sage: L.elliptic_logarithm(E(I+1, I+2)) # abs tol 1e-15 + -0.773376784700140 - 0.177736018028666*I + sage: L.elliptic_exponential(_) # abs tol 1e-15 + (1.00000000000000 - 1.00000000000000*I : 2.00000000000000 - 1.00000000000000*I : 1.00000000000000) + """ # First we cache the elliptic curve with this period lattice: self.E = E @@ -223,12 +231,20 @@ def __init__(self, E, embedding=None): # the given embedding: K = E.base_field() + self.is_approximate = isinstance(K, (RealField_class, ComplexField_class)) if embedding is None: - embs = K.embeddings(AA) - real = len(embs) > 0 - if not real: - embs = K.embeddings(QQbar) - embedding = embs[0] + if K in (AA, QQbar): + embedding = K.hom(QQbar) + real = K == AA + elif self.is_approximate: + embedding = K.hom(K) + real = isinstance(K, RealField_class) + else: + embs = K.embeddings(AA) + real = len(embs) > 0 + if not real: + embs = K.embeddings(QQbar) + embedding = embs[0] else: embedding = refine_embedding(embedding, Infinity) real = embedding(K.gen()).imag().is_zero() @@ -255,20 +271,24 @@ def __init__(self, E, embedding=None): # The ei are used both for period computation and elliptic # logarithms. - self.Ebar = self.E.change_ring(self.embedding) - self.f2 = self.Ebar.two_division_polynomial() + if self.is_approximate: + self.f2 = self.E.two_division_polynomial() + else: + self.Ebar = self.E.change_ring(self.embedding) + self.f2 = self.Ebar.two_division_polynomial() if self.real_flag == 1: # positive discriminant - self._ei = self.f2.roots(AA,multiplicities=False) + self._ei = self.f2.roots(K if self.is_approximate else AA,multiplicities=False) self._ei.sort() # e1 < e2 < e3 e1, e2, e3 = self._ei elif self.real_flag == -1: # negative discriminant - self._ei = self.f2.roots(QQbar, multiplicities=False) + self._ei = self.f2.roots(ComplexField(K.precision()) if self.is_approximate else QQbar, multiplicities=False) self._ei = sorted(self._ei, key=lambda z: z.imag()) e1, e3, e2 = self._ei # so e3 is real - e3 = AA(e3) + if not self.is_approximate: + e3 = AA(e3) self._ei = [e1, e2, e3] else: - self._ei = self.f2.roots(QQbar, multiplicities=False) + self._ei = self.f2.roots(ComplexField(K.precision()) if self.is_approximate else QQbar, multiplicities=False) e1, e2, e3 = self._ei # The quantities sqrt(e_i-e_j) are cached (as elements of @@ -329,7 +349,8 @@ def __repr__(self): To: Algebraic Real Field Defn: a |--> 1.259921049894873? """ - if self.E.base_field() is QQ: + K = self.E.base_field() + if K in (QQ, AA, QQbar) or isinstance(K, (RealField_class, ComplexField_class)): return "Period lattice associated to %s" % (self.E) return "Period lattice associated to %s with respect to the embedding %s" % (self.E, self.embedding) @@ -364,8 +385,8 @@ def __call__(self, P, prec=None): sage: P = E([-1,1]) sage: P.is_on_identity_component () False - sage: L(P, prec=96) - 0.4793482501902193161295330101 + 0.985868850775824102211203849...*I + sage: L(P, prec=96) # abs tol 1e-27 + 0.4793482501902193161295330101 + 0.985868850775824102211203849*I sage: Q = E([3,5]) sage: Q.is_on_identity_component() True @@ -630,6 +651,13 @@ def tau(self, prec=None, algorithm='sage'): w1, w2 = self.normalised_basis(prec=prec, algorithm=algorithm) return w1/w2 + @cached_method + def _compute_default_prec(self): + r""" + Internal function to compute the default precision to be used if nothing is passed in. + """ + return self.E.base_field().precision() if self.is_approximate else RealField().precision() + @cached_method def _compute_periods_real(self, prec=None, algorithm='sage'): r""" @@ -670,13 +698,13 @@ def _compute_periods_real(self, prec=None, algorithm='sage'): 1.9072648860892725468182549468 - 1.3404778596244020196600112394*I) """ if prec is None: - prec = 53 + prec = self._compute_default_prec() R = RealField(prec) C = ComplexField(prec) if algorithm == 'pari': ainvs = self.E.a_invariants() - if self.E.base_field() is not QQ: + if self.E.base_field() is not QQ and not self.is_approximate: ainvs = [C(self.embedding(ai)).real() for ai in ainvs] # The precision for omega() is determined by ellinit() @@ -688,9 +716,8 @@ def _compute_periods_real(self, prec=None, algorithm='sage'): raise ValueError("invalid value of 'algorithm' parameter") pi = R.pi() - # Up to now everything has been exact in AA or QQbar, but now - # we must go transcendental. Only now is the desired - # precision used! + # Up to now everything has been exact in AA or QQbar (unless self.is_approximate), + # but now we must go transcendental. Only now is the desired precision used! if self.real_flag == 1: # positive discriminant a, b, c = (R(x) for x in self._abc) w1 = R(pi/a.agm(b)) # least real period @@ -758,12 +785,11 @@ def _compute_periods_complex(self, prec=None, normalise=True): 0.692321964451917 """ if prec is None: - prec = RealField().precision() + prec = self._compute_default_prec() C = ComplexField(prec) - # Up to now everything has been exact in AA, but now we - # must go transcendental. Only now is the desired - # precision used! + # Up to now everything has been exact in AA or QQbar (unless self.is_approximate), + # but now we must go transcendental. Only now is the desired precision used! pi = C.pi() a, b, c = (C(x) for x in self._abc) if (a+b).abs() < (a-b).abs(): @@ -1107,7 +1133,7 @@ def sigma(self, z, prec=None, flag=0): 2.60912163570108 - 0.200865080824587*I """ if prec is None: - prec = RealField().precision() + prec = self._compute_default_prec() try: return self.E.pari_curve().ellsigma(z, flag, precision=prec) except AttributeError: @@ -1211,14 +1237,14 @@ def coordinates(self, z, rounding=None): sage: L = E.period_lattice() sage: w1, w2 = L.basis(prec=100) sage: P = E([-1,1]) - sage: zP = P.elliptic_logarithm(precision=100); zP + sage: zP = P.elliptic_logarithm(precision=100); zP # abs tol 1e-28 0.47934825019021931612953301006 + 0.98586885077582410221120384908*I - sage: L.coordinates(zP) + sage: L.coordinates(zP) # abs tol 1e-28 (0.19249290511394227352563996419, 0.50000000000000000000000000000) - sage: sum([x*w for x, w in zip(L.coordinates(zP), L.basis(prec=100))]) + sage: sum([x*w for x, w in zip(L.coordinates(zP), L.basis(prec=100))]) # abs tol 1e-28 0.47934825019021931612953301006 + 0.98586885077582410221120384908*I - sage: L.coordinates(12*w1 + 23*w2) + sage: L.coordinates(12*w1 + 23*w2) # abs tol 1e-28 (12.000000000000000000000000000, 23.000000000000000000000000000) sage: L.coordinates(12*w1 + 23*w2, rounding='floor') (11, 22) @@ -1276,17 +1302,17 @@ def reduce(self, z): sage: L = E.period_lattice() sage: w1, w2 = L.basis(prec=100) sage: P = E([-1,1]) - sage: zP = P.elliptic_logarithm(precision=100); zP + sage: zP = P.elliptic_logarithm(precision=100); zP # abs tol 1e-28 0.47934825019021931612953301006 + 0.98586885077582410221120384908*I - sage: z = zP + 10*w1 - 20*w2; z + sage: z = zP + 10*w1 - 20*w2; z # abs tol 1e-28 25.381473858740770069343110929 - 38.448885180257139986236950114*I - sage: L.reduce(z) + sage: L.reduce(z) # abs tol 1e-28 0.47934825019021931612953301006 + 0.98586885077582410221120384908*I - sage: L.elliptic_logarithm(2*P) + sage: L.elliptic_logarithm(2*P) # abs tol 1e-15 0.958696500380439 - sage: L.reduce(L.elliptic_logarithm(2*P)) + sage: L.reduce(L.elliptic_logarithm(2*P)) # abs tol 1e-15 0.958696500380439 - sage: L.reduce(L.elliptic_logarithm(2*P) + 10*w1 - 20*w2) + sage: L.reduce(L.elliptic_logarithm(2*P) + 10*w1 - 20*w2) # abs tol 1e-15 0.958696500380444 """ C = z.parent() @@ -1366,12 +1392,12 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): The elliptic log from the real coordinates:: - sage: L.e_log_RC(xP, yP) + sage: L.e_log_RC(xP, yP) # abs tol 1e-15 0.479348250190219 + 0.985868850775824*I The same elliptic log from the algebraic point:: - sage: L(P) + sage: L(P) # abs tol 1e-15 0.479348250190219 + 0.985868850775824*I A number field example:: @@ -1383,10 +1409,10 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): sage: v = K.real_places()[0] sage: L = E.period_lattice(v) sage: P = E.lift_x(1/3*a^2 + a + 5/3) - sage: L(P) + sage: L(P) # abs tol 1e-15 3.51086196882538 sage: xP, yP = [v(c) for c in P.xy()] - sage: L.e_log_RC(xP, yP) + sage: L.e_log_RC(xP, yP) # abs tol 1e-15 3.51086196882538 Elliptic logs of real points which do not come from algebraic @@ -1396,11 +1422,11 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): sage: ER = EllipticCurve([v(ai) for ai in E.a_invariants()]) sage: P = ER.lift_x(12.34) sage: xP, yP = P.xy() - sage: xP, yP + sage: xP, yP # abs tol 1e-15 (12.3400000000000, -43.3628968710567) - sage: L.e_log_RC(xP, yP) + sage: L.e_log_RC(xP, yP) # abs tol 1e-15 0.284656841192041 - sage: xP, yP = ER.lift_x(0).xy() + sage: xP, yP = ER.lift_x(0).xy() # abs tol 1e-15 sage: L.e_log_RC(xP, yP) 1.34921304541057 @@ -1410,18 +1436,18 @@ def e_log_RC(self, xP, yP, prec=None, reduce=True): sage: v = K.complex_embeddings()[0] sage: L = E.period_lattice(v) sage: P = E.lift_x(1/3*a^2 + a + 5/3) - sage: L(P) + sage: L(P) # abs tol 1e-15 1.68207104397706 - 1.87873661686704*I sage: xP, yP = [v(c) for c in P.xy()] - sage: L.e_log_RC(xP, yP) + sage: L.e_log_RC(xP, yP) # abs tol 1e-15 1.68207104397706 - 1.87873661686704*I sage: EC = EllipticCurve([v(ai) for ai in E.a_invariants()]) sage: xP, yP = EC.lift_x(0).xy() - sage: L.e_log_RC(xP, yP) + sage: L.e_log_RC(xP, yP) # abs tol 1e-15 2.06711431204080 - 1.73451485683471*I """ if prec is None: - prec = RealField().precision() + prec = self._compute_default_prec() # Note: using log2(prec) + 3 guard bits is usually enough. # To avoid computing a logarithm, we use 40 guard bits which # should be largely enough in practice. @@ -1709,11 +1735,61 @@ def elliptic_logarithm(self, P, prec=None, reduce=True): 1.17058357737548897849026170185581196033579563441850967539191867385734983296504066660506637438866628981886518901958717288150400849746892393771983141354 - 1.13513899565966043682474529757126359416758251309237866586896869548539516543734207347695898664875799307727928332953834601460994992792519799260968053875*I sage: L.elliptic_logarithm(P, prec=1000) 1.17058357737548897849026170185581196033579563441850967539191867385734983296504066660506637438866628981886518901958717288150400849746892393771983141354014895386251320571643977497740116710952913769943240797618468987304985625823413440999754037939123032233879499904283600304184828809773650066658885672885 - 1.13513899565966043682474529757126359416758251309237866586896869548539516543734207347695898664875799307727928332953834601460994992792519799260968053875387282656993476491590607092182964878750169490985439873220720963653658829712494879003124071110818175013453207439440032582917366703476398880865439217473*I + + Elliptic curve over ``QQbar``:: + + sage: E = EllipticCurve(QQbar, [sqrt(2), I]) + sage: L = E.period_lattice() + sage: P = E.lift_x(3) + sage: L.elliptic_logarithm(P) + -1.97657221097437 - 1.05021415535949*I + sage: L.elliptic_exponential(_) # abs tol 1e-15 + (3.00000000000000 + 9.20856947066460e-16*I : -5.59022723358798 - 0.0894418024719718*I : 1.00000000000000) + sage: L.elliptic_logarithm(P, prec=100) # abs tol 1e-15 + -3.4730631218714889933426781799 + 0.44627675553762761312098773197*I + sage: L.elliptic_exponential(_) # abs tol 1e-28 + (3.0000000000000000000000000000 - 1.4773628579202938936348512161e-30*I : -5.5902272335879800026836302686 - 0.089441802471969391005702381090*I : 1.0000000000000000000000000000) + + Real approximate field, negative discriminant. Note that the output precision uses the precision of the base field:: + + sage: E = EllipticCurve(RealField(100), [1, 6]) + sage: L = E.period_lattice() + sage: L.real_flag + -1 + sage: P = E(3, 6) + sage: L.elliptic_logarithm(P) + 2.4593388737550379526023682666 + sage: L.elliptic_exponential(_) + (3.0000000000000000000000000000 : 5.9999999999999999999999999999 : 1.0000000000000000000000000000) + + Real approximate field, positive discriminant:: + + sage: E = EllipticCurve(RealField(100), [-4, 3]) + sage: L = E.period_lattice() + sage: L.real_flag + 1 + sage: P = E.lift_x(4) + sage: L.elliptic_logarithm(P) + 0.51188849089267627141925354967 + sage: L.elliptic_exponential(_) + (4.0000000000000000000000000000 : -7.1414284285428499979993998114 : 1.0000000000000000000000000000) + + Complex approximate field:: + + sage: E = EllipticCurve(ComplexField(100), [I, 3*I+4]) + sage: L = E.period_lattice() + sage: L.real_flag + 0 + sage: P = E.lift_x(4) + sage: L.elliptic_logarithm(P) + -1.1447032790074574712147458157 - 0.72429843602171875396186134806*I + sage: L.elliptic_exponential(_) + (4.0000000000000000000000000000 + 1.2025589033682610849950210280e-30*I : -8.2570982991257407680322611854 - 0.42387771989714340809597881586*I : 1.0000000000000000000000000000) """ if P.curve() is not self.E: raise ValueError("Point is on the wrong curve") if prec is None: - prec = RealField().precision() + prec = self._compute_default_prec() if P.is_zero(): return ComplexField(prec)(0) @@ -1826,8 +1902,8 @@ def elliptic_exponential(self, z, to_curve=True): sage: E = EllipticCurve('37a') sage: K. = QuadraticField(-5) sage: L = E.change_ring(K).period_lattice(K.places()[0]) - sage: L.elliptic_exponential(CDF(.1,.1)) - (0.0000142854026029... - 49.9960001066650*I + sage: L.elliptic_exponential(CDF(.1,.1)) # abs tol 1e-15 + (0.0000142854026029 - 49.9960001066650*I : 249.520141250950 + 250.019855549131*I : 1.00000000000000) sage: L.elliptic_exponential(CDF(.1,.1), to_curve=False) (0.0000142854026029447 - 49.9960001066650*I, @@ -1926,7 +2002,10 @@ def elliptic_exponential(self, z, to_curve=True): if to_curve: K = x.parent() - v = refine_embedding(self.embedding, Infinity) + if self.is_approximate: + v = self.embedding + else: + v = refine_embedding(self.embedding, Infinity) a1, a2, a3, a4, a6 = (K(v(a)) for a in self.E.ainvs()) b2 = K(v(self.E.b2())) x = x - b2 / 12 diff --git a/src/sage/schemes/elliptic_curves/period_lattice_region.pyx b/src/sage/schemes/elliptic_curves/period_lattice_region.pyx old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/sha_tate.py b/src/sage/schemes/elliptic_curves/sha_tate.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/elliptic_curves/weierstrass_transform.py b/src/sage/schemes/elliptic_curves/weierstrass_transform.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py old mode 100755 new mode 100644 index a0257a065fd..3b135e39975 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -1196,16 +1196,14 @@ def irreducible_components(self): sage: PP. = ProjectiveSpace(4, QQ) sage: V = PP.subscheme((x^2 - y^2 - z^2) * (w^5 - 2*v^2*z^3) * w * (v^3 - x^2*z)) sage: V.irreducible_components() # needs sage.libs.singular - [ - Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: - w, - Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: - x^2 - y^2 - z^2, - Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: - x^2*z - v^3, - Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: - w^5 - 2*z^3*v^2 - ] + [Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: + w, + Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: + x^2 - y^2 - z^2, + Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: + x^2*z - v^3, + Closed subscheme of Projective Space of dimension 4 over Rational Field defined by: + w^5 - 2*z^3*v^2] We verify that the irrelevant ideal is not accidentally returned (see :issue:`6920`):: @@ -1216,9 +1214,7 @@ def irreducible_components(self): sage: I = [f] + [f.derivative(zz) for zz in PP.gens()] sage: V = PP.subscheme(I) sage: V.irreducible_components() # needs sage.libs.singular - [ - - ] + [] The same polynomial as above defines a scheme with a nontrivial irreducible component in affine space (instead of @@ -1227,13 +1223,11 @@ def irreducible_components(self): sage: AA. = AffineSpace(4, QQ) sage: V = AA.subscheme(I) sage: V.irreducible_components() # needs sage.libs.singular - [ - Closed subscheme of Affine Space of dimension 4 over Rational Field defined by: - w, - z, - y, - x - ] + [Closed subscheme of Affine Space of dimension 4 over Rational Field defined by: + w, + z, + y, + x] """ try: return self.__irreducible_components diff --git a/src/sage/schemes/generic/ambient_space.py b/src/sage/schemes/generic/ambient_space.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/generic/divisor.py b/src/sage/schemes/generic/divisor.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/generic/divisor_group.py b/src/sage/schemes/generic/divisor_group.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/generic/glue.py b/src/sage/schemes/generic/glue.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/generic/hypersurface.py b/src/sage/schemes/generic/hypersurface.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/generic/point.py b/src/sage/schemes/generic/point.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/generic/spec.py b/src/sage/schemes/generic/spec.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/constructor.py b/src/sage/schemes/hyperelliptic_curves/constructor.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx b/src/sage/schemes/hyperelliptic_curves/hypellfrob.pyx old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_padic_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_rational_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/invariants.py b/src/sage/schemes/hyperelliptic_curves/invariants.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py b/src/sage/schemes/hyperelliptic_curves/jacobian_endomorphism_utils.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py b/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py old mode 100755 new mode 100644 index efc2a805bc0..c83c1a0997c --- a/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py @@ -185,7 +185,7 @@ def _have_established_geometrically_trivial(self): trivial. This is related to the warning at the top of the - `jacobian_endomorphism_utils.py` module. + ``jacobian_endomorphism_utils.py`` module. INPUT: @@ -214,7 +214,7 @@ def _have_established_geometrically_field(self): trivial. This is related to the warning at the top of the - `jacobian_endomorphism_utils.py` module. + ``jacobian_endomorphism_utils.py`` module. INPUT: diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/meson.build b/src/sage/schemes/hyperelliptic_curves/meson.build index e4b017d4192..170d08baaca 100644 --- a/src/sage/schemes/hyperelliptic_curves/meson.build +++ b/src/sage/schemes/hyperelliptic_curves/meson.build @@ -1,5 +1,6 @@ inc_hypellfrob = include_directories('hypellfrob') py.install_sources( + '__init__.py', 'all.py', 'constructor.py', 'hyperelliptic_finite_field.py', diff --git a/src/sage/schemes/hyperelliptic_curves/mestre.py b/src/sage/schemes/hyperelliptic_curves/mestre.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/jacobians/abstract_jacobian.py b/src/sage/schemes/jacobians/abstract_jacobian.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/meson.build b/src/sage/schemes/meson.build index c74c532b930..4dac80900e9 100644 --- a/src/sage/schemes/meson.build +++ b/src/sage/schemes/meson.build @@ -1,4 +1,9 @@ -py.install_sources('all.py', 'overview.py', subdir: 'sage/schemes') +py.install_sources( + '__init__.py', + 'all.py', + 'overview.py', + subdir: 'sage/schemes', +) install_subdir('affine', install_dir: sage_install_dir / 'schemes') install_subdir('berkovich', install_dir: sage_install_dir / 'schemes') diff --git a/src/sage/schemes/plane_conics/con_field.py b/src/sage/schemes/plane_conics/con_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/plane_conics/con_finite_field.py b/src/sage/schemes/plane_conics/con_finite_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/plane_conics/con_number_field.py b/src/sage/schemes/plane_conics/con_number_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/plane_conics/con_rational_field.py b/src/sage/schemes/plane_conics/con_rational_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/plane_conics/con_rational_function_field.py b/src/sage/schemes/plane_conics/con_rational_function_field.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/plane_conics/constructor.py b/src/sage/schemes/plane_conics/constructor.py old mode 100755 new mode 100644 index a08089522c2..49e3f77e28e --- a/src/sage/schemes/plane_conics/constructor.py +++ b/src/sage/schemes/plane_conics/constructor.py @@ -33,7 +33,7 @@ from sage.rings.number_field.number_field_base import NumberField from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.schemes.affine.affine_point import SchemeMorphism_point_affine from sage.schemes.projective.projective_point import SchemeMorphism_point_projective_field @@ -240,7 +240,7 @@ def Conic(base_field, F=None, names=None, unique=True): return ProjectiveConic_rational_field(P2, F) if isinstance(base_field, NumberField): return ProjectiveConic_number_field(P2, F) - if isinstance(base_field, FractionField_generic) and isinstance(base_field.ring(), (PolynomialRing_general, MPolynomialRing_base)): + if isinstance(base_field, FractionField_generic) and isinstance(base_field.ring(), (PolynomialRing_generic, MPolynomialRing_base)): return ProjectiveConic_rational_function_field(P2, F) return ProjectiveConic_field(P2, F) diff --git a/src/sage/schemes/plane_quartics/quartic_constructor.py b/src/sage/schemes/plane_quartics/quartic_constructor.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/plane_quartics/quartic_generic.py b/src/sage/schemes/plane_quartics/quartic_generic.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/product_projective/homset.py b/src/sage/schemes/product_projective/homset.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/product_projective/morphism.py b/src/sage/schemes/product_projective/morphism.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/product_projective/point.py b/src/sage/schemes/product_projective/point.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/product_projective/subscheme.py b/src/sage/schemes/product_projective/subscheme.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/projective/proj_bdd_height.py b/src/sage/schemes/projective/proj_bdd_height.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/projective/projective_homset.py b/src/sage/schemes/projective/projective_homset.py old mode 100755 new mode 100644 index 7f86f7ea0f6..da3f5b502cd --- a/src/sage/schemes/projective/projective_homset.py +++ b/src/sage/schemes/projective/projective_homset.py @@ -640,6 +640,8 @@ def _element_constructor_(self, *v, **kwds): """ if len(v) == 1: v = v[0] + if v == 0: + return self.zero() return self.codomain()._point(self.extended_codomain(), v, **kwds) def _repr_(self): @@ -689,6 +691,23 @@ def base_extend(self, R): 'implemented as modules over rings other than ZZ') return self + def zero(self): + r""" + Return the neutral element in this group of points. + + EXAMPLES:: + + sage: S = EllipticCurve(GF(5), [1,1]).point_homset() + sage: S.zero() + (0 : 1 : 0) + sage: S = EllipticCurve(Zmod(15), [1,1]).point_homset() + sage: S.zero() + (0 : 1 : 0) + """ + return self.codomain()(0) + + _an_element_ = zero + from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.schemes.generic.homset', diff --git a/src/sage/schemes/projective/projective_morphism.py b/src/sage/schemes/projective/projective_morphism.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py old mode 100755 new mode 100644 index c5d6b02c05a..88ab4eadcfc --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -533,7 +533,11 @@ def scale_by(self, t): def normalize_coordinates(self): """ - Removes the gcd from the coordinates of this point (including `-1`). + Removes the gcd from the coordinates of this point (including `-1`) + and rescales everything so that the last nonzero entry is as "simple" + as possible. The notion of "simple" here depends on the base ring; + concretely, the last nonzero coordinate will be `1` in a field and + positive over an ordered ring. .. WARNING:: The gcd will depend on the base ring. @@ -552,7 +556,7 @@ def normalize_coordinates(self): sage: P = ProjectiveSpace(Zp(7), 2, 'x') sage: p = P([-5, -15, -2]) sage: p.normalize_coordinates(); p - (5 + O(7^20) : 1 + 2*7 + O(7^20) : 2 + O(7^20)) + (6 + 3*7 + 3*7^2 + 3*7^3 + 3*7^4 + 3*7^5 + 3*7^6 + 3*7^7 + 3*7^8 + 3*7^9 + 3*7^10 + 3*7^11 + 3*7^12 + 3*7^13 + 3*7^14 + 3*7^15 + 3*7^16 + 3*7^17 + 3*7^18 + 3*7^19 + O(7^20) : 4 + 4*7 + 3*7^2 + 3*7^3 + 3*7^4 + 3*7^5 + 3*7^6 + 3*7^7 + 3*7^8 + 3*7^9 + 3*7^10 + 3*7^11 + 3*7^12 + 3*7^13 + 3*7^14 + 3*7^15 + 3*7^16 + 3*7^17 + 3*7^18 + 3*7^19 + O(7^20) : 1 + O(7^20)) :: @@ -576,8 +580,8 @@ def normalize_coordinates(self): sage: R. = PolynomialRing(QQ) sage: P = ProjectiveSpace(R, 1) sage: Q = P(2*c, 4*c) - sage: Q.normalize_coordinates();Q - (2 : 4) + sage: Q.normalize_coordinates(); Q + (1/2 : 1) A polynomial ring over a ring gives the more intuitive result. :: @@ -614,15 +618,19 @@ def normalize_coordinates(self): else: GCD = R(gcd(self._coords[0], self._coords[1])) index = 2 - neg = self._coords[0] <= 0 and self._coords[1] <= 0 - while not GCD.is_one() and index < len(self._coords): - neg = self._coords[index] <= 0 + while not GCD.is_unit() and index < len(self._coords): GCD = R(gcd(GCD, self._coords[index])) index += 1 - if not GCD.is_one(): + if not GCD.is_unit(): self.scale_by(~GCD) - if neg: - self.scale_by(-ZZ.one()) + index = len(self._coords) - 1 + while not self._coords[index]: + index -= 1 + if self._coords[index].is_unit(): + if not self._coords[index].is_one(): + self.scale_by(~self._coords[index]) + elif self._coords[index] < 0: + self.scale_by(-R.one()) self._normalized = True def dehomogenize(self, n): diff --git a/src/sage/schemes/projective/projective_rational_point.py b/src/sage/schemes/projective/projective_rational_point.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py old mode 100755 new mode 100644 index 89d4f28f48b..9073faa9706 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -100,7 +100,7 @@ from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from sage.rings.rational_field import QQ, RationalField from sage.schemes.generic.ambient_space import AmbientSpace @@ -248,7 +248,7 @@ def ProjectiveSpace(n, R=None, names=None): sage: P.gens() == R.gens() True """ - if isinstance(n, (MPolynomialRing_base, PolynomialRing_general)) and R is None: + if isinstance(n, (MPolynomialRing_base, PolynomialRing_generic)) and R is None: if names is not None: # Check for the case that the user provided a variable name # That does not match what we wanted to use from R diff --git a/src/sage/schemes/projective/projective_subscheme.py b/src/sage/schemes/projective/projective_subscheme.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/riemann_surfaces/riemann_surface.py b/src/sage/schemes/riemann_surfaces/riemann_surface.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/chow_group.py b/src/sage/schemes/toric/chow_group.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/divisor.py b/src/sage/schemes/toric/divisor.py old mode 100755 new mode 100644 index fe043e5dbb0..013c03030ee --- a/src/sage/schemes/toric/divisor.py +++ b/src/sage/schemes/toric/divisor.py @@ -2026,10 +2026,7 @@ class ToricRationalDivisorClassGroup_basis_lattice(FreeModule_ambient_pid): Basis lattice of The toric rational divisor class group of a 2-d CPR-Fano toric variety covered by 4 affine patches sage: L.basis() - [ - Divisor class [1, 0], - Divisor class [0, 1] - ] + [Divisor class [1, 0], Divisor class [0, 1]] """ def __init__(self, group): diff --git a/src/sage/schemes/toric/divisor_class.pyx b/src/sage/schemes/toric/divisor_class.pyx old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/fano_variety.py b/src/sage/schemes/toric/fano_variety.py old mode 100755 new mode 100644 index fcf5d03d476..fb8265818bd --- a/src/sage/schemes/toric/fano_variety.py +++ b/src/sage/schemes/toric/fano_variety.py @@ -129,7 +129,7 @@ from sage.rings.rational_field import QQ from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base -from sage.rings.polynomial.polynomial_ring import PolynomialRing_general +from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.fraction_field import FractionField_generic from sage.schemes.toric.toric_subscheme import AlgebraicScheme_subscheme_toric @@ -1583,7 +1583,7 @@ def add_variables(field, variables): if isinstance(field, FractionField_generic): # Q(a) ---> Q(a, b) rather than Q(a)(b) R = field.ring() - if isinstance(R, (PolynomialRing_general, MPolynomialRing_base)): + if isinstance(R, (PolynomialRing_generic, MPolynomialRing_base)): new_variables = list(R.variable_names()) for v in variables: if v not in new_variables: diff --git a/src/sage/schemes/toric/homset.py b/src/sage/schemes/toric/homset.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/ideal.py b/src/sage/schemes/toric/ideal.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/library.py b/src/sage/schemes/toric/library.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/meson.build b/src/sage/schemes/toric/meson.build index d9dea45fcc8..0e85031ccf5 100644 --- a/src/sage/schemes/toric/meson.build +++ b/src/sage/schemes/toric/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'chow_group.py', 'divisor.py', diff --git a/src/sage/schemes/toric/morphism.py b/src/sage/schemes/toric/morphism.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/points.py b/src/sage/schemes/toric/points.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/sheaf/constructor.py b/src/sage/schemes/toric/sheaf/constructor.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/sheaf/klyachko.py b/src/sage/schemes/toric/sheaf/klyachko.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/toric_subscheme.py b/src/sage/schemes/toric/toric_subscheme.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/variety.py b/src/sage/schemes/toric/variety.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/weierstrass.py b/src/sage/schemes/toric/weierstrass.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/weierstrass_covering.py b/src/sage/schemes/toric/weierstrass_covering.py old mode 100755 new mode 100644 diff --git a/src/sage/schemes/toric/weierstrass_higher.py b/src/sage/schemes/toric/weierstrass_higher.py old mode 100755 new mode 100644 diff --git a/src/sage/sets/disjoint_set.pyx b/src/sage/sets/disjoint_set.pyx index c2cce67037f..53e793755ec 100644 --- a/src/sage/sets/disjoint_set.pyx +++ b/src/sage/sets/disjoint_set.pyx @@ -556,10 +556,11 @@ cdef class DisjointSet_of_integers(DisjointSet_class): Add a new element into a new set containing only the new element. According to :wikipedia:`Disjoint-set_data_structure#Making_new_sets` the - `make_set` operation adds a new element into a new set containing only - the new element. The new set is added at the end of `self`. + ``make_set`` operation adds a new element into a new set containing only + the new element. The new set is added at the end of ``self``. EXAMPLES:: + sage: d = DisjointSet(5) sage: d.union(1, 2) sage: d.union(0, 1) @@ -568,6 +569,13 @@ cdef class DisjointSet_of_integers(DisjointSet_class): {{0, 1, 2}, {3}, {4}, {5}} sage: d.find(1) 1 + + TESTS:: + + sage: d = DisjointSet(0) + sage: d.make_set() + sage: d + {{0}} """ OP_make_set(self._nodes) @@ -874,8 +882,8 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): Add a new element into a new set containing only the new element. According to :wikipedia:`Disjoint-set_data_structure#Making_new_sets` - the `make_set` operation adds a new element into a new set containing - only the new element. The new set is added at the end of `self`. + the ``make_set`` operation adds a new element into a new set containing + only the new element. The new set is added at the end of ``self``. INPUT: diff --git a/src/sage/sets/family.pyx b/src/sage/sets/family.pyx index f87768f3989..0ccc4606ded 100644 --- a/src/sage/sets/family.pyx +++ b/src/sage/sets/family.pyx @@ -337,7 +337,10 @@ def Family(indices, function=None, hidden_keys=[], hidden_function=None, lazy=Fa sage: f = Family(list(range(1,27)), lambda i: chr(i+96)) sage: f - Finite family {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', 8: 'h', 9: 'i', 10: 'j', 11: 'k', 12: 'l', 13: 'm', 14: 'n', 15: 'o', 16: 'p', 17: 'q', 18: 'r', 19: 's', 20: 't', 21: 'u', 22: 'v', 23: 'w', 24: 'x', 25: 'y', 26: 'z'} + Finite family {1: 'a', 2: 'b', 3: 'c', 4: 'd', 5: 'e', 6: 'f', 7: 'g', + 8: 'h', 9: 'i', 10: 'j', 11: 'k', 12: 'l', 13: 'm', 14: 'n', 15: 'o', + 16: 'p', 17: 'q', 18: 'r', 19: 's', 20: 't', 21: 'u', 22: 'v', 23: 'w', + 24: 'x', 25: 'y', 26: 'z'} sage: f[2] 'b' diff --git a/src/sage/sets/finite_set_map_cy.pyx b/src/sage/sets/finite_set_map_cy.pyx index f41450d5842..73dbdfdd934 100644 --- a/src/sage/sets/finite_set_map_cy.pyx +++ b/src/sage/sets/finite_set_map_cy.pyx @@ -621,11 +621,10 @@ cdef class FiniteSetEndoMap_N(FiniteSetMap_MN): sage: F([1, 0, 2]) * F([2, 1, 0]) [1, 2, 0] """ - assert(self._parent is other._parent), "Parent mismatch" + assert (self._parent is other._parent), "Parent mismatch" if self._parent._action == "right": return self._compose_internal_(other, self._parent) - else: - return other._compose_internal_(self, self._parent) + return other._compose_internal_(self, self._parent) def __pow__(self, n, dummy): """ @@ -679,11 +678,10 @@ cdef class FiniteSetEndoMap_Set(FiniteSetMap_Set): sage: g * f map: a -> c, b -> c, c -> c """ - assert(self._parent is other._parent), "Parent mismatch" + assert (self._parent is other._parent), "Parent mismatch" if self._parent._action == "right": return self._compose_internal_(other, self._parent) - else: - return other._compose_internal_(self, self._parent) + return other._compose_internal_(self, self._parent) def __pow__(self, n, dummy): """ diff --git a/src/sage/sets/meson.build b/src/sage/sets/meson.build index 73faddaf9c7..92d4cb4cd17 100644 --- a/src/sage/sets/meson.build +++ b/src/sage/sets/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'all__sagemath_objects.py', 'cartesian_product.py', diff --git a/src/sage/sets/pythonclass.pyx b/src/sage/sets/pythonclass.pyx index 02f34931b64..8aab718a39c 100644 --- a/src/sage/sets/pythonclass.pyx +++ b/src/sage/sets/pythonclass.pyx @@ -3,15 +3,15 @@ Set of all objects of a given Python class """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2018 Jeroen Demeyer # # 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 cpython.object cimport Py_EQ, Py_NE from sage.structure.richcmp cimport rich_to_bool diff --git a/src/sage/sets/recursively_enumerated_set.pyx b/src/sage/sets/recursively_enumerated_set.pyx index 3d9d4a00f75..b20fa8cbe8a 100644 --- a/src/sage/sets/recursively_enumerated_set.pyx +++ b/src/sage/sets/recursively_enumerated_set.pyx @@ -286,8 +286,9 @@ from collections import deque def RecursivelyEnumeratedSet(seeds, successors, structure=None, - enumeration=None, max_depth=float("inf"), post_process=None, - facade=None, category=None): + enumeration=None, max_depth=float("inf"), + post_process=None, + facade=None, category=None): r""" Return a recursively enumerated set. @@ -470,7 +471,7 @@ cdef class RecursivelyEnumeratedSet_generic(Parent): A recursively enumerated set (breadth first search) """ assert enumeration in ['naive', 'depth', 'breadth'], \ - "unknown enumeration(={})".format(enumeration) + "unknown enumeration(={})".format(enumeration) self._seeds = seeds self.successors = successors @@ -480,7 +481,8 @@ cdef class RecursivelyEnumeratedSet_generic(Parent): if post_process is not None: self.post_process = post_process self._graded_component = None - Parent.__init__(self, facade=facade, category=EnumeratedSets().or_subcategory(category)) + Parent.__init__(self, facade=facade, + category=EnumeratedSets().or_subcategory(category)) def __reduce__(self): r""" @@ -1532,10 +1534,7 @@ def search_forest_iterator(roots, children, algorithm='depth'): # (you ask the children for the last node you met). Setting # position on 0 results in a breadth search (enumerate all the # descendants of a node before going on to the next father) - if algorithm == 'depth': - position = -1 - else: - position = 0 + position = -1 if algorithm == 'depth' else 0 # Invariant: # - for breadth first search: stack[i] contains an iterator over the nodes @@ -1555,7 +1554,7 @@ def search_forest_iterator(roots, children, algorithm='depth'): continue yield node - stack.append( iter(children(node)) ) + stack.append(iter(children(node))) class RecursivelyEnumeratedSet_forest(Parent): @@ -1742,8 +1741,8 @@ class RecursivelyEnumeratedSet_forest(Parent): sage: loads(dumps(S)) An enumerated set with a forest structure """ - def __init__(self, roots = None, children = None, post_process = None, - algorithm = 'depth', facade = None, category=None): + def __init__(self, roots=None, children=None, post_process=None, + algorithm='depth', facade=None, category=None): r""" TESTS:: @@ -1759,7 +1758,8 @@ class RecursivelyEnumeratedSet_forest(Parent): if post_process is not None: self.post_process = post_process self._algorithm = algorithm - Parent.__init__(self, facade = facade, category = EnumeratedSets().or_subcategory(category)) + Parent.__init__(self, facade=facade, + category=EnumeratedSets().or_subcategory(category)) __len__ = None @@ -1833,7 +1833,7 @@ class RecursivelyEnumeratedSet_forest(Parent): """ iter = search_forest_iterator(self.roots(), self.children, - algorithm = self._algorithm) + algorithm=self._algorithm) if hasattr(self, "post_process"): iter = _imap_and_filter_none(self.post_process, iter) return iter @@ -2016,7 +2016,7 @@ class RecursivelyEnumeratedSet_forest(Parent): """ stack = [iter(self.roots())] while stack: - position = randint(0,len(stack)-1) + position = randint(0, len(stack) - 1) try: node = next(stack[position]) except StopIteration: @@ -2025,12 +2025,12 @@ class RecursivelyEnumeratedSet_forest(Parent): if node == elt: return True - stack.append( iter(self.children(node)) ) + stack.append(iter(self.children(node))) return False - def map_reduce(self, map_function = None, - reduce_function = None, - reduce_init = None): + def map_reduce(self, map_function=None, + reduce_function=None, + reduce_init=None): r""" Apply a Map/Reduce algorithm on ``self``. @@ -2084,7 +2084,7 @@ class RecursivelyEnumeratedSet_forest(Parent): """ import sage.parallel.map_reduce return sage.parallel.map_reduce.RESetMapReduce( - forest = self, - map_function = map_function, - reduce_function = reduce_function, - reduce_init = reduce_init).run() + forest=self, + map_function=map_function, + reduce_function=reduce_function, + reduce_init=reduce_init).run() diff --git a/src/sage/stats/distributions/catalog.py b/src/sage/stats/distributions/catalog.py index f03bdd97ae3..8ae97fb24c4 100644 --- a/src/sage/stats/distributions/catalog.py +++ b/src/sage/stats/distributions/catalog.py @@ -17,14 +17,14 @@ sage: from sage.stats.distributions.catalog import * """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2024 Gareth Ma # # Distributed under the terms of the GNU General Public License (GPL), # version 2 or later (at your preference). # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.misc.lazy_import import lazy_import lazy_import("sage.stats.distributions.discrete_gaussian_integer", ["DiscreteGaussianDistributionIntegerSampler"]) diff --git a/src/sage/stats/distributions/meson.build b/src/sage/stats/distributions/meson.build index 129d5f74d13..db152755b95 100644 --- a/src/sage/stats/distributions/meson.build +++ b/src/sage/stats/distributions/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'catalog.py', 'dgs.pxd', diff --git a/src/sage/stats/hmm/chmm.pyx b/src/sage/stats/hmm/chmm.pyx index 540f91356d0..f345f47f09b 100644 --- a/src/sage/stats/hmm/chmm.pyx +++ b/src/sage/stats/hmm/chmm.pyx @@ -1332,7 +1332,7 @@ cdef class GaussianMixtureHiddenMarkovModel(GaussianHiddenMarkovModel): # the m-components of the probability. alpha_minus = alpha._values[t*N + j] / prob for m in range(M): - numer = alpha_minus * G.prob_m(obs._values[t], m) * beta._values[t*N + j] + numer = alpha_minus * G.prob_m(obs._values[t], m) * beta._values[t*N + j] mixed_gamma._values[m*T + t] = numer / P return mixed_gamma diff --git a/src/sage/stats/hmm/hmm.pxd b/src/sage/stats/hmm/hmm.pxd index 1abcb95392b..e1a2fa8590e 100644 --- a/src/sage/stats/hmm/hmm.pxd +++ b/src/sage/stats/hmm/hmm.pxd @@ -14,4 +14,3 @@ cdef class HiddenMarkovModel: cdef TimeSeries A, pi cdef TimeSeries _baum_welch_gamma(self, TimeSeries alpha, TimeSeries beta) - diff --git a/src/sage/stats/hmm/meson.build b/src/sage/stats/hmm/meson.build index cbf4a30caa5..661c578252e 100644 --- a/src/sage/stats/hmm/meson.build +++ b/src/sage/stats/hmm/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'distributions.pxd', 'hmm.pxd', diff --git a/src/sage/stats/hmm/util.pxd b/src/sage/stats/hmm/util.pxd index b0d399d9aaf..4be9fbd77d5 100644 --- a/src/sage/stats/hmm/util.pxd +++ b/src/sage/stats/hmm/util.pxd @@ -4,4 +4,3 @@ cdef class HMM_Util: cpdef normalize_probability_TimeSeries(self, TimeSeries T, Py_ssize_t i, Py_ssize_t j) cpdef TimeSeries initial_probs_to_TimeSeries(self, pi, bint normalize) cpdef TimeSeries state_matrix_to_TimeSeries(self, A, int N, bint normalize) - diff --git a/src/sage/stats/meson.build b/src/sage/stats/meson.build index 414a909270c..52c4b684ac4 100644 --- a/src/sage/stats/meson.build +++ b/src/sage/stats/meson.build @@ -1,4 +1,5 @@ py.install_sources( + '__init__.py', 'all.py', 'basic_stats.py', 'intlist.pxd', diff --git a/src/sage/stats/time_series.pyx b/src/sage/stats/time_series.pyx index 28318238a25..13ab0bf6614 100644 --- a/src/sage/stats/time_series.pyx +++ b/src/sage/stats/time_series.pyx @@ -465,7 +465,7 @@ cdef class TimeSeries: """ cdef Py_ssize_t i cdef TimeSeries t = new_time_series(self._length) - memcpy(t._values, self._values , sizeof(double)*self._length) + memcpy(t._values, self._values, sizeof(double)*self._length) return t def __add__(left, right): @@ -1971,7 +1971,7 @@ cdef class TimeSeries: mid = n + bin_size/2 right = n + 2*bin_size/3 - rgbcolor = 'blue' if open < close else 'red' + rgbcolor = 'blue' if open < close else 'red' p += line([(mid, low), (mid, high)], rgbcolor=rgbcolor) p += polygon([(left, open), (right, open), (right, close), (left, close)], rgbcolor=rgbcolor) diff --git a/src/sage/structure/__init__.py b/src/sage/structure/__init__.py index 2534e5a71f8..bf977ccc379 100644 --- a/src/sage/structure/__init__.py +++ b/src/sage/structure/__init__.py @@ -1,3 +1,3 @@ # sage_setup: distribution = sagemath-objects # Resolve a cyclic import -import sage.structure.element \ No newline at end of file +import sage.structure.element diff --git a/src/sage/structure/all.py b/src/sage/structure/all.py index 40b9daa67e8..785acc174e3 100644 --- a/src/sage/structure/all.py +++ b/src/sage/structure/all.py @@ -21,10 +21,10 @@ from sage.structure.proof import all as proof -from sage.misc.lazy_import import lazy_import -lazy_import('sage.structure.formal_sum', ['FormalSums', 'FormalSum']) -del lazy_import - from sage.structure.mutability import Mutability from sage.structure.element_wrapper import ElementWrapper + +from sage.misc.lazy_import import lazy_import +lazy_import('sage.structure.formal_sum', ['FormalSums', 'FormalSum']) +del lazy_import diff --git a/src/sage/structure/coerce.pyx b/src/sage/structure/coerce.pyx index cc2f1124cb4..6861cfb5be3 100644 --- a/src/sage/structure/coerce.pyx +++ b/src/sage/structure/coerce.pyx @@ -1891,7 +1891,7 @@ cdef class CoercionModel: 1/2*x sage: cm.discover_action(F, ZZ, operator.truediv) Right inverse action by Rational Field on - Free Algebra on 1 generators (x,) over Rational Field + Free Algebra on 1 generator (x,) over Rational Field with precomposition on right by Natural morphism: From: Integer Ring To: Rational Field diff --git a/src/sage/structure/element.pyx b/src/sage/structure/element.pyx index 14cae09d6f0..f8faa8a7737 100644 --- a/src/sage/structure/element.pyx +++ b/src/sage/structure/element.pyx @@ -817,9 +817,9 @@ cdef class Element(SageObject): ngens = parent.ngens() except (AttributeError, NotImplementedError, TypeError): return self - variables=[] - # use "gen" instead of "gens" as a ParentWithGens is not - # required to have the latter + variables = [] + + # using gen instead of gens for i in range(ngens): gen = parent.gen(i) if str(gen) in kwds: @@ -4661,7 +4661,7 @@ def coerce_binop(method): EXAMPLES: - Sparse polynomial rings uses `@coerce_binop` on `gcd`:: + Sparse polynomial rings uses ``@coerce_binop`` on ``gcd``:: sage: S. = PolynomialRing(ZZ, sparse=True) sage: f = x^2 @@ -4695,7 +4695,7 @@ def coerce_binop(method): sage: h.gcd(f, 'modular') 1 - We demonstrate a small class using `@coerce_binop` on a method:: + We demonstrate a small class using ``@coerce_binop`` on a method:: sage: from sage.structure.element import coerce_binop sage: class MyRational(Rational): @@ -4737,6 +4737,7 @@ def coerce_binop(method): TypeError: algorithm 1 not supported """ @sage_wraps(method) + @cython.binding(True) def new_method(self, other, *args, **kwargs): if have_same_parent(self, other): return method(self, other, *args, **kwargs) diff --git a/src/sage/structure/element_wrapper.pxd b/src/sage/structure/element_wrapper.pxd index dda6630c84d..158d5687a8a 100644 --- a/src/sage/structure/element_wrapper.pxd +++ b/src/sage/structure/element_wrapper.pxd @@ -10,4 +10,3 @@ cdef class ElementWrapper(Element): cdef class ElementWrapperCheckWrappedClass(ElementWrapper): pass - diff --git a/src/sage/structure/formal_sum.py b/src/sage/structure/formal_sum.py index ab72ff5eb2d..662e3b33240 100644 --- a/src/sage/structure/formal_sum.py +++ b/src/sage/structure/formal_sum.py @@ -65,11 +65,11 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** - -from sage.misc.repr import repr_lincomb import operator from collections import OrderedDict +from sage.misc.persist import register_unpickle_override +from sage.misc.repr import repr_lincomb from sage.modules.module import Module from sage.structure.element import ModuleElement from sage.structure.richcmp import richcmp @@ -392,11 +392,14 @@ def _element_constructor_(self, x, check=True, reduce=True): else: x = x._data if isinstance(x, list): - return self.element_class(x, check=check,reduce=reduce,parent=self) + return self.element_class(x, check=check, + reduce=reduce, parent=self) if x == 0: - return self.element_class([], check=False, reduce=False, parent=self) + return self.element_class([], check=False, + reduce=False, parent=self) else: - return self.element_class([(self.base_ring()(1), x)], check=False, reduce=False, parent=self) + return self.element_class([(self.base_ring()(1), x)], + check=False, reduce=False, parent=self) def _coerce_map_from_(self, X): r""" @@ -413,7 +416,7 @@ def _coerce_map_from_(self, X): From: Abelian Group of all Formal Finite Sums over Integer Ring To: Abelian Group of all Formal Finite Sums over Rational Field """ - if isinstance(X,FormalSums): + if isinstance(X, FormalSums): if self.base_ring().has_coerce_map_from(X.base_ring()): return True return False @@ -475,7 +478,7 @@ def _an_element_(self, check=False, reduce=False): 1/2 """ return self.element_class([(self.base_ring().an_element(), 1)], - check=check, reduce=reduce, parent=self) + check=check, reduce=reduce, parent=self) formal_sums = FormalSums() @@ -483,5 +486,4 @@ def _an_element_(self, check=False, reduce=False): # Formal sums now derives from UniqueRepresentation, which makes the # factory function unnecessary. This is why the name was changed from # class FormalSums_generic to class FormalSums. -from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.structure.formal_sum', 'FormalSums_generic', FormalSums) diff --git a/src/sage/structure/gens_py.py b/src/sage/structure/gens_py.py index 6d3fcae2520..99d881ae2cd 100644 --- a/src/sage/structure/gens_py.py +++ b/src/sage/structure/gens_py.py @@ -3,7 +3,7 @@ Pure python code for abstract base class for objects with generators """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2005 William Stein # # Distributed under the terms of the GNU General Public License (GPL) @@ -15,8 +15,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** def multiplicative_iterator(M): diff --git a/src/sage/structure/global_options.py b/src/sage/structure/global_options.py index 0f3308cc80f..d27bda16658 100644 --- a/src/sage/structure/global_options.py +++ b/src/sage/structure/global_options.py @@ -130,7 +130,7 @@ ....: cake='waist begins again', ....: cream='fluffy, white stuff')) ....: tip = dict(default=10, description='Reward for good service', - ....: checker = lambda tip: tip in range(0,20)) + ....: checker = lambda tip: tip in range(20)) sage: Menu.options Current options for menu - dessert: espresso @@ -409,7 +409,7 @@ class options(GlobalOptions): ....: cake='waist begins again', ....: cream='fluffy, white stuff')), ....: tip=dict(default=10, description='Reward for good service', - ....: checker=lambda tip: tip in range(0,20)) + ....: checker=lambda tip: tip in range(20)) ....: ) sage: Menu.options Current options for menu @@ -908,7 +908,7 @@ class GlobalOptions(metaclass=GlobalOptionsMeta): ....: cake='waist begins again', ....: cream='fluffy white stuff')) ....: tip = dict(default=10, description='Reward for good service', - ....: checker=lambda tip: tip in range(0,20)) + ....: checker=lambda tip: tip in range(20)) sage: Menu.options Current options for menu - dessert: espresso @@ -1013,7 +1013,7 @@ def __init__(self, NAME=None, module='', option_class='', doc='', end_doc='', ** ....: cake='waist begins again', ....: cream='fluffy white stuff')) ....: tip = dict(default=10, description='Reward for good service', - ....: checker=lambda tip: tip in range(0,20)) + ....: checker=lambda tip: tip in range(20)) sage: menu._name # Default name is class name 'menu' sage: class specials(GlobalOptions): @@ -1296,7 +1296,7 @@ def __setstate__(self, state): the :class:`GlobalOptions` class. The :meth:`__getstate__` method returns a dictionary with an - `options_class` key which identifies the "parent" class for the options. + ``options_class`` key which identifies the "parent" class for the options. This is then used to unpickle the options class. EXAMPLES:: diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index 7586eb06aaf..259398761bc 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -316,7 +316,7 @@ def _parse_names(self, m, use_latex): return names[m] except KeyError: return None - else: # treat it like a list + else: # treat it like a list try: i = self._indices.rank(m) except (AttributeError, TypeError, KeyError, ValueError): @@ -458,7 +458,7 @@ def _repr_generator(self, m): return self.prefix() + left + (', '.join(repr(val) for val in m)) + right if not quotes and isinstance(m, str): return self.prefix() + left + m + right - return self.prefix() + left + repr(m) + right # mind the (m), to accept a tuple for m + return self.prefix() + left + repr(m) + right # mind the (m), to accept a tuple for m def _ascii_art_generator(self, m): r""" diff --git a/src/sage/structure/list_clone_timings.py b/src/sage/structure/list_clone_timings.py index a072b7287a5..500167b1157 100644 --- a/src/sage/structure/list_clone_timings.py +++ b/src/sage/structure/list_clone_timings.py @@ -73,12 +73,12 @@ cy_add1_mutable(e) : 625 loops, best of 3: 14.1 µs per loop cy_add1_with(e) : 625 loops, best of 3: 17.5 µs per loop """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2009-2010 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.list_clone import ClonableArray from sage.structure.list_clone_demo import IncreasingArrays @@ -116,7 +116,7 @@ def check(self): ##################################################################### -###### Timings functions ###### +# Timings functions # ##################################################################### def add1_internal(bla): """ diff --git a/src/sage/structure/mutability.pyx b/src/sage/structure/mutability.pyx index 69d034bd8c3..a8808a29623 100644 --- a/src/sage/structure/mutability.pyx +++ b/src/sage/structure/mutability.pyx @@ -12,6 +12,7 @@ Mutability Cython Implementation # https://www.gnu.org/licenses/ ########################################################################## +cimport cython from sage.misc.decorators import sage_wraps cdef class Mutability: @@ -286,6 +287,7 @@ def require_mutable(f): - Simon King """ @sage_wraps(f) + @cython.binding(True) def new_f(self, *args, **kwds): if getattr(self, '_is_immutable', False): raise ValueError("{} instance is immutable, {} must not be called".format(type(self), repr(f))) @@ -338,6 +340,7 @@ def require_immutable(f): - Simon King """ @sage_wraps(f) + @cython.binding(True) def new_f(self, *args, **kwds): if not getattr(self,'_is_immutable',False): raise ValueError("{} instance is mutable, {} must not be called".format(type(self), repr(f))) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 8e8940b5846..1dd2ae070ca 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -2599,17 +2599,19 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: # needs sage.schemes sage: E = EllipticCurve([1,0]) sage: coercion_model.get_action(E, ZZ, operator.mul) - Right Integer Multiplication by Integer Ring - on Elliptic Curve defined by y^2 = x^3 + x over Rational Field + Right action by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x over Rational Field sage: coercion_model.get_action(ZZ, E, operator.mul) - Left Integer Multiplication by Integer Ring - on Elliptic Curve defined by y^2 = x^3 + x over Rational Field + Left action by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x over Rational Field sage: coercion_model.get_action(E, int, operator.mul) - Right Integer Multiplication by Set of Python objects of class 'int' - on Elliptic Curve defined by y^2 = x^3 + x over Rational Field + Right action by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x over Rational Field + with precomposition on right by Native morphism: + From: Set of Python objects of class 'int' + To: Integer Ring sage: coercion_model.get_action(int, E, operator.mul) - Left Integer Multiplication by Set of Python objects of class 'int' - on Elliptic Curve defined by y^2 = x^3 + x over Rational Field + Left action by Integer Ring on Elliptic Curve defined by y^2 = x^3 + x over Rational Field + with precomposition on left by Native morphism: + From: Set of Python objects of class 'int' + To: Integer Ring :: @@ -3042,8 +3044,7 @@ cdef class EltPair: sage: K. = Qq(9) # needs sage.rings.padics sage: E = EllipticCurve_from_j(0).base_extend(K) # needs sage.rings.padics sage: E.get_action(ZZ) # needs sage.rings.padics - Right Integer Multiplication - by Integer Ring + Right action by Integer Ring on Elliptic Curve defined by y^2 + (1+O(3^20))*y = x^3 over 3-adic Unramified Extension Field in a defined by x^2 + 2*x + 2 diff --git a/src/sage/structure/proof/all.py b/src/sage/structure/proof/all.py index 0db573b93ce..271109fb2e2 100644 --- a/src/sage/structure/proof/all.py +++ b/src/sage/structure/proof/all.py @@ -1,4 +1,5 @@ # sage_setup: distribution = sagemath-objects +from sage.structure.proof.proof import WithProof def arithmetic(t=None): @@ -240,6 +241,3 @@ def all(t=None): return _proof_prefs._require_proof.copy() for s in _proof_prefs._require_proof: _proof_prefs._require_proof[s] = bool(t) - - -from sage.structure.proof.proof import WithProof diff --git a/src/sage/structure/proof/proof.py b/src/sage/structure/proof/proof.py index c8c2df4cafe..b6b7d8b0509 100644 --- a/src/sage/structure/proof/proof.py +++ b/src/sage/structure/proof/proof.py @@ -225,7 +225,8 @@ def get_flag(t=None, subsystem=None): False """ if t is None: - if subsystem in ["arithmetic", "elliptic_curve", "linear_algebra", "number_field","polynomial"]: + if subsystem in ["arithmetic", "elliptic_curve", + "linear_algebra", "number_field", "polynomial"]: return _proof_prefs._require_proof[subsystem] else: return _proof_prefs._require_proof["other"] diff --git a/src/sage/structure/sequence.py b/src/sage/structure/sequence.py index cc9fcedadfe..614ad8c0fe4 100644 --- a/src/sage/structure/sequence.py +++ b/src/sage/structure/sequence.py @@ -70,13 +70,13 @@ # https://www.gnu.org/licenses/ # **************************************************************************** - +from sage.misc.persist import register_unpickle_override import sage.structure.sage_object import sage.structure.coerce def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=None, use_sage_types=False): - """ + r""" A mutable list of elements with a common guaranteed universe, which can be set immutable. @@ -98,10 +98,10 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non immutable - ``cr`` -- boolean (default: ``False``); if ``True``, then print a carriage return - after each comma when printing this sequence + after each comma when calling ``repr()`` on this sequence (see note below) - - ``cr_str`` -- boolean (default: ``False``); if ``True``, then print a carriage return - after each comma when calling ``str()`` on this sequence + - ``cr_str`` -- boolean (default: same as ``cr``); if ``True``, then print a carriage return + after each comma when calling ``str()`` on this sequence (see note below) - ``use_sage_types`` -- boolean (default: ``False``); if ``True``, coerce the built-in Python numerical types int, float, complex to the corresponding @@ -203,12 +203,55 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non sage: v.universe() Finite Field of size 5 + .. NOTE:: + + ``cr`` and ``cr_str`` is not recommended (because IPython's pretty printer is used); + nevertheless it is kept for backwards compatibility. + + By default ``Sequence`` are printed using IPython's pretty printer, + so ``cr`` and ``cr_str`` are not taken into account at all:: + + sage: Sequence([1, 2, 3], cr=False) + [1, 2, 3] + sage: Sequence([1, 2, 3], cr=True) + [1, 2, 3] + + Nevertheless, before the pretty printer exists, ``repr()`` is used. + Now ``cr`` and ``cr_str`` still affects the behavior of ``repr()`` and ``str()``:: + + sage: repr(Sequence([1, 2, 3], cr=False)) + '[1, 2, 3]' + sage: repr(Sequence([1, 2, 3], cr=True)) + '[\n1,\n2,\n3\n]' + + In any case, this behavior should probably not be relied upon. + TESTS:: sage: Sequence(["a"], universe=ZZ) Traceback (most recent call last): ... TypeError: unable to convert a to an element of Integer Ring + + Here are some tests for ``cr`` and ``cr_str``, even though they shouldn't be used. + ``cr_str`` can be weird in this case, but we keep the current implementation + (the feature is not recommended anyway so it doesn't make much difference):: + + sage: str(Sequence([1, 2, 3], cr=True, cr_str=True)) + '[\n1,\n2,\n3\n]' + sage: str(Sequence([1, 2, 3], cr=True, cr_str=False)) + '[\n1,\n2,\n3\n]' + + In the opposite case, ``cr_str`` works fine:: + + sage: str(Sequence([1, 2, 3], cr=False, cr_str=False)) + '[1, 2, 3]' + sage: str(Sequence([1, 2, 3], cr=False, cr_str=True)) + '[\n1,\n2,\n3\n]' + sage: repr(Sequence([1, 2, 3], cr=False, cr_str=False)) + '[1, 2, 3]' + sage: repr(Sequence([1, 2, 3], cr=False, cr_str=True)) + '[1, 2, 3]' """ if universe is None: if isinstance(x, Sequence_generic): @@ -239,7 +282,7 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non # start the pairwise coercion for i in range(len(x) - 1): try: - x[i], x[i+1] = sage.structure.element.canonical_coercion(x[i],x[i+1]) + x[i], x[i+1] = sage.structure.element.canonical_coercion(x[i], x[i+1]) except TypeError: from sage.categories.objects import Objects universe = Objects() @@ -257,7 +300,7 @@ def Sequence(x, universe=None, check=True, immutable=False, cr=False, cr_str=Non except ImportError: pass else: - if isinstance(universe, MPolynomialRing_base) or isinstance(universe, BooleanMonomialMonoid) or (isinstance(universe, QuotientRing_nc) and isinstance(universe.cover_ring(), MPolynomialRing_base)): + if isinstance(universe, (MPolynomialRing_base, BooleanMonomialMonoid)) or (isinstance(universe, QuotientRing_nc) and isinstance(universe.cover_ring(), MPolynomialRing_base)): return PolynomialSequence(x, universe, immutable=immutable, cr=cr, cr_str=cr_str) return Sequence_generic(x, universe, check, immutable, cr, cr_str, use_sage_types) @@ -285,8 +328,7 @@ class Sequence_generic(sage.structure.sage_object.SageObject, list): - ``immutable`` -- boolean (default: ``True``); whether or not this sequence is immutable - - ``cr`` -- boolean (default: ``False``); if ``True``, then print a carriage return - after each comma when printing this sequence + - ``cr``, ``cr_str`` -- see :func:`Sequence` - ``use_sage_types`` -- boolean (default: ``False``); if ``True``, coerce the built-in Python numerical types int, float, complex to the corresponding @@ -406,11 +448,7 @@ def __init__(self, x, universe=None, check=True, immutable=False, [1, 2, 3, 4, 5] sage: a = Sequence([1..3], universe=QQ, check=False, immutable=True, cr=True, cr_str=False, use_sage_types=True) sage: a - [ - 1, - 2, - 3 - ] + [1, 2, 3] sage: a = Sequence([1..5], universe=QQ, check=False, immutable=True, cr_str=True, use_sage_types=True) sage: a [1, 2, 3, 4, 5] @@ -515,16 +553,16 @@ def __getitem__(self, n): check=False, immutable=False, cr=self.__cr) - else: - return list.__getitem__(self,n) + + return list.__getitem__(self, n) # We have to define the *slice functions as long as Sage uses Python 2.* # otherwise the inherited *slice functions from list are called def __getslice__(self, i, j): - return self.__getitem__(slice(i,j)) + return self.__getitem__(slice(i, j)) def __setslice__(self, i, j, value): - return self.__setitem__(slice(i,j), value) + return self.__setitem__(slice(i, j), value) def append(self, x): """ @@ -646,6 +684,9 @@ def __hash__(self): def _repr_(self): """ + Return a string representation of this sequence. + Typically, :meth:`_repr_pretty_` is used instead of this method. + EXAMPLES:: sage: Sequence([1,2/3,-2/5])._repr_() @@ -662,6 +703,21 @@ def _repr_(self): else: return list.__repr__(self) + def _repr_pretty_(self, p, cycle): + """ + For pretty printing in the Sage command prompt. + + Since ``Sequence`` inherits from ``list``, we just use IPython's built-in + ``list`` pretty printer. + When :issue:`36801` is fixed, this function will be redundant. + + EXAMPLES:: + + sage: Sequence([1,2/3,-2/5]) # indirect doctest + [1, 2/3, -2/5] + """ + p.pretty(list(self)) + def _latex_(self): r""" TESTS:: @@ -863,26 +919,25 @@ def __getattr__(self, name): sage: hash(S) 34 """ - if name == "_Sequence_generic__cr" and hasattr(self,"_Sequence__cr"): + if name == "_Sequence_generic__cr" and hasattr(self, "_Sequence__cr"): self.__cr = self._Sequence__cr return self.__cr - elif name == "_Sequence_generic__cr_str" and hasattr(self,"_Sequence__cr_str"): + if name == "_Sequence_generic__cr_str" and hasattr(self, "_Sequence__cr_str"): self.__cr_str = self._Sequence__cr_str return self.__cr_str - elif name == "_Sequence_generic__immutable" and hasattr(self,"_Sequence__immutable"): + if name == "_Sequence_generic__immutable" and hasattr(self, "_Sequence__immutable"): self.__immutable = self._Sequence__immutable return self.__immutable - elif name == "_Sequence_generic__universe" and hasattr(self,"_Sequence__universe"): + if name == "_Sequence_generic__universe" and hasattr(self, "_Sequence__universe"): self.__universe = self._Sequence__universe return self.__universe - elif name == "_Sequence_generic__hash" and hasattr(self,"_Sequence__hash"): + if name == "_Sequence_generic__hash" and hasattr(self, "_Sequence__hash"): self.__hash = self._Sequence__hash return self.__hash - else: - raise AttributeError("'Sequence_generic' object has no attribute '%s'" % name) + + raise AttributeError("'Sequence_generic' object has no attribute '%s'" % name) seq = Sequence -from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.structure.sequence', 'Sequence', Sequence_generic) diff --git a/src/sage/structure/set_factories.py b/src/sage/structure/set_factories.py index c65a31089e8..ca46a413d7a 100644 --- a/src/sage/structure/set_factories.py +++ b/src/sage/structure/set_factories.py @@ -306,12 +306,12 @@ - Florent Hivert (2011-2012): initial revision """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.sage_object import SageObject @@ -846,7 +846,8 @@ def element_constructor_attributes(self, constraints): sage: pol.element_constructor_attributes(()) {'_element_constructor_': <... 'tuple'>, '_parent_for': None} """ - return {'_element_constructor_' : self._constructor, '_parent_for' : None} + return {'_element_constructor_': self._constructor, + '_parent_for': None} def _repr_(self): r""" @@ -1107,7 +1108,7 @@ def __contains__(self, x): False """ if (isinstance(x, self.element_class) and - x.parent() == self._parent_for): # TODO: is_parent_of ??? + x.parent() == self._parent_for): # TODO: is_parent_of ??? try: self.check_element(x, True) except ValueError: @@ -1140,7 +1141,7 @@ def __call__(self, *args, **keywords): # Ensure idempotence of element construction if (len(args) == 1 and isinstance(args[0], self.element_class) and - args[0].parent() == self._parent_for): + args[0].parent() == self._parent_for): check = keywords.get("check", True) if check: self.check_element(args[0], check) diff --git a/src/sage/structure/set_factories_example.py b/src/sage/structure/set_factories_example.py index df4db63ef89..ba7d0f782e4 100644 --- a/src/sage/structure/set_factories_example.py +++ b/src/sage/structure/set_factories_example.py @@ -25,12 +25,12 @@ S_a^b := \{(x,y) \in S \mid x = a, y = b\}. """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2012 Florent Hivert # # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# **************************************************************************** from sage.structure.unique_representation import UniqueRepresentation from sage.structure.element_wrapper import ElementWrapper @@ -99,8 +99,8 @@ def __call__(self, x=None, y=None, policy=None): if isinstance(y, (Integer, int)): return SingletonPair(x, y, policy) return PairsX_(x, policy) - elif isinstance(y, (Integer, int)): - return Pairs_Y(y, policy) + if isinstance(y, (Integer, int)): + return Pairs_Y(y, policy) return AllPairs(policy) def add_constraints(self, cons, args_opts): diff --git a/src/sage/structure/test_factory.py b/src/sage/structure/test_factory.py index 707feb0d409..216c0d6d3d9 100644 --- a/src/sage/structure/test_factory.py +++ b/src/sage/structure/test_factory.py @@ -3,7 +3,7 @@ Test of the :mod:`~sage.structure.factory` module """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Robert Bradshaw # # Distributed under the terms of the GNU General Public License (GPL) @@ -15,8 +15,8 @@ # # The full text of the GPL is available at: # -# http://www.gnu.org/licenses/ -#****************************************************************************** +# https://www.gnu.org/licenses/ +# ***************************************************************************** from sage.structure.factory import UniqueFactory diff --git a/src/sage/symbolic/expression.pyx b/src/sage/symbolic/expression.pyx index 52da8232dc6..da4d5db908f 100644 --- a/src/sage/symbolic/expression.pyx +++ b/src/sage/symbolic/expression.pyx @@ -372,6 +372,7 @@ More sanity tests:: # https://www.gnu.org/licenses/ # **************************************************************************** +cimport cython from cysignals.signals cimport sig_on, sig_off from sage.ext.cplusplus cimport ccrepr, ccreadstr @@ -13574,6 +13575,7 @@ def _eval_on_operands(f): Some documentation. """ @sage_wraps(f) + @cython.binding(True) def new_f(ex, *args, **kwds): new_args = list(ex._unpack_operands()) new_args.extend(args) diff --git a/src/sage/symbolic/expression_conversions.py b/src/sage/symbolic/expression_conversions.py index 2d59c66293c..0a2b25d4a8a 100644 --- a/src/sage/symbolic/expression_conversions.py +++ b/src/sage/symbolic/expression_conversions.py @@ -23,7 +23,7 @@ from sage.misc.lazy_import import lazy_import from sage.symbolic.ring import SR from sage.structure.element import Expression -from sage.functions.all import exp +from sage.functions.log import exp from sage.symbolic.operators import arithmetic_operators, relation_operators, FDerivativeOperator, add_vararg, mul_vararg from sage.rings.number_field.number_field_element_base import NumberFieldElement_base from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField @@ -1651,7 +1651,6 @@ class Exponentialize(ExpressionTreeWalker): # the same canned results dictionary at each call. from sage.calculus.var import function from sage.functions.hyperbolic import sinh, cosh, sech, csch, tanh, coth - from sage.functions.log import exp from sage.functions.trig import sin, cos, sec, csc, tan, cot from sage.rings.integer import Integer from sage.symbolic.constants import e, I @@ -1749,7 +1748,6 @@ def composition(self, ex, op): sage: s.composition(q, q.operator()) (cos(b) + I*sin(b))*e^a """ - from sage.functions.log import exp if op is not exp: # return super().composition(ex, op) return op(*[self(oper) for oper in ex.operands()]) diff --git a/src/sage/symbolic/ginac/numeric.cpp b/src/sage/symbolic/ginac/numeric.cpp index e973390ffa2..02b07296193 100644 --- a/src/sage/symbolic/ginac/numeric.cpp +++ b/src/sage/symbolic/ginac/numeric.cpp @@ -3665,7 +3665,7 @@ const numeric numeric::log(const numeric &b, PyObject* parent) const { } // General log -// Handle special cases here that return MPZ/MPQ +// Handle special cases here that return MPZ/MPQ (or an infinity) const numeric numeric::ratlog(const numeric &b, bool& israt) const { israt = true; if (b.is_one()) { @@ -3688,6 +3688,9 @@ const numeric numeric::ratlog(const numeric &b, bool& israt) const { israt = false; return *_num0_p; } + if (v._long == 0) { + return py_funcs.py_eval_neg_infinity(); + } int c = 0; std::ldiv_t ld; ld.quot = v._long; diff --git a/src/sage/symbolic/integration/external.py b/src/sage/symbolic/integration/external.py index 5f647228564..1390c524300 100644 --- a/src/sage/symbolic/integration/external.py +++ b/src/sage/symbolic/integration/external.py @@ -214,70 +214,31 @@ def fricas_integrator(expression, v, a=None, b=None, noPole=True): return result -def giac_integrator(expression, v, a=None, b=None): - r""" - Integration using Giac. - - EXAMPLES:: - - sage: from sage.symbolic.integration.external import giac_integrator - sage: giac_integrator(sin(x), x) - -cos(x) - sage: giac_integrator(1/(x^2+6), x, -oo, oo) - 1/6*sqrt(6)*pi - - TESTS:: - - sage: giac_integrator(e^(-x^2)*log(x), x) - integrate(e^(-x^2)*log(x), x) - - Check that :issue:`30133` is fixed:: - - sage: ee = SR.var('e') - sage: giac_integrator(ee^x, x) - e^x/log(e) - sage: y = SR.var('π') - sage: giac_integrator(cos(y), y) - sin(π) - - Check that :issue:`29966` is fixed:: - - sage: giac_integrator(sqrt(x + sqrt(x)), x) - 1/12*(2*sqrt(x)*(4*sqrt(x) + 1) - 3)*sqrt(x + sqrt(x))... - """ - ex = expression._giac_() - if a is None: - result = ex.integrate(v._giac_()) - else: - result = ex.integrate(v._giac_(), a._giac_(), b._giac_()) - if 'integrate' in format(result) or 'integration' in format(result): - return expression.integrate(v, a, b, hold=True) - return result._sage_() - - def libgiac_integrator(expression, v, a=None, b=None): r""" Integration using libgiac. EXAMPLES:: + sage: # needs sage.libs.giac sage: import sage.libs.giac ... sage: from sage.symbolic.integration.external import libgiac_integrator sage: libgiac_integrator(sin(x), x) -cos(x) sage: libgiac_integrator(1/(x^2+6), x, -oo, oo) - No checks were made for singular points of antiderivative... 1/6*sqrt(6)*pi TESTS:: + sage: # needs sage.libs.giac sage: libgiac_integrator(e^(-x^2)*log(x), x) integrate(e^(-x^2)*log(x), x) The following integral fails with the Giac Pexpect interface, but works with libgiac (:issue:`31873`):: + sage: # needs sage.libs.giac sage: a, x = var('a,x') sage: f = sec(2*a*x) sage: F = libgiac_integrator(f, x) @@ -295,10 +256,9 @@ def libgiac_integrator(expression, v, a=None, b=None): return expression.integrate(v, a, b, hold=True) from sage.libs.giac.giac import Pygen - # We call Pygen on first argument because otherwise some expressions - # involving derivatives result in doctest failures in interfaces/sympy.py - # -- related to the fixme note in sage.libs.giac.giac.GiacFunction.__call__ - # regarding conversion of lists. + # We call Pygen on first argument because otherwise some + # expressions involving derivatives result in doctest failures in + # sage/interfaces/sympy.py if a is None: result = libgiac.integrate(Pygen(expression), v) else: diff --git a/src/sage/symbolic/integration/integral.py b/src/sage/symbolic/integration/integral.py index 0877d132030..4a70d373516 100644 --- a/src/sage/symbolic/integration/integral.py +++ b/src/sage/symbolic/integration/integral.py @@ -28,7 +28,7 @@ available_integrators['sympy'] = external.sympy_integrator available_integrators['mathematica_free'] = external.mma_free_integrator available_integrators['fricas'] = external.fricas_integrator -available_integrators['giac'] = external.giac_integrator +available_integrators['giac'] = external.libgiac_integrator available_integrators['libgiac'] = external.libgiac_integrator ###################################################### @@ -59,9 +59,10 @@ def __init__(self): Check for :issue:`28913`:: + sage: # needs sage.libs.giac sage: Ex = (1-2*x^(1/3))^(3/4)/x sage: integrate(Ex, x, algorithm='giac') # long time - 4*(-2*x^(1/3) + 1)^(3/4) + 6*arctan((-2*x^(1/3) + 1)^(1/4)) - 3*log((-2*x^(1/3) + 1)^(1/4) + 1) + 3*log(abs((-2*x^(1/3) + 1)^(1/4) - 1)) + 4*(-2*x^(1/3) + 1)^(3/4) + 6*arctan((-2*x^(1/3) + 1)^(1/4)) - 3*log(abs((-2*x^(1/3) + 1)^(1/4) + 1)) + 3*log(abs((-2*x^(1/3) + 1)^(1/4) - 1)) Check for :issue:`29833`:: @@ -207,10 +208,13 @@ def __init__(self): Check for :issue:`32354`:: + sage: # needs sage.libs.giac 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') + sage: result = integral(1/max_symbolic(x, 1)**2, x, 0, oo, algorithm='giac') + ... + sage: result 2 """ # The automatic evaluation routine will try these integrators @@ -474,9 +478,9 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): - ``'fricas'`` -- use FriCAS (the optional fricas spkg has to be installed) - - ``'giac'`` -- use Giac + - ``'giac'`` -- use libgiac - - ``'libgiac'`` -- use libgiac + - ``'libgiac'`` -- use libgiac (alias for ``'giac'``) To prevent automatic evaluation, use the ``hold`` argument. @@ -695,9 +699,15 @@ def integrate(expression, v=None, a=None, b=None, algorithm=None, hold=False): sage: integrate(f(x), x, 1, 2, algorithm='sympy') # needs sympy -1/2*pi + arctan(8) + arctan(5) + arctan(2) + arctan(1/2) - Using Giac to integrate the absolute value of a trigonometric expression:: + Using Giac to integrate the absolute value of a trigonometric + expression. If Giac is installed, this will be attempted + automatically in the event that Maxima is unable to integrate the + expression:: - sage: integrate(abs(cos(x)), x, 0, 2*pi, algorithm='giac') + sage: # needs sage.libs.giac + sage: result = integrate(abs(cos(x)), x, 0, 2*pi, algorithm='giac') + ... + sage: result 4 sage: result = integrate(abs(cos(x)), x, 0, 2*pi) ... diff --git a/src/sage/symbolic/meson.build b/src/sage/symbolic/meson.build index 0ba39cb4d45..fc1f2a806e3 100644 --- a/src/sage/symbolic/meson.build +++ b/src/sage/symbolic/meson.build @@ -2,6 +2,7 @@ inc_ginac = include_directories('ginac') inc_pynac = include_directories('.') py.install_sources( + '__init__.py', 'all.py', 'assumptions.py', 'benchmark.py', diff --git a/src/sage/symbolic/pynac_impl.pxi b/src/sage/symbolic/pynac_impl.pxi index 967ff18d020..fcd084cea81 100644 --- a/src/sage/symbolic/pynac_impl.pxi +++ b/src/sage/symbolic/pynac_impl.pxi @@ -40,7 +40,6 @@ from sage.arith.functions import lcm from sage.cpython.string cimport str_to_bytes, char_to_str from sage.ext.stdsage cimport PY_NEW from sage.libs.gmp.all cimport * -from sage.libs.gsl.types cimport * from sage.libs.gsl.complex cimport * from sage.libs.gsl.gamma cimport gsl_sf_lngamma_complex_e from sage.libs.mpmath import utils as mpmath_utils diff --git a/src/sage/symbolic/ring.pyx b/src/sage/symbolic/ring.pyx index 65fccee5324..d5d435e6757 100644 --- a/src/sage/symbolic/ring.pyx +++ b/src/sage/symbolic/ring.pyx @@ -187,7 +187,7 @@ cdef class SymbolicRing(sage.rings.abc.SymbolicRing): True """ if isinstance(R, type): - if R in [int, float, long, complex, bool]: + if R in (int, float, complex, bool): return True if is_numpy_type(R): @@ -207,7 +207,7 @@ cdef class SymbolicRing(sage.rings.abc.SymbolicRing): return False else: from sage.rings.fraction_field import FractionField_generic - from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic from sage.rings.infinity import InfinityRing, UnsignedInfinityRing @@ -219,7 +219,8 @@ cdef class SymbolicRing(sage.rings.abc.SymbolicRing): if R._is_numerical(): # Almost anything with a coercion into any precision of CC return R not in (RLF, CLF) - elif isinstance(R, PolynomialRing_general) or isinstance(R, MPolynomialRing_base) or isinstance(R, FractionField_generic) or isinstance(R, LaurentPolynomialRing_generic): + elif isinstance(R, (PolynomialRing_generic, MPolynomialRing_base, + FractionField_generic, LaurentPolynomialRing_generic)): base = R.base_ring() return base is not self and self.has_coerce_map_from(base) elif (R is InfinityRing or R is UnsignedInfinityRing diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index 32ac954c7b4..83ffecab289 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -50,11 +50,7 @@ sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ,3) sage: basis = V.basis() ; basis - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: c = Components(QQ, basis, 2) ; c 2-indices components w.r.t. [ (1, 0, 0), @@ -290,11 +286,7 @@ class Components(SageObject): sage: from sage.tensor.modules.comp import Components sage: V = VectorSpace(QQ,3) sage: basis = V.basis() ; basis - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: c = Components(QQ, basis, 2) ; c 2-indices components w.r.t. [ (1, 0, 0), @@ -1688,7 +1680,7 @@ def __sub__(self, other): """ if isinstance(other, (int, Integer)) and other == 0: return +self - return self + (-other) #!# correct, deals properly with + return self + (-other) # ! # correct, deals properly with # symmetries, but is probably not optimal def __rsub__(self, other): diff --git a/src/sage/tensor/modules/finite_rank_free_module.py b/src/sage/tensor/modules/finite_rank_free_module.py index 9a4e44f0f12..9da32715e9e 100644 --- a/src/sage/tensor/modules/finite_rank_free_module.py +++ b/src/sage/tensor/modules/finite_rank_free_module.py @@ -232,11 +232,7 @@ class :class:`~sage.modules.free_module.FreeModule_generic` distinguished basis, while ``FiniteRankFreeModule`` does not:: sage: N.basis() - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] sage: M.bases() [] sage: M.print_bases() @@ -378,11 +374,7 @@ class :class:`~sage.modules.free_module.FreeModule_generic` sage: V is QQ^3 True sage: V.basis() - [ - (1, 0, 0), - (0, 1, 0), - (0, 0, 1) - ] + [(1, 0, 0), (0, 1, 0), (0, 0, 1)] To create a vector space without any distinguished basis, one has to use ``FiniteRankFreeModule``:: @@ -1302,7 +1294,7 @@ def __init__( self._dual_exterior_powers = {} # Set of all modules (tensor powers, exterior powers) # that depend on self's bases: - self._all_modules = set([self]) + self._all_modules = {self} # List of known bases on the free module: self._known_bases = [] self._def_basis = None # default basis diff --git a/src/sage/tensor/modules/free_module_basis.py b/src/sage/tensor/modules/free_module_basis.py index f882b88e300..ca3116f2648 100644 --- a/src/sage/tensor/modules/free_module_basis.py +++ b/src/sage/tensor/modules/free_module_basis.py @@ -500,7 +500,7 @@ def __init__(self, basis, symbol, latex_symbol=None, indices=None, Basis_abstract.__init__(self, basis._fmodule, symbol, latex_symbol, indices, latex_indices) # The individual linear forms: - vl = list() + vl = [] fmodule = self._fmodule ring_one = fmodule._ring.one() for i in fmodule.irange(): @@ -719,7 +719,7 @@ def __init__(self, fmodule, symbol, latex_symbol=None, indices=None, # The basis is added to the module list of bases fmodule._known_bases.append(self) # The individual vectors: - vl = list() + vl = [] ring_one = fmodule._ring.one() for i in fmodule.irange(): v = fmodule.element_class(fmodule) diff --git a/src/sage/tensor/modules/free_module_tensor.py b/src/sage/tensor/modules/free_module_tensor.py index 94974e6059b..19c42c53081 100644 --- a/src/sage/tensor/modules/free_module_tensor.py +++ b/src/sage/tensor/modules/free_module_tensor.py @@ -2801,12 +2801,12 @@ def contract(self, *args): # nb_cov_s = 0 # Number of covariant indices of self not involved in the # contraction - for pos in range(k1,k1+l1): + for pos in range(k1, k1 + l1): if pos not in pos1: nb_cov_s += 1 nb_con_o = 0 # Number of contravariant indices of other not involved # in the contraction - for pos in range(0,k2): + for pos in range(k2): if pos not in pos2: nb_con_o += 1 if nb_cov_s != 0 and nb_con_o != 0: diff --git a/src/sage/tests/arxiv_0812_2725.py b/src/sage/tests/arxiv_0812_2725.py index 9bacb5c18aa..25e24ca3735 100644 --- a/src/sage/tests/arxiv_0812_2725.py +++ b/src/sage/tests/arxiv_0812_2725.py @@ -25,7 +25,7 @@ sage: dcrossing([(1,5), (2,4), (4,9), (6,12), (7,10), (10,11)]) 3 """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2008 Dan Drake # # This program is free software: you can redistribute it and/or modify @@ -34,8 +34,8 @@ # your option) any later version. # # See https://www.gnu.org/licenses/. -#***************************************************************************** -from sage.combinat.set_partition import SetPartitions as SetPartitions +# **************************************************************************** +from sage.combinat.set_partition import SetPartitions def CompleteMatchings(n): diff --git a/src/sage/tests/book_stein_modform.py b/src/sage/tests/book_stein_modform.py index 667bb057c70..4b7e07a89d7 100644 --- a/src/sage/tests/book_stein_modform.py +++ b/src/sage/tests/book_stein_modform.py @@ -34,11 +34,9 @@ sage: E6^4 1/64524128256 - 1/32006016*q + 241/10668672*q^2 + O(q^3) sage: victor_miller_basis(28,5) - [ - 1 + 15590400*q^3 + 36957286800*q^4 + O(q^5), - q + 151740*q^3 + 61032448*q^4 + O(q^5), - q^2 + 192*q^3 - 8280*q^4 + O(q^5) - ] + [1 + 15590400*q^3 + 36957286800*q^4 + O(q^5), + q + 151740*q^3 + 61032448*q^4 + O(q^5), + q^2 + 192*q^3 - 8280*q^4 + O(q^5)] sage: R. = QQ[['q']] sage: F4 = 240 * eisenstein_series_qexp(4,3) sage: F6 = -504 * eisenstein_series_qexp(6,3) @@ -50,12 +48,10 @@ 1 + 196560*q^2 + O(q^3) sage: M = ModularForms(1,36, prec=6).echelon_form() sage: M.basis() - [ - 1 + 6218175600*q^4 + 15281788354560*q^5 + O(q^6), - q + 57093088*q^4 + 37927345230*q^5 + O(q^6), - q^2 + 194184*q^4 + 7442432*q^5 + O(q^6), - q^3 - 72*q^4 + 2484*q^5 + O(q^6) - ] + [1 + 6218175600*q^4 + 15281788354560*q^5 + O(q^6), + q + 57093088*q^4 + 37927345230*q^5 + O(q^6), + q^2 + 194184*q^4 + 7442432*q^5 + O(q^6), + q^3 - 72*q^4 + 2484*q^5 + O(q^6)] sage: T2 = M.hecke_matrix(2); T2 [ 34359738369 0 6218175600 9026867482214400] [ 0 0 34416831456 5681332472832] @@ -196,11 +192,9 @@ (x - 2)^2 * (x - 6)^3 * (x^2 - 8)^2 sage: M = ModularSymbols(39, 2) sage: M.T(2).decomposition() - [ - Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(39) of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 9 for Gamma_0(39) of weight 2 with sign 0 over Rational Field, - Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 9 for Gamma_0(39) of weight 2 with sign 0 over Rational Field - ] + [Modular Symbols subspace of dimension 2 of Modular Symbols space of dimension 9 for Gamma_0(39) of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 3 of Modular Symbols space of dimension 9 for Gamma_0(39) of weight 2 with sign 0 over Rational Field, + Modular Symbols subspace of dimension 4 of Modular Symbols space of dimension 9 for Gamma_0(39) of weight 2 with sign 0 over Rational Field] sage: M = ModularSymbols(2, 2) sage: M.boundary_map() Hecke module morphism boundary map defined by the matrix @@ -290,10 +284,7 @@ sage: f(1,0) -1/3*q^2 + 2/3*q^3 + 1/3*q^4 - 2/3*q^5 + O(q^6) sage: S.q_expansion_basis(6) - [ - q - q^3 - q^4 + O(q^6), - q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6) - ] + [q - q^3 - q^4 + O(q^6), q^2 - 2*q^3 - q^4 + 2*q^5 + O(q^6)] sage: R = Integers(49) sage: R Ring of integers modulo 49 @@ -342,16 +333,14 @@ 1 sage: G = DirichletGroup(20) sage: G.galois_orbits() - [ - [Dirichlet character modulo 20 of conductor 20 mapping 11 |--> -1, 17 |--> -1], - [Dirichlet character modulo 20 of conductor 20 mapping 11 |--> -1, 17 |--> -zeta4, - Dirichlet character modulo 20 of conductor 20 mapping 11 |--> -1, 17 |--> zeta4], - [Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1], - [Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -1], - [Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -zeta4, - Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4], - [Dirichlet character modulo 20 of conductor 1 mapping 11 |--> 1, 17 |--> 1] - ] + [[Dirichlet character modulo 20 of conductor 20 mapping 11 |--> -1, 17 |--> -1], + [Dirichlet character modulo 20 of conductor 20 mapping 11 |--> -1, 17 |--> -zeta4, + Dirichlet character modulo 20 of conductor 20 mapping 11 |--> -1, 17 |--> zeta4], + [Dirichlet character modulo 20 of conductor 4 mapping 11 |--> -1, 17 |--> 1], + [Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -1], + [Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> -zeta4, + Dirichlet character modulo 20 of conductor 5 mapping 11 |--> 1, 17 |--> zeta4], + [Dirichlet character modulo 20 of conductor 1 mapping 11 |--> 1, 17 |--> 1]] sage: G = DirichletGroup(11, QQ); G Group of Dirichlet characters modulo 11 with values in Rational Field sage: list(G) @@ -423,19 +412,17 @@ -108846/5*zeta4 - 176868/5 sage: E = EisensteinForms(Gamma1(13),2) sage: E.eisenstein_series() - [ - 1/2 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6), - -7/13*zeta6 - 11/13 + q + (2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + (6*zeta6 - 3)*q^4 - 4*q^5 + O(q^6), - q + (zeta6 + 2)*q^2 + (-zeta6 + 3)*q^3 + (3*zeta6 + 3)*q^4 + 4*q^5 + O(q^6), - -zeta6 + q + (2*zeta6 - 1)*q^2 + (3*zeta6 - 2)*q^3 + (-2*zeta6 - 1)*q^4 + 6*q^5 + O(q^6), - q + (zeta6 + 1)*q^2 + (zeta6 + 2)*q^3 + (zeta6 + 2)*q^4 + 6*q^5 + O(q^6), - -1 + q - q^2 + 4*q^3 + 3*q^4 - 4*q^5 + O(q^6), - q + q^2 + 4*q^3 + 3*q^4 + 4*q^5 + O(q^6), - zeta6 - 1 + q + (-2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + (2*zeta6 - 3)*q^4 + 6*q^5 + O(q^6), - q + (-zeta6 + 2)*q^2 + (-zeta6 + 3)*q^3 + (-zeta6 + 3)*q^4 + 6*q^5 + O(q^6), - 7/13*zeta6 - 18/13 + q + (-2*zeta6 + 3)*q^2 + (3*zeta6 - 2)*q^3 + (-6*zeta6 + 3)*q^4 - 4*q^5 + O(q^6), - q + (-zeta6 + 3)*q^2 + (zeta6 + 2)*q^3 + (-3*zeta6 + 6)*q^4 + 4*q^5 + O(q^6) - ] + [1/2 + q + 3*q^2 + 4*q^3 + 7*q^4 + 6*q^5 + O(q^6), + -7/13*zeta6 - 11/13 + q + (2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + (6*zeta6 - 3)*q^4 - 4*q^5 + O(q^6), + q + (zeta6 + 2)*q^2 + (-zeta6 + 3)*q^3 + (3*zeta6 + 3)*q^4 + 4*q^5 + O(q^6), + -zeta6 + q + (2*zeta6 - 1)*q^2 + (3*zeta6 - 2)*q^3 + (-2*zeta6 - 1)*q^4 + 6*q^5 + O(q^6), + q + (zeta6 + 1)*q^2 + (zeta6 + 2)*q^3 + (zeta6 + 2)*q^4 + 6*q^5 + O(q^6), + -1 + q - q^2 + 4*q^3 + 3*q^4 - 4*q^5 + O(q^6), + q + q^2 + 4*q^3 + 3*q^4 + 4*q^5 + O(q^6), + zeta6 - 1 + q + (-2*zeta6 + 1)*q^2 + (-3*zeta6 + 1)*q^3 + (2*zeta6 - 3)*q^4 + 6*q^5 + O(q^6), + q + (-zeta6 + 2)*q^2 + (-zeta6 + 3)*q^3 + (-zeta6 + 3)*q^4 + 6*q^5 + O(q^6), + 7/13*zeta6 - 18/13 + q + (-2*zeta6 + 3)*q^2 + (3*zeta6 - 2)*q^3 + (-6*zeta6 + 3)*q^4 - 4*q^5 + O(q^6), + q + (-zeta6 + 3)*q^2 + (zeta6 + 2)*q^3 + (-3*zeta6 + 6)*q^4 + 4*q^5 + O(q^6)] sage: e = E.eisenstein_series() sage: for e in E.eisenstein_series(): ....: print(e.parameters()) @@ -538,21 +525,15 @@ of dimension 10 for Congruence Subgroup Gamma0(45) of weight 2 over Rational Field sage: S.basis() - [ - q - q^4 - q^10 - 2*q^13 + O(q^14), - q^2 - q^5 - 3*q^8 + 4*q^11 + O(q^14), - q^3 - q^6 - q^9 - q^12 + O(q^14) - ] + [q - q^4 - q^10 - 2*q^13 + O(q^14), + q^2 - q^5 - 3*q^8 + 4*q^11 + O(q^14), + q^3 - q^6 - q^9 - q^12 + O(q^14)] sage: S.new_subspace().basis() - [ - q + q^2 - q^4 - q^5 - 3*q^8 - q^10 + 4*q^11 - 2*q^13 + O(q^14) - ] + [q + q^2 - q^4 - q^5 - 3*q^8 - q^10 + 4*q^11 - 2*q^13 + O(q^14)] sage: CuspForms(Gamma0(9),2) Cuspidal subspace of dimension 0 of Modular Forms space of dimension 3 for Congruence Subgroup Gamma0(9) of weight 2 over Rational Field sage: CuspForms(Gamma0(15),2, prec=10).basis() - [ - q - q^2 - q^3 - q^4 + q^5 + q^6 + 3*q^8 + q^9 + O(q^10) - ] + [q - q^2 - q^3 - q^4 + q^5 + q^6 + 3*q^8 + q^9 + O(q^10)] """ 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 90db67c02e1..b5531b112b4 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 @@ -494,11 +494,7 @@ Sage example in ./calculus.tex, line 2487:: sage: A.eigenvectors_right() - [(1, [ - (1, -1, 1) - ], 1), (-2, [ - (1, -1, 0) - ], 2)] + [(1, [(1, -1, 1)], 1), (-2, [(1, -1, 0)], 2)] Sage example in ./calculus.tex, line 2499:: 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 e904843bfdd..9a52f0f97ed 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 @@ -406,30 +406,23 @@ sage: A.eigenvalues() [4, 1, 2, 2] sage: A.eigenvectors_right() - [(4, [ - (1, 5, 5, 1) - ], 1), (1, [ - (0, 1, 1, 4) - ], 1), (2, [ - (1, 3, 0, 1), - (0, 0, 1, 1) - ], 2)] + [(4, [(1, 5, 5, 1)], 1), + (1, [(0, 1, 1, 4)], 1), + (2, [(1, 3, 0, 1), (0, 0, 1, 1)], 2)] sage: A.eigenspaces_right() - [ - (4, Vector space of degree 4 and dimension 1 over Finite Field - of size 7 - User basis matrix: - [1 5 5 1]), - (1, Vector space of degree 4 and dimension 1 over Finite Field - of size 7 - User basis matrix: - [0 1 1 4]), - (2, Vector space of degree 4 and dimension 2 over Finite Field - of size 7 - User basis matrix: - [1 3 0 1] - [0 0 1 1]) - ] + [(4, + Vector space of degree 4 and dimension 1 over Finite Field of size 7 + User basis matrix: + [1 5 5 1]), + (1, + Vector space of degree 4 and dimension 1 over Finite Field of size 7 + User basis matrix: + [0 1 1 4]), + (2, + Vector space of degree 4 and dimension 2 over Finite Field of size 7 + User basis matrix: + [1 3 0 1] + [0 0 1 1])] Sage example in ./linalg.tex, line 2770:: diff --git a/src/sage/tests/books/judson-abstract-algebra/galois-sage.py b/src/sage/tests/books/judson-abstract-algebra/galois-sage.py index 9af165c8904..af1f6fa8e6f 100644 --- a/src/sage/tests/books/judson-abstract-algebra/galois-sage.py +++ b/src/sage/tests/books/judson-abstract-algebra/galois-sage.py @@ -152,16 +152,14 @@ ~~~~~~~~~~~~~~~~~~~~~~ :: sage: Sequence([[fromL(tau(r)) for r in roots] for tau in G], cr=True) - [ - [b, a, -a, -b], - [-b, -a, a, b], - [a, -b, b, -a], - [b, -a, a, -b], - [-a, -b, b, a], - [a, b, -b, -a], - [-b, a, -a, b], - [-a, b, -b, a] - ] + [[b, a, -a, -b], + [-b, -a, a, b], + [a, -b, b, -a], + [b, -a, a, -b], + [-a, -b, b, a], + [a, b, -b, -a], + [-b, a, -a, b], + [-a, b, -b, a]] ~~~~~~~~~~~~~~~~~~~~~~ :: @@ -382,71 +380,69 @@ ~~~~~~~~~~~~~~~~~~~~~~ :: sage: L.subfields() - [ - (Number Field in c0 with defining polynomial x, - Ring morphism: - From: Number Field in c0 with defining polynomial x - To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - Defn: 0 |--> 0, - None), - (Number Field in c1 with defining polynomial x^2 + 112*x + 40000, - Ring morphism: - From: Number Field in c1 with defining polynomial x^2 + 112*x + 40000 - To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - Defn: c1 |--> 4*c^4, - None), - (Number Field in c2 with defining polynomial x^2 + 512, - Ring morphism: - From: Number Field in c2 with defining polynomial x^2 + 512 - To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - Defn: c2 |--> 1/25*c^6 + 78/25*c^2, - None), - (Number Field in c3 with defining polynomial x^2 - 288, - Ring morphism: - From: Number Field in c3 with defining polynomial x^2 - 288 - To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - Defn: c3 |--> -1/25*c^6 + 22/25*c^2, - None), - (Number Field in c4 with defining polynomial x^4 + 112*x^2 + 40000, - Ring morphism: - From: Number Field in c4 with defining polynomial x^4 + 112*x^2 + 40000 - To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - Defn: c4 |--> 2*c^2, - None), - (Number Field in c5 with defining polynomial x^4 + 8, - Ring morphism: - From: Number Field in c5 with defining polynomial x^4 + 8 - To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - Defn: c5 |--> -1/80*c^5 + 1/40*c, + [(Number Field in c0 with defining polynomial x, + Ring morphism: + From: Number Field in c0 with defining polynomial x + To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + Defn: 0 |--> 0, None), - (Number Field in c6 with defining polynomial x^4 + 648, - Ring morphism: - From: Number Field in c6 with defining polynomial x^4 + 648 - To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - Defn: c6 |--> 1/80*c^5 + 79/40*c, - None), - (Number Field in c7 with defining polynomial x^4 - 512, - Ring morphism: - From: Number Field in c7 with defining polynomial x^4 - 512 - To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - Defn: c7 |--> -1/60*c^5 + 41/30*c, - None), - (Number Field in c8 with defining polynomial x^4 - 32, - Ring morphism: - From: Number Field in c8 with defining polynomial x^4 - 32 - To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - Defn: c8 |--> 1/60*c^5 + 19/30*c, - None), - (Number Field in c9 with defining polynomial x^8 + 28*x^4 + 2500, - Ring morphism: - From: Number Field in c9 with defining polynomial x^8 + 28*x^4 + 2500 - To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - Defn: c9 |--> c, - Ring morphism: - From: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 - To: Number Field in c9 with defining polynomial x^8 + 28*x^4 + 2500 - Defn: c |--> c9) - ] + (Number Field in c1 with defining polynomial x^2 + 112*x + 40000, + Ring morphism: + From: Number Field in c1 with defining polynomial x^2 + 112*x + 40000 + To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + Defn: c1 |--> 4*c^4, + None), + (Number Field in c2 with defining polynomial x^2 + 512, + Ring morphism: + From: Number Field in c2 with defining polynomial x^2 + 512 + To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + Defn: c2 |--> 1/25*c^6 + 78/25*c^2, + None), + (Number Field in c3 with defining polynomial x^2 - 288, + Ring morphism: + From: Number Field in c3 with defining polynomial x^2 - 288 + To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + Defn: c3 |--> -1/25*c^6 + 22/25*c^2, + None), + (Number Field in c4 with defining polynomial x^4 + 112*x^2 + 40000, + Ring morphism: + From: Number Field in c4 with defining polynomial x^4 + 112*x^2 + 40000 + To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + Defn: c4 |--> 2*c^2, + None), + (Number Field in c5 with defining polynomial x^4 + 8, + Ring morphism: + From: Number Field in c5 with defining polynomial x^4 + 8 + To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + Defn: c5 |--> -1/80*c^5 + 1/40*c, + None), + (Number Field in c6 with defining polynomial x^4 + 648, + Ring morphism: + From: Number Field in c6 with defining polynomial x^4 + 648 + To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + Defn: c6 |--> 1/80*c^5 + 79/40*c, + None), + (Number Field in c7 with defining polynomial x^4 - 512, + Ring morphism: + From: Number Field in c7 with defining polynomial x^4 - 512 + To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + Defn: c7 |--> -1/60*c^5 + 41/30*c, + None), + (Number Field in c8 with defining polynomial x^4 - 32, + Ring morphism: + From: Number Field in c8 with defining polynomial x^4 - 32 + To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + Defn: c8 |--> 1/60*c^5 + 19/30*c, + None), + (Number Field in c9 with defining polynomial x^8 + 28*x^4 + 2500, + Ring morphism: + From: Number Field in c9 with defining polynomial x^8 + 28*x^4 + 2500 + To: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + Defn: c9 |--> c, + Ring morphism: + From: Number Field in c with defining polynomial x^8 + 28*x^4 + 2500 + To: Number Field in c9 with defining polynomial x^8 + 28*x^4 + 2500 + Defn: c |--> c9)] ~~~~~~~~~~~~~~~~~~~~~~ :: diff --git a/src/sage/tests/books/judson-abstract-algebra/vect-sage.py b/src/sage/tests/books/judson-abstract-algebra/vect-sage.py index 23f624da585..083f35e9972 100644 --- a/src/sage/tests/books/judson-abstract-algebra/vect-sage.py +++ b/src/sage/tests/books/judson-abstract-algebra/vect-sage.py @@ -108,10 +108,7 @@ ~~~~~~~~~~~~~~~~~~~~~~ :: sage: S.basis() - [ - (1, 0, 2/3), - (0, 1, -7/3) - ] + [(1, 0, 2/3), (0, 1, -7/3)] ~~~~~~~~~~~~~~~~~~~~~~ :: diff --git a/src/sage/topology/cell_complex.py b/src/sage/topology/cell_complex.py index 7b64a3d36dd..e2276fb8839 100644 --- a/src/sage/topology/cell_complex.py +++ b/src/sage/topology/cell_complex.py @@ -544,7 +544,7 @@ def homology(self, dim=None, base_ring=ZZ, subcomplex=None, [0,0] x [0,1] x [0,1] - [0,1] x [0,0] x [0,1] + [0,1] x [0,1] x [0,0] - [0,1] x [0,1] x [1,1] + [0,1] x [1,1] x [0,1] - [1,1] x [0,1] x [0,1])] - Similarly for simpicial sets:: + Similarly for simplicial sets:: sage: S = simplicial_sets.Sphere(2) sage: S.homology(generators=True) # needs sage.modules diff --git a/src/sage/topology/delta_complex.py b/src/sage/topology/delta_complex.py index b9ce4d5fb62..338a6008931 100644 --- a/src/sage/topology/delta_complex.py +++ b/src/sage/topology/delta_complex.py @@ -304,7 +304,7 @@ def store_bdry(simplex, faces): # else a dictionary indexed by simplices dimension = max([f.dimension() for f in data]) old_data_by_dim = {} - for dim in range(0, dimension+1): + for dim in range(dimension + 1): old_data_by_dim[dim] = [] new_data[dim] = [] for x in data: @@ -466,7 +466,7 @@ def subcomplex(self, data): new_dict[d+1].append(tuple([translate[n] for n in f])) new_dict[d].append(cells[d][x]) cells_to_add.update(cells[d][x]) - new_cells = [new_dict[n] for n in range(0, max_dim+1)] + new_cells = [new_dict[n] for n in range(max_dim + 1)] sub = DeltaComplex(new_cells) sub._is_subcomplex_of = {self: new_data} return sub @@ -564,7 +564,7 @@ def cells(self, subcomplex=None): raise ValueError("this is not a subcomplex of self") else: subcomplex_cells = subcomplex._is_subcomplex_of[self] - for d in range(0, max(subcomplex_cells.keys())+1): + for d in range(max(subcomplex_cells.keys()) + 1): L = list(cells[d]) for c in subcomplex_cells[d]: L[c] = None @@ -1303,7 +1303,7 @@ def elementary_subdivision(self, idx=-1): # added_cells: dict indexed by (n-1)-cells, with value the # corresponding new n-cell. added_cells = {(): len(cells_dict[0])-1} - for n in range(0, dim): + for n in range(dim): new_cells = {} # for each n-cell in the standard simplex, add an # (n+1)-cell to the subdivided complex. diff --git a/src/sage/topology/simplicial_complex.py b/src/sage/topology/simplicial_complex.py index 54166cf4f1f..ac0af5dcd7b 100644 --- a/src/sage/topology/simplicial_complex.py +++ b/src/sage/topology/simplicial_complex.py @@ -1477,7 +1477,7 @@ def h_vector(self): d = self.dimension() f = self.f_vector() # indexed starting at 0, since it's a Python list h = [] - for j in range(0, d + 2): + for j in range(d + 2): s = 0 for i in range(-1, j): s += (-1)**(j-i-1) * binomial(d-i, j-i-1) * f[i+1] diff --git a/src/sage/topology/simplicial_set.py b/src/sage/topology/simplicial_set.py index 974feac8510..7387dde2f94 100644 --- a/src/sage/topology/simplicial_set.py +++ b/src/sage/topology/simplicial_set.py @@ -455,7 +455,7 @@ def __eq__(self, other): def __ne__(self, other): """ - This returns the negation of `__eq__`. + This returns the negation of ``__eq__``. EXAMPLES:: diff --git a/src/sage/topology/simplicial_set_examples.py b/src/sage/topology/simplicial_set_examples.py index 367a00413b7..5f0a4f2d228 100644 --- a/src/sage/topology/simplicial_set_examples.py +++ b/src/sage/topology/simplicial_set_examples.py @@ -123,7 +123,7 @@ def __eq__(self, other) -> bool: def __ne__(self, other) -> bool: """ - Return the negation of `__eq__`. + Return the negation of ``__eq__``. EXAMPLES:: diff --git a/src/sage/typeset/character_art.py b/src/sage/typeset/character_art.py index bc64866ed01..950bb2ea392 100644 --- a/src/sage/typeset/character_art.py +++ b/src/sage/typeset/character_art.py @@ -685,8 +685,8 @@ def __add__(self, Nelt): if self._baseline is not None and Nelt._baseline is not None: # left treatement - for line in self._matrix: - new_matrix.append(line + " " * (self._l - len(line))) + new_matrix.extend(line + " " * (self._l - len(line)) + for line in self._matrix) if new_h > self._h: # | new_h > self._h @@ -695,8 +695,9 @@ def __add__(self, Nelt): # | } :: Nelt._baseline - self._baseline # | } if new_baseline > self._baseline: - for k in range(new_baseline - self._baseline): - new_matrix.append(" " * self._l) + l_space = " " * self._l + new_matrix.extend(l_space + for k in range(new_baseline - self._baseline)) # | } new_h > self._h # | } new_h - new_baseline > self._h - self._baseline # ||<-- baseline number of white lines at the top @@ -722,8 +723,8 @@ def __add__(self, Nelt): for j in range(Nelt._h): new_matrix[i + j] += Nelt._matrix[j] else: - for line in self._matrix: - new_matrix.append(line + " " * (self._l - len(line))) + new_matrix.extend(line + " " * (self._l - len(line)) + for line in self._matrix) for i, line_i in enumerate(Nelt._matrix): if i == len(new_matrix): new_matrix.append(" " * self._l + line_i) diff --git a/src/sage/version.py b/src/sage/version.py index 8e15dcf37c7..16c67de2983 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 = '10.5.rc2' -date = '2024-11-30' -banner = 'SageMath version 10.5.rc2, Release Date: 2024-11-30' +version = '10.6.beta4' +date = '2025-01-18' +banner = 'SageMath version 10.6.beta4, Release Date: 2025-01-18' diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index d90c2eb2dd1..dab2531bac3 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -647,6 +647,11 @@ def linkcode_resolve(domain, info): \makeatother """ +# Enable "hard wrapping" long code lines (only applies if breaking +# long codelines at spaces or other suitable places failed, typically +# this is for long decimal expansions or possibly long string identifiers) +latex_elements['sphinxsetup'] = "verbatimforcewraps=true" + # Documents to append as an appendix to all manuals. # latex_appendices = [] @@ -670,6 +675,7 @@ def linkcode_resolve(domain, info): # used when building html version pngmath_latex_preamble += macro + '\n' + # ------------------------------------------ # add custom context variables for templates # ------------------------------------------ @@ -712,10 +718,12 @@ def add_page_context(app, pagename, templatename, context, doctree): dangling_debug = False + def debug_inf(app, message): if dangling_debug: app.info(message) + def call_intersphinx(app, env, node, contnode): r""" Call intersphinx and make links between Sage manuals relative. @@ -749,6 +757,7 @@ def call_intersphinx(app, env, node, contnode): debug_inf(app, "---- Intersphinx: %s not Found" % node['reftarget']) return res + def find_sage_dangling_links(app, env, node, contnode): r""" Try to find dangling link in local module imports or all.py. @@ -859,6 +868,7 @@ def find_sage_dangling_links(app, env, node, contnode): '__builtin__', ] + def check_nested_class_picklability(app, what, name, obj, skip, options): """ Print a warning if pickling is broken for nested classes. @@ -879,6 +889,7 @@ def check_nested_class_picklability(app, what, name, obj, skip, options): 'sage.misc.nested_class.NestedClassMetaclass.' % ( v.__module__ + '.' + name + '.' + nm)) + def skip_member(app, what, name, obj, skip, options): """ To suppress Sphinx warnings / errors, we diff --git a/src/sage_docbuild/ext/sage_autodoc.py b/src/sage_docbuild/ext/sage_autodoc.py index 6f048222437..94e7d076fa9 100644 --- a/src/sage_docbuild/ext/sage_autodoc.py +++ b/src/sage_docbuild/ext/sage_autodoc.py @@ -81,8 +81,12 @@ is_function_or_cython_function) _getdoc = getdoc + + def getdoc(obj, *args, **kwargs): return sage_getdoc_original(obj) + + # ------------------------------------------------------------------ if TYPE_CHECKING: @@ -1616,7 +1620,7 @@ def can_document_member( try: result_bool = isinstance(member, type) or ( isattr and isinstance(member, NewType | TypeVar)) - except: + except Exception: result_bool = isinstance(member, type) or ( isattr and (inspect.isNewType(member) or isinstance(member, TypeVar))) return result_bool @@ -1695,7 +1699,7 @@ def import_object(self, raiseerror: bool = False) -> bool: # support both sphinx 8 and py3.9/older sphinx try: test_bool = isinstance(self.object, NewType | TypeVar) - except: + except Exception: test_bool = inspect.isNewType(self.object) or isinstance(self.object, TypeVar) if test_bool: modname = getattr(self.object, '__module__', self.modname) @@ -1709,7 +1713,7 @@ def _get_signature(self) -> tuple[Any | None, str | None, Signature | None]: # support both sphinx 8 and py3.9/older sphinx try: test_bool = isinstance(self.object, NewType | TypeVar) - except: + except Exception: test_bool = inspect.isNewType(self.object) or isinstance(self.object, TypeVar) if test_bool: # Suppress signature @@ -1899,7 +1903,7 @@ def add_directive_header(self, sig: str) -> None: # support both sphinx 8 and py3.9/older sphinx try: test_bool = isinstance(self.object, NewType | TypeVar) - except: + except Exception: test_bool = inspect.isNewType(self.object) or isinstance(self.object, TypeVar) if test_bool: return @@ -1911,7 +1915,7 @@ def add_directive_header(self, sig: str) -> None: # support both sphinx 8 and py3.9/older sphinx try: newtype_test = isinstance(self.object, NewType) - except: + except Exception: newtype_test = inspect.isNewType(self.object) if (not self.doc_as_attr and not newtype_test and canonical_fullname and self.fullname != canonical_fullname): @@ -2053,7 +2057,7 @@ def add_content(self, more_content: StringList | None) -> None: # support both sphinx 8 and py3.9/older sphinx try: newtype_test = isinstance(self.object, NewType) - except: + except Exception: newtype_test = inspect.isNewType(self.object) if newtype_test: if self.config.autodoc_typehints_format == "short": diff --git a/src/sage_setup/autogen/flint/templates/flint_wrap.h.template b/src/sage_setup/autogen/flint/templates/flint_wrap.h.template index 97323ede6ce..ec58aa2f602 100644 --- a/src/sage_setup/autogen/flint/templates/flint_wrap.h.template +++ b/src/sage_setup/autogen/flint/templates/flint_wrap.h.template @@ -26,6 +26,10 @@ #pragma push_macro("ulong") #undef ulong +/* Reserved in C99, needed for FLINT without https://github.com/flintlib/flint/pull/2027 */ +#pragma push_macro("I") +#define I Iv + #include /* If flint was already previously included via another header (e.g. @@ -43,6 +47,7 @@ #undef mp_bitcnt_t #pragma pop_macro("ulong") +#pragma pop_macro("I") /* CPU_SIZE_1 and SIZE_RED_FAILURE_THRESH are defined as macros in flint/fmpz_lll.h * and as variables in fplll/defs.h, which breaks build if linbox is compiled with fplll */ diff --git a/src/sage_setup/autogen/interpreters/internal/instructions.py b/src/sage_setup/autogen/interpreters/internal/instructions.py index aad7583196d..475c312b274 100644 --- a/src/sage_setup/autogen/interpreters/internal/instructions.py +++ b/src/sage_setup/autogen/interpreters/internal/instructions.py @@ -385,6 +385,7 @@ def instr_funcall_1arg_mpfr(name, io, op): """ return InstrSpec(name, io, code='%s(o0, i0, MPFR_RNDN);' % op) + def instr_funcall_2args_mpc(name, io, op): r""" A helper function for creating MPC instructions with two inputs @@ -400,6 +401,7 @@ def instr_funcall_2args_mpc(name, io, op): """ return InstrSpec(name, io, code='%s(o0, i0, i1, MPC_RNDNN);' % op) + def instr_funcall_1arg_mpc(name, io, op): r""" A helper function for creating MPC instructions with one input diff --git a/src/sage_setup/autogen/interpreters/internal/memory.py b/src/sage_setup/autogen/interpreters/internal/memory.py index 801596e98c8..54710efd6a3 100644 --- a/src/sage_setup/autogen/interpreters/internal/memory.py +++ b/src/sage_setup/autogen/interpreters/internal/memory.py @@ -36,7 +36,7 @@ def string_of_addr(a): """ if isinstance(a, int): return str(a) - assert(isinstance(a, MemoryChunk)) + assert isinstance(a, MemoryChunk) return '*%s++' % a.name diff --git a/src/sage_setup/autogen/interpreters/internal/specs/cc.py b/src/sage_setup/autogen/interpreters/internal/specs/cc.py index cc42a6defab..569ebc633c9 100644 --- a/src/sage_setup/autogen/interpreters/internal/specs/cc.py +++ b/src/sage_setup/autogen/interpreters/internal/specs/cc.py @@ -101,6 +101,7 @@ def pass_call_c_argument(self): """ return "result" + class CCInterpreter(StackInterpreter): r""" A subclass of StackInterpreter, specifying an interpreter over diff --git a/src/sage_setup/autogen/interpreters/internal/storage.py b/src/sage_setup/autogen/interpreters/internal/storage.py index ce77abbe586..76c4f06e06f 100644 --- a/src/sage_setup/autogen/interpreters/internal/storage.py +++ b/src/sage_setup/autogen/interpreters/internal/storage.py @@ -852,6 +852,7 @@ def assign_c_from_py(self, c, py): ty_mpfr = StorageTypeMPFR() + class StorageTypeMPC(StorageTypeAutoReference): r""" StorageTypeMPC is a subtype of StorageTypeAutoReference that deals diff --git a/src/sage_setup/command/sage_build_cython.py b/src/sage_setup/command/sage_build_cython.py index f4b1357c543..880ce7383e2 100644 --- a/src/sage_setup/command/sage_build_cython.py +++ b/src/sage_setup/command/sage_build_cython.py @@ -49,6 +49,7 @@ if DEVEL: extra_compile_args.append('-ggdb') + class sage_build_cython(Command): name = 'build_cython' description = "compile Cython extensions into C/C++ extensions" diff --git a/src/sage_setup/command/sage_build_ext.py b/src/sage_setup/command/sage_build_ext.py index a9c5a87a673..5ef452316f0 100644 --- a/src/sage_setup/command/sage_build_ext.py +++ b/src/sage_setup/command/sage_build_ext.py @@ -15,6 +15,7 @@ from distutils.errors import DistutilsSetupError from sage_setup.run_parallel import execute_list_of_commands + class sage_build_ext(build_ext): def finalize_options(self): build_ext.finalize_options(self) diff --git a/src/sage_setup/command/sage_build_ext_minimal.py b/src/sage_setup/command/sage_build_ext_minimal.py index 34ac31f8a87..25cab109ff8 100644 --- a/src/sage_setup/command/sage_build_ext_minimal.py +++ b/src/sage_setup/command/sage_build_ext_minimal.py @@ -20,7 +20,7 @@ def get_default_number_build_jobs() -> int: Get number of parallel build jobs used by default, i.e. unless explicitly set by the --parallel command line argument of setup.py. - First, the environment variable `SAGE_NUM_THREADS` is checked. + First, the environment variable ``SAGE_NUM_THREADS`` is checked. If that is unset, return the number of processors on the system, with a maximum of 10 (to prevent overloading the system if there a lot of CPUs). diff --git a/src/sage_setup/excepthook.py b/src/sage_setup/excepthook.py index e5206d9c082..a40cf7cec4d 100644 --- a/src/sage_setup/excepthook.py +++ b/src/sage_setup/excepthook.py @@ -1,6 +1,7 @@ import os import sys + def excepthook(*exc): """ When an error occurs, display an error message similar to the error diff --git a/src/sage_setup/find.py b/src/sage_setup/find.py index e00336b3443..fa963c2a124 100644 --- a/src/sage_setup/find.py +++ b/src/sage_setup/find.py @@ -172,6 +172,7 @@ def find_python_sources(src_dir, modules=['sage'], distributions=None, os.chdir(cwd) return python_packages, python_modules, cython_modules + def filter_cython_sources(src_dir, distributions, exclude_distributions=None): """ Find all Cython modules in the given source directory that belong to the @@ -221,6 +222,7 @@ def filter_cython_sources(src_dir, distributions, exclude_distributions=None): return files + def _cythonized_dir(src_dir=None, editable_install=None): """ Return the path where Cython-generated files are placed by the build system. @@ -343,6 +345,7 @@ def find_extra_files(src_dir, modules, cythonized_dir, special_filenames=[], *, return data_files + def installed_files_by_module(site_packages, modules=('sage',)): """ Find all currently installed files diff --git a/src/sage_setup/run_parallel.py b/src/sage_setup/run_parallel.py index 5e25cd1b6a6..a920f4070e8 100644 --- a/src/sage_setup/run_parallel.py +++ b/src/sage_setup/run_parallel.py @@ -22,6 +22,7 @@ keep_going = False + def run_command(cmd): """ INPUT: @@ -35,6 +36,7 @@ def run_command(cmd): sys.stdout.flush() return os.system(cmd) + def apply_func_progress(p): """ Given a triple p consisting of a function, value and a string, @@ -49,6 +51,7 @@ def apply_func_progress(p): sys.stdout.flush() return p[0](p[1]) + def execute_list_of_commands_in_parallel(command_list, nthreads): """ Execute the given list of commands, possibly in parallel, using @@ -83,6 +86,7 @@ def execute_list_of_commands_in_parallel(command_list, nthreads): pool.join() process_command_results(result) + def process_command_results(result_values): error = None for r in result_values: @@ -94,6 +98,7 @@ def process_command_results(result_values): if error: sys.exit(1) + def execute_list_of_commands(command_list): """ INPUT: @@ -124,10 +129,10 @@ def execute_list_of_commands(command_list): nthreads = min(len(command_list), nthreads) nthreads = max(1, nthreads) - def plural(n,noun): + def plural(n, noun): if n == 1: return "1 %s" % noun - return "%i %ss" % (n,noun) + return "%i %ss" % (n, noun) print("Executing %s (using %s)" % (plural(len(command_list),"command"), plural(nthreads,"thread"))) execute_list_of_commands_in_parallel(command_list, nthreads) diff --git a/src/sage_setup/setenv.py b/src/sage_setup/setenv.py index 48a38afad74..e7ad6552440 100644 --- a/src/sage_setup/setenv.py +++ b/src/sage_setup/setenv.py @@ -4,6 +4,7 @@ import platform from pathlib import Path + def _environ_prepend(var, value, separator=':'): if value: if var in os.environ: @@ -11,6 +12,7 @@ def _environ_prepend(var, value, separator=':'): else: os.environ[var] = value + def setenv(): from sage.env import SAGE_LOCAL, SAGE_VENV, SAGE_ARCHFLAGS, SAGE_PKG_CONFIG_PATH diff --git a/src/setup.cfg.m4 b/src/setup.cfg.m4 index 969793209c8..3a4ec930b8f 100644 --- a/src/setup.cfg.m4 +++ b/src/setup.cfg.m4 @@ -9,7 +9,7 @@ license_files = LICENSE.txt include(`setup_cfg_metadata.m4')dnl' [options] -python_requires = >=3.9, <3.13 +python_requires = >=3.9, <3.14 install_requires = SPKG_INSTALL_REQUIRES_six dnl From build/pkgs/sagelib/dependencies diff --git a/src/tox.ini b/src/tox.ini index b6548bc55a4..29dd3fcaa15 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -180,7 +180,7 @@ description = # W605: invalid escape sequence ‘x’ # See https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes deps = pycodestyle -commands = pycodestyle --select E111,E21,E221,E222,E225,E227,E228,E25,E271,E275,E303,E305,E306,E401,E502,E701,E702,E703,E71,E72,W291,W293,W391,W605 {posargs:{toxinidir}/sage/} +commands = pycodestyle --select E111,E21,E221,E222,E225,E227,E228,E25,E271,E275,E302,E303,E305,E306,E401,E502,E701,E702,E703,E71,E72,W291,W293,W391,W605 {posargs:{toxinidir}/sage/} pycodestyle --select E111,E271,E301,E302,E303,E305,E306,E401,E502,E703,E712,E713,E714,E72,W29,W391,W605, --filename *.pyx {posargs:{toxinidir}/sage/} [pycodestyle] @@ -302,19 +302,16 @@ passenv = RUFF_OUTPUT_FORMAT # 12 F811 [*] Redefinition of unused `CompleteDiscreteValuationRings` from line 49 # 8 PLC0414 [*] Import alias does not rename original package # 7 E743 [ ] Ambiguous function name: `I` -# 7 PLE0101 [ ] Explicit return in `__init__` # 7 PLR0124 [ ] Name compared with itself, consider replacing `a == a` # 5 PLW0127 [ ] Self-assignment of variable `a` -# 4 F541 [*] f-string without any placeholders # 4 PLW1508 [ ] Invalid type for environment variable default; expected `str` or `None` # 3 PLC3002 [ ] Lambda expression called directly. Execute the expression inline instead. # 2 E742 [ ] Ambiguous class name: `I` # 2 PLE0302 [ ] The special method `__len__` expects 1 parameter, 3 were given -# 2 PLW0129 [ ] Asserting on a non-empty string literal will always pass # 1 F402 [ ] Import `factor` from line 259 shadowed by loop variable # 1 PLC0208 [*] Use a sequence type instead of a `set` when iterating over values # -commands = ruff check --ignore PLR2004,I001,F401,E741,F821,PLR0912,PLR0913,E402,PLR0915,PLW2901,PLR5501,PLR0911,E731,F405,PLR1714,PLR1736,F403,PLR0402,PLW0603,F841,PLW0602,PLW0642,PLR1711,E714,SIM101,PLR1704,PLW3301,PLW1510,E721,PLW0211,PLW0120,F811,PLC2401,PLC0414,E743,PLE0101,PLR0124,PLW0127,F541,PLW1508,PLC3002,E742,PLE0302,PLW0129,F402,PLC0208 {posargs:{toxinidir}/sage/} +commands = ruff check --ignore E402,E721,E731,E741,E742,E743,F401,F402,F403,F405,F821,F841,I001,PLC0206,PLC0208,PLC2401,PLC3002,PLE0302,PLR0124,PLR0402,PLR0911,PLR0912,PLR0913,PLR0915,PLR1704,PLR1711,PLR1714,PLR1736,PLR2004,PLR5501,PLW0120,PLW0127,PLW0211,PLW0602,PLW0603,PLW0642,PLW1508,PLW1510,PLW2901,PLW3301 {posargs:{toxinidir}/sage/} [flake8] rst-roles = @@ -377,14 +374,6 @@ exclude = sage/graphs/graph_plot.py sage/misc/sagedoc.py -[pytest] -python_files = *_test.py -norecursedirs = local prefix venv build builddir pkgs .git src/doc src/bin tools -addopts = --import-mode importlib -doctest_optionflags = NORMALIZE_WHITESPACE ELLIPSIS -# https://docs.pytest.org/en/stable/reference/reference.html#confval-consider_namespace_packages -consider_namespace_packages = True - [coverage:run] source = sage concurrency = multiprocessing,thread diff --git a/subprojects/factory b/subprojects/factory new file mode 160000 index 00000000000..769668a07b8 --- /dev/null +++ b/subprojects/factory @@ -0,0 +1 @@ +Subproject commit 769668a07b8110213dc5d8113ad24dd096439d4c diff --git a/tools/README.md b/tools/README.md index b0c2e4bb68b..4e4905739b5 100644 --- a/tools/README.md +++ b/tools/README.md @@ -2,6 +2,22 @@ This folder contains various command-line tools that are used to facilitate different development tasks. Below is a brief description of each command available in this directory. +## Update Conda Environment Files + +This command is used to update the Conda environment files in the project. It automatically adds new dependencies to the Conda files, removes deleted dependencies, and updates the version of existing dependencies. The source of the dependencies is the `pyproject.toml` file, which specifies the following dependencies: + +- `build-system.requires`: Python dependencies required for building +- `project.dependencies`: Python dependencies required for running +- `external.build-requires`: External dependencies required for building +- `external.host-requires`: External dependencies required for running + + +Within an active virtual environment where `grayskull`, `conda-lock` and `toml` are installed, run the following command: + +```bash +tools/update-conda.py +``` + ## Update Meson Build Files This command is used to updates the Meson build files in the project. It automatically adds new source files (py, pyx) to the Meson files and removes deleted source files. This command is useful when adding or removing source files from the project. @@ -9,5 +25,5 @@ This command is used to updates the Meson build files in the project. It automat Within an active virtual environment where Meson is installed, run the following command: ```bash -tools/update_meson.py +tools/update-meson.py ``` diff --git a/tools/update-conda.py b/tools/update-conda.py new file mode 100644 index 00000000000..3ed5a083785 --- /dev/null +++ b/tools/update-conda.py @@ -0,0 +1,181 @@ +#!/usr/bin/env python3 +# Requirements: pip install https://github.com/conda/grayskull conda-lock +# Usage: python tools/update-conda.py . + +import argparse +import subprocess +from pathlib import Path + +import toml as tomllib +from grayskull.config import Configuration +from grayskull.strategy.py_base import merge_setup_toml_metadata +from grayskull.strategy.py_toml import get_all_toml_info +from grayskull.strategy.pypi import extract_requirements, normalize_requirements_list +from packaging.requirements import Requirement + +# Get source directory from command line arguments +parser = argparse.ArgumentParser() +parser.add_argument( + "sourcedir", help="Source directory", nargs="?", default=".", type=Path +) +options = parser.parse_args() + +platforms = { + "linux-64": "linux", + "linux-aarch64": "linux-aarch64", + "osx-64": "macos-x86_64", + "osx-arm64": "macos", + # "win-64": "win", +} +pythons = ["3.11", "3.12"] +tags = [""] + + +def write_env_file(env_file: Path, dependencies: list[str]) -> None: + env_file.write_text( + """name: sage +channels: + - conda-forge + - nodefaults +dependencies: +""" + + "".join(f" - {req}" + "\n" for req in dependencies) + ) + print(f"Conda environment file written to {env_file}") + + +def filter_requirements(dependencies: set[str], python: str) -> set[str]: + def filter_dep(dep: str): + req = Requirement(dep) + env = {"python_version": python} + if not req.marker or req.marker.evaluate(env): + # Serialize the requirement without the marker + req.marker = None + return str(req) + return None + + return set(filter(None, map(filter_dep, dependencies))) + + +def update_conda(source_dir: Path) -> None: + pyproject_toml = source_dir / "pyproject.toml" + if not pyproject_toml.exists(): + print(f"pyproject.toml not found in {pyproject_toml}") + return + + for platform_key, platform_value in platforms.items(): + for python in pythons: + dependencies = get_dependencies(pyproject_toml, python) + for tag in tags: + # Pin Python version + pinned_dependencies = { + f"python={python}" if dep == "python" else dep + for dep in dependencies + } + + dev_dependencies = get_dev_dependencies(pyproject_toml) + print(f"Adding dev dependencies: {dev_dependencies}") + pinned_dependencies = pinned_dependencies.union(dev_dependencies) + + pinned_dependencies = sorted(pinned_dependencies) + + env_file = source_dir / f"environment{tag}-{python}.yml" + write_env_file(env_file, pinned_dependencies) + lock_file = source_dir / f"environment{tag}-{python}-{platform_value}" + lock_file_gen = ( + source_dir / f"environment{tag}-{python}-{platform_value}.yml" + ) + print( + f"Updating lock file for {env_file} at {lock_file_gen}", flush=True + ) + subprocess.run( + [ + "conda-lock", + "--mamba", + "--channel", + "conda-forge", + "--kind", + "env", + "--platform", + platform_key, + "--file", + str(env_file), + "--lockfile", + str(lock_file), + "--filename-template", + str(lock_file), + ], + check=True, + ) + + # Add conda env name to lock file at beginning + with open(lock_file_gen, "r+") as f: + content = f.read() + f.seek(0, 0) + f.write(f"name: sage{tag or '-dev'}\n{content}") + + +def get_dependencies(pyproject_toml: Path, python: str) -> list[str]: + grayskull_config = Configuration("sagemath") + pyproject_metadata = merge_setup_toml_metadata( + {}, get_all_toml_info(pyproject_toml) + ) + requirements = extract_requirements(pyproject_metadata, grayskull_config, {}) + all_requirements = ( + requirements.get("build", []) + + requirements.get("host", []) + + requirements.get("run", []) + ) + + # Specify concrete package for some virtual packages + all_requirements.remove("{{ blas }}") + all_requirements.append("blas=2.*=openblas") + all_requirements.remove("{{ compiler('c') }}") + all_requirements.append("c-compiler") + all_requirements.remove("{{ compiler('cxx') }}") + all_requirements.append("cxx-compiler") + # all_requirements.remove("{{ compiler('fortran') }}") + all_requirements.append("fortran-compiler") + + # Correct pypi name for some packages + python_requirements = set(pyproject_metadata.get("install_requires", [])) + # Specify concrete packages for some packages not yet in grayskull + python_requirements.remove("pkg:generic/tachyon") + python_requirements.add("tachyon") + python_requirements.remove("pkg:generic/sagemath-elliptic-curves") + python_requirements.add("sagemath-db-elliptic-curves") + python_requirements.remove("pkg:generic/sagemath-polytopes-db") + python_requirements.add("sagemath-db-polytopes") + python_requirements.discard("pkg:generic/sagemath-graphs") + python_requirements.add("sagemath-db-graphs") + python_requirements.remove("memory_allocator") + python_requirements.add("memory-allocator") + # Following can be removed once https://github.com/regro/cf-scripts/pull/2176 is used in grayskull + python_requirements = { + req.replace("lrcalc", "python-lrcalc") for req in python_requirements + } + python_requirements = filter_requirements(python_requirements, python) + all_requirements += normalize_requirements_list( + python_requirements, grayskull_config + ) + all_requirements.remove("<{ pin_compatible('numpy') }}") + all_requirements.remove("memory_allocator") + # Needed to run configure/bootstrap, can be deleted once we fully migrated to meson + all_requirements.append("autoconf") + all_requirements.append("automake") + all_requirements.append("m4") + # Needed to fix a bug on Macos with broken pkg-config + all_requirements.append("expat") + return all_requirements + + +def get_dev_dependencies(pyproject_toml: Path) -> list[str]: + pyproject = tomllib.load(pyproject_toml) + dependency_groups = pyproject.get("dependency-groups", {}) + dev_dependencies = dependency_groups.get("test", []) + dependency_groups.get( + "docs", [] + ) + return dev_dependencies + + +update_conda(options.sourcedir) diff --git a/tools/update-meson.py b/tools/update-meson.py index 827b7d9b5a3..1a53ac21397 100755 --- a/tools/update-meson.py +++ b/tools/update-meson.py @@ -86,9 +86,6 @@ def update_python_sources(self: Rewriter, visitor: AstPython): to_append: list[StringNode] = [] for file in python_files: file_name = file.name - if file_name == "__init__.py": - # We don't want to add __init__.py files - continue if file_name in src_list: continue token = Token("string", target.filename, 0, 0, 0, None, file_name)