diff --git a/.ci/create-changes-html.sh b/.ci/create-changes-html.sh index 2cca91d81c8..0e80d0d2814 100755 --- a/.ci/create-changes-html.sh +++ b/.ci/create-changes-html.sh @@ -1,11 +1,12 @@ #!/bin/sh if [ $# != 2 ]; then - echo >&2 "usage: $0 BASE_DOC_COMMIT DOC_REPO" - echo >&2 "creates CHANGES.html in the current directory" - echo >&2 "for the diffs of DOC_REPO against BASE_DOC_COMMIT" + echo >&2 "Usage: $0 DIFF_TEXT DOC_REPO" + echo >&2 "This script generates a CHANGES.html file in the current directory" + echo >&2 "and adds anchor targets in the documents within DOC_REPO" + echo >&2 "based on the diff hunks in the DIFF_TEXT file." exit 1 fi -BASE_DOC_COMMIT="$1" +DIFF_TEXT="$1" DOC_REPOSITORY="$2" # Create CHANGES.html @@ -52,11 +53,10 @@ diffParagraphs.forEach(paragraph => { EOF echo '' >> CHANGES.html echo '' >> CHANGES.html -(cd $DOC_REPOSITORY && git diff $BASE_DOC_COMMIT -- "*.html") > diff.txt python3 - << EOF import os, re, html from itertools import chain -with open('diff.txt', 'r') as f: +with open('$DIFF_TEXT', 'r') as f: diff_text = f.read() diff_blocks = re.split(r'^(?=diff --git)', diff_text, flags=re.MULTILINE) out_blocks = [] @@ -83,12 +83,21 @@ for block in diff_blocks: hunk_lines = [] search_result = re.search(r'@@ -(\d+),(\d+) \+(\d+),(\d+)', line) if search_result: - line_number = int(search_result.group(3)) + line_number = int(search_result.group(3)) - 1 span = int(search_result.group(4)) for i in chain(range(line_number, line_number + span), range(line_number - 1, -1, -1)): - if content[i].startswith('<') and not content[i].startswith('' + content[i] + content[i] = ln[:idx] + f'' + ln[idx:] hunks.append(f'

hunk #{count}

') break hunk_lines.append(line) @@ -107,4 +116,4 @@ EOF cat diff.html >> CHANGES.html echo '' >> CHANGES.html echo '' >> CHANGES.html -rm diff.txt diff.html +rm diff.html diff --git a/.ci/write-dockerfile.sh b/.ci/write-dockerfile.sh index 75f89b23868..68c19ca675e 100755 --- a/.ci/write-dockerfile.sh +++ b/.ci/write-dockerfile.sh @@ -283,8 +283,8 @@ $ADD .upstream.d /new/.upstream.d ADD .ci /.ci RUN if [ -d /sage ]; then \ echo "### Incremental build from \$(cat /sage/VERSION.txt)" && \ - printf '/src\n!/src/doc/bootstrap\n!/src/bin\n!/src/*.m4\n!/src/*.toml\n!/src/VERSION.txt\n' >> /sage/.gitignore && \ - printf '/src\n!/src/doc/bootstrap\n!/src/bin\n!/src/*.m4\n!/src/*.toml\n!/src/VERSION.txt\n' >> /new/.gitignore && \ + printf '/src/*\n!/src/doc/bootstrap\n!/src/bin\n!/src/*.m4\n!/src/*.toml\n!/src/VERSION.txt\n' >> /sage/.gitignore && \ + printf '/src/*\n!/src/doc/bootstrap\n!/src/bin\n!/src/*.m4\n!/src/*.toml\n!/src/VERSION.txt\n' >> /new/.gitignore && \ if ! (cd /new && /.ci/retrofit-worktree.sh worktree-image /sage); then \ echo "retrofit-worktree.sh failed, falling back to replacing /sage"; \ for a in local logs; do \ diff --git a/.devcontainer/portability-centos-stream-9-python3.9-minimal/devcontainer.json b/.devcontainer/portability-centos-stream-9-minimal/devcontainer.json similarity index 85% rename from .devcontainer/portability-centos-stream-9-python3.9-minimal/devcontainer.json rename to .devcontainer/portability-centos-stream-9-minimal/devcontainer.json index acf524fe795..6c714ff4879 100644 --- a/.devcontainer/portability-centos-stream-9-python3.9-minimal/devcontainer.json +++ b/.devcontainer/portability-centos-stream-9-minimal/devcontainer.json @@ -3,12 +3,12 @@ // from .devcontainer/portability-devcontainer.json.in // See https://aka.ms/devcontainer.json for format details. { - "name": "centos-stream-9-python3.9-minimal (≥ 8-core)", + "name": "centos-stream-9-minimal (≥ 8-core)", "build": { "dockerfile": "portability-Dockerfile", // See tox.ini for definitions "args": { - "SYSTEM_FACTOR": "centos-stream-9-python3.9", + "SYSTEM_FACTOR": "centos-stream-9", "PACKAGE_FACTOR": "minimal", "DOCKER_TARGET": "with-targets", "DOCKER_TAG": "dev" diff --git a/.devcontainer/portability-centos-stream-9-python3.9-minimal/portability-Dockerfile b/.devcontainer/portability-centos-stream-9-minimal/portability-Dockerfile similarity index 100% rename from .devcontainer/portability-centos-stream-9-python3.9-minimal/portability-Dockerfile rename to .devcontainer/portability-centos-stream-9-minimal/portability-Dockerfile diff --git a/.devcontainer/portability-centos-stream-9-python3.12-minimal/devcontainer.json b/.devcontainer/portability-centos-stream-9-python3.12-minimal/devcontainer.json new file mode 100644 index 00000000000..05bcceac4e2 --- /dev/null +++ b/.devcontainer/portability-centos-stream-9-python3.12-minimal/devcontainer.json @@ -0,0 +1,25 @@ +// The command "tox -e update_docker_platforms" +// creates .devcontainer/portability-*-*/devcontainer.json +// from .devcontainer/portability-devcontainer.json.in +// See https://aka.ms/devcontainer.json for format details. +{ + "name": "centos-stream-9-python3.12-minimal (≥ 8-core)", + "build": { + "dockerfile": "portability-Dockerfile", + // See tox.ini for definitions + "args": { + "SYSTEM_FACTOR": "centos-stream-9-python3.12", + "PACKAGE_FACTOR": "minimal", + "DOCKER_TARGET": "with-targets", + "DOCKER_TAG": "dev" + } + }, + "containerEnv": { + "MAKE": "make -j4" + }, + "onCreateCommand": ".devcontainer/onCreate.sh", + "updateContentCommand": ".devcontainer/portability-updateContent.sh", + "extensions": [ + "ms-python.python" + ] +} diff --git a/.devcontainer/portability-centos-stream-9-python3.9-standard/portability-Dockerfile b/.devcontainer/portability-centos-stream-9-python3.12-minimal/portability-Dockerfile similarity index 100% rename from .devcontainer/portability-centos-stream-9-python3.9-standard/portability-Dockerfile rename to .devcontainer/portability-centos-stream-9-python3.12-minimal/portability-Dockerfile diff --git a/.devcontainer/portability-centos-stream-9-python3.12-standard/devcontainer.json b/.devcontainer/portability-centos-stream-9-python3.12-standard/devcontainer.json new file mode 100644 index 00000000000..56e71035e88 --- /dev/null +++ b/.devcontainer/portability-centos-stream-9-python3.12-standard/devcontainer.json @@ -0,0 +1,25 @@ +// The command "tox -e update_docker_platforms" +// creates .devcontainer/portability-*-*/devcontainer.json +// from .devcontainer/portability-devcontainer.json.in +// See https://aka.ms/devcontainer.json for format details. +{ + "name": "centos-stream-9-python3.12-standard (≥ 8-core)", + "build": { + "dockerfile": "portability-Dockerfile", + // See tox.ini for definitions + "args": { + "SYSTEM_FACTOR": "centos-stream-9-python3.12", + "PACKAGE_FACTOR": "standard", + "DOCKER_TARGET": "with-targets", + "DOCKER_TAG": "dev" + } + }, + "containerEnv": { + "MAKE": "make -j4" + }, + "onCreateCommand": ".devcontainer/onCreate.sh", + "updateContentCommand": ".devcontainer/portability-updateContent.sh", + "extensions": [ + "ms-python.python" + ] +} diff --git a/.devcontainer/portability-centos-stream-9-python3.12-standard/portability-Dockerfile b/.devcontainer/portability-centos-stream-9-python3.12-standard/portability-Dockerfile new file mode 120000 index 00000000000..692e2a79d64 --- /dev/null +++ b/.devcontainer/portability-centos-stream-9-python3.12-standard/portability-Dockerfile @@ -0,0 +1 @@ +../portability-Dockerfile \ No newline at end of file diff --git a/.devcontainer/portability-centos-stream-9-python3.9-standard/devcontainer.json b/.devcontainer/portability-centos-stream-9-standard/devcontainer.json similarity index 85% rename from .devcontainer/portability-centos-stream-9-python3.9-standard/devcontainer.json rename to .devcontainer/portability-centos-stream-9-standard/devcontainer.json index fa42385cae5..d3da5d3160a 100644 --- a/.devcontainer/portability-centos-stream-9-python3.9-standard/devcontainer.json +++ b/.devcontainer/portability-centos-stream-9-standard/devcontainer.json @@ -3,12 +3,12 @@ // from .devcontainer/portability-devcontainer.json.in // See https://aka.ms/devcontainer.json for format details. { - "name": "centos-stream-9-python3.9-standard (≥ 8-core)", + "name": "centos-stream-9-standard (≥ 8-core)", "build": { "dockerfile": "portability-Dockerfile", // See tox.ini for definitions "args": { - "SYSTEM_FACTOR": "centos-stream-9-python3.9", + "SYSTEM_FACTOR": "centos-stream-9", "PACKAGE_FACTOR": "standard", "DOCKER_TARGET": "with-targets", "DOCKER_TAG": "dev" diff --git a/.devcontainer/portability-centos-stream-9-standard/portability-Dockerfile b/.devcontainer/portability-centos-stream-9-standard/portability-Dockerfile new file mode 120000 index 00000000000..692e2a79d64 --- /dev/null +++ b/.devcontainer/portability-centos-stream-9-standard/portability-Dockerfile @@ -0,0 +1 @@ +../portability-Dockerfile \ No newline at end of file diff --git a/.devcontainer/portability-fedora-41-minimal/devcontainer.json b/.devcontainer/portability-fedora-41-minimal/devcontainer.json new file mode 100644 index 00000000000..3efafa0f18e --- /dev/null +++ b/.devcontainer/portability-fedora-41-minimal/devcontainer.json @@ -0,0 +1,25 @@ +// The command "tox -e update_docker_platforms" +// creates .devcontainer/portability-*-*/devcontainer.json +// from .devcontainer/portability-devcontainer.json.in +// See https://aka.ms/devcontainer.json for format details. +{ + "name": "fedora-41-minimal (≥ 8-core)", + "build": { + "dockerfile": "portability-Dockerfile", + // See tox.ini for definitions + "args": { + "SYSTEM_FACTOR": "fedora-41", + "PACKAGE_FACTOR": "minimal", + "DOCKER_TARGET": "with-targets", + "DOCKER_TAG": "dev" + } + }, + "containerEnv": { + "MAKE": "make -j4" + }, + "onCreateCommand": ".devcontainer/onCreate.sh", + "updateContentCommand": ".devcontainer/portability-updateContent.sh", + "extensions": [ + "ms-python.python" + ] +} diff --git a/.devcontainer/portability-fedora-41-minimal/portability-Dockerfile b/.devcontainer/portability-fedora-41-minimal/portability-Dockerfile new file mode 120000 index 00000000000..692e2a79d64 --- /dev/null +++ b/.devcontainer/portability-fedora-41-minimal/portability-Dockerfile @@ -0,0 +1 @@ +../portability-Dockerfile \ No newline at end of file diff --git a/.devcontainer/portability-fedora-41-standard/devcontainer.json b/.devcontainer/portability-fedora-41-standard/devcontainer.json new file mode 100644 index 00000000000..fd82a00396a --- /dev/null +++ b/.devcontainer/portability-fedora-41-standard/devcontainer.json @@ -0,0 +1,25 @@ +// The command "tox -e update_docker_platforms" +// creates .devcontainer/portability-*-*/devcontainer.json +// from .devcontainer/portability-devcontainer.json.in +// See https://aka.ms/devcontainer.json for format details. +{ + "name": "fedora-41-standard (≥ 8-core)", + "build": { + "dockerfile": "portability-Dockerfile", + // See tox.ini for definitions + "args": { + "SYSTEM_FACTOR": "fedora-41", + "PACKAGE_FACTOR": "standard", + "DOCKER_TARGET": "with-targets", + "DOCKER_TAG": "dev" + } + }, + "containerEnv": { + "MAKE": "make -j4" + }, + "onCreateCommand": ".devcontainer/onCreate.sh", + "updateContentCommand": ".devcontainer/portability-updateContent.sh", + "extensions": [ + "ms-python.python" + ] +} diff --git a/.devcontainer/portability-fedora-41-standard/portability-Dockerfile b/.devcontainer/portability-fedora-41-standard/portability-Dockerfile new file mode 120000 index 00000000000..692e2a79d64 --- /dev/null +++ b/.devcontainer/portability-fedora-41-standard/portability-Dockerfile @@ -0,0 +1 @@ +../portability-Dockerfile \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c7200f847d8..69bb8f6d12f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -102,7 +102,7 @@ jobs: uses: actions/checkout@v4 - name: Get changed files and packages id: changed-files - uses: tj-actions/changed-files@v44 + uses: tj-actions/changed-files@v45 with: # File extensions for doctests per sage.doctest.control.skipfile files_yaml: | @@ -176,7 +176,7 @@ jobs: - name: Build Docker image id: image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: # push and load may not be set together at the moment # @@ -291,7 +291,7 @@ jobs: - name: Build Docker image id: image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: push: true load: false @@ -389,7 +389,7 @@ jobs: - name: Build Docker image id: image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: push: true load: false @@ -503,7 +503,7 @@ jobs: - name: Build Docker image id: image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: push: true load: false diff --git a/.github/workflows/ci-linux-incremental.yml b/.github/workflows/ci-linux-incremental.yml index a7900534b32..8606e7a4ca5 100644 --- a/.github/workflows/ci-linux-incremental.yml +++ b/.github/workflows/ci-linux-incremental.yml @@ -46,7 +46,7 @@ jobs: - uses: actions/checkout@v4 - name: Get all packages that have changed id: changed-files - uses: tj-actions/changed-files@v44 + uses: tj-actions/changed-files@v45 with: files_yaml: | configures: @@ -60,9 +60,9 @@ jobs: uninstall_targets=$(echo $(for a in '' ${{ steps.changed-files.outputs.configures_all_changed_files }}; do echo $a | sed -E 's,build/pkgs/([a-z0-9][_.a-z0-9]*)/spkg-configure[.]m4 *,\1-uninstall,'; done | sort -u)) build_targets=$(echo $(for a in '' ${{ steps.changed-files.outputs.pkgs_all_changed_files }}; do SPKG=$(echo $a | sed -E 's,-,_,g;s,(build/)?pkgs/([a-z0-9][-_.a-z0-9]*)/[^ ]* *,\2,;'); if [ -f "build/pkgs/$SPKG/checksums.ini" -o -f "build/pkgs/$SPKG/requirements.txt" -o -f "build/pkgs/$SPKG/spkg-install" ]; then echo "$SPKG-ensure"; fi; done | sort -u)) if [ -n "$uninstall_targets" ]; then - echo "build_targets=$uninstall_targets reconfigure $build_targets ci-build-with-fallback" >> $GITHUB_OUTPUT + echo "build_targets=$uninstall_targets reconfigure $build_targets" >> $GITHUB_OUTPUT else - echo "build_targets=$build_targets ci-build-with-fallback" >> $GITHUB_OUTPUT + echo "build_targets=$build_targets" >> $GITHUB_OUTPUT fi cat $GITHUB_OUTPUT - uses: actions/checkout@v4 @@ -92,7 +92,7 @@ jobs: from_docker_target: "with-targets" from_docker_tag: "dev" docker_targets: "with-targets" - targets: "${{needs.changed_files.outputs.build_targets}} doc-html ptest-nodoc" + targets: "${{needs.changed_files.outputs.build_targets}} ci-build-with-fallback doc-html ptest-nodoc" tox_system_factors: >- ["ubuntu-focal", "ubuntu-noble", @@ -108,6 +108,29 @@ jobs: docker_push_repository: ghcr.io/${{ github.repository }}/ max_parallel: 8 + constraints_pkgs-norequirements: + needs: [changed_files] + uses: ./.github/workflows/docker.yml + with: + # Build incrementally from published Docker image + incremental: true + free_disk_space: true + from_docker_repository: ghcr.io/sagemath/sage/ + from_docker_target: "with-targets-pre" + from_docker_tag: "dev" + docker_targets: "with-targets-pre" + targets_pre: "${{needs.changed_files.outputs.build_targets}} all-sage-local python3-ensure tox-ensure sagelib-tox-sagepython-constraints_pkgs-norequirements" + tox_system_factors: >- + ["ubuntu-focal", + "ubuntu-noble", + "debian-bookworm", + "fedora-40", + "debian-bullseye-i386"] + tox_packages_factors: >- + ["standard"] + docker_push_repository: ghcr.io/${{ github.repository }}/ + max_parallel: 16 + site: needs: [changed_files] uses: ./.github/workflows/docker.yml diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index cae29a27819..ca4607e3cc3 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -34,7 +34,7 @@ permissions: jobs: - # standard-pre and standard (without ptest) for the default platform (used by build.yml etc.) + # standard (without ptest) for the default platform (used by build.yml etc.) default: uses: ./.github/workflows/docker.yml with: @@ -54,24 +54,27 @@ jobs: # All platforms. This duplicates the default platform, but why not, # it makes it more robust regarding random timeouts. - standard-pre: + standard: if: ${{ success() || failure() }} uses: ./.github/workflows/docker.yml with: # Build from scratch - docker_targets: "with-system-packages configured with-targets-pre" + free_disk_space: true + docker_targets: "with-system-packages configured with-targets-pre with-targets with-targets-optional" # FIXME: duplicated from env.TARGETS targets_pre: all-sage-local + targets: build doc-html + targets_optional: ptest tox_packages_factors: >- ["standard"] docker_push_repository: ghcr.io/${{ github.repository }}/ - # Make sure that all "standard-pre" jobs can start simultaneously, + # Make sure that all "standard" jobs can start simultaneously, # so that runners are available by the time that "default" starts. max_parallel: 50 - standard: + standard-constraints_pkgs-norequirements: if: ${{ success() || failure() }} - needs: [standard-pre] + needs: [standard] uses: ./.github/workflows/docker.yml with: # Build incrementally from previous stage (pre) @@ -79,20 +82,15 @@ jobs: free_disk_space: true from_docker_repository: ghcr.io/${{ github.repository }}/ from_docker_target: "with-targets-pre" - docker_targets: "with-targets with-targets-optional" - # FIXME: duplicated from env.TARGETS - targets: build doc-html - targets_optional: ptest + docker_targets: "with-targets-pre" + targets_pre: all-sage-local python3-ensure tox-ensure sagelib-tox-sagepython-constraints_pkgs-norequirements tox_packages_factors: >- ["standard"] - docker_push_repository: ghcr.io/${{ github.repository }}/ - # Reduce from 30 to 20 because it runs in parallel with 'standard-sitepackages' - # and 'minimal-pre' below - max_parallel: 20 + max_parallel: 15 standard-sitepackages: if: ${{ success() || failure() }} - needs: [standard-pre] + needs: [standard] uses: ./.github/workflows/docker.yml with: # Build incrementally from previous stage (pre) @@ -128,38 +126,22 @@ jobs: docker_push_repository: ghcr.io/${{ github.repository }}/ max_parallel: 8 - minimal-pre: - if: ${{ success() || failure() }} - uses: ./.github/workflows/docker.yml - with: - # Build from scratch - docker_targets: "with-system-packages configured with-targets-pre" - # FIXME: duplicated from env.TARGETS - targets_pre: all-sage-local - tox_packages_factors: >- - ["minimal"] - docker_push_repository: ghcr.io/${{ github.repository }}/ - # Reduced from 30 because it may run in parallel with 'standard' and 'standard-sitepackages' above. - # Calibrated for clogging the job pipeline until the "default" job has finished. - max_parallel: 24 - minimal: if: ${{ success() || failure() }} - needs: [minimal-pre] uses: ./.github/workflows/docker.yml with: - # Build incrementally from previous stage (pre) - incremental: true + # Build from scratch free_disk_space: true - from_docker_repository: ghcr.io/${{ github.repository }}/ - from_docker_target: "with-targets-pre" - docker_targets: "with-targets with-targets-optional" + docker_targets: "with-system-packages configured with-targets-pre with-targets with-targets-optional" # FIXME: duplicated from env.TARGETS + targets_pre: all-sage-local targets: build doc-html targets_optional: ptest tox_packages_factors: >- ["minimal"] docker_push_repository: ghcr.io/${{ github.repository }}/ + # Reduced from 30 because it may run in parallel with 'standard' and 'standard-sitepackages' above. + # Calibrated for clogging the job pipeline until the "default" job has finished. max_parallel: 24 maximal-pre: @@ -176,7 +158,7 @@ jobs: ["maximal"] docker_push_repository: ghcr.io/${{ github.repository }}/ - optional-0-o: + optional: if: ${{ success() || failure() }} needs: [maximal-pre] uses: ./.github/workflows/docker.yml @@ -188,42 +170,12 @@ jobs: tox_packages_factors: >- ["maximal"] docker_targets: "with-targets-optional" - # [0-9a-o] excludes _, in particular package _develop - targets_optional: '$(echo $(export PATH=build/bin:$PATH && sage-package list :optional: --has-file "spkg-install.in|spkg-install|requirements.txt" --no-file "huge|has_nonfree_dependencies" | grep -v sagemath_doc | grep ^[0-9a-o]))' - - - optional-p-z: - if: ${{ success() || failure() }} - needs: [optional-0-o] - uses: ./.github/workflows/docker.yml - with: - incremental: true - free_disk_space: true - from_docker_repository: ghcr.io/${{ github.repository }}/ - from_docker_target: "with-targets-pre" - tox_packages_factors: >- - ["maximal"] - docker_targets: "with-targets-optional" - # [0-9a-o] excludes _, in particular package _develop - targets_optional: '$(echo $(export PATH=build/bin:$PATH && sage-package list :optional: --has-file "spkg-install.in|spkg-install|requirements.txt" --no-file "huge|has_nonfree_dependencies" | grep -v sagemath_doc | grep ^[p-z]))' - - experimental-0-o: - if: ${{ success() || failure() }} - needs: [optional-p-z] - uses: ./.github/workflows/docker.yml - with: - incremental: true - free_disk_space: true - from_docker_repository: ghcr.io/${{ github.repository }}/ - from_docker_target: "with-targets-pre" - tox_packages_factors: >- - ["maximal"] - docker_targets: "with-targets-optional" - targets_optional: '$(echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file "spkg-install.in|spkg-install|requirements.txt" --no-file "huge|has_nonfree_dependencies" | grep -v sagemath_doc | grep ^[0-9a-o]))' + # We remove packages starting with _, in particular package _develop + targets_optional: '$(echo $(export PATH=build/bin:$PATH && sage-package list :optional: --has-file "spkg-install.in|spkg-install|requirements.txt" --no-file "huge|has_nonfree_dependencies" | grep -v sagemath_doc | grep -v ^_))' - experimental-p-z: + experimental: if: ${{ success() || failure() }} - needs: [experimental-0-o] + needs: [optional] uses: ./.github/workflows/docker.yml with: incremental: true @@ -233,4 +185,4 @@ jobs: tox_packages_factors: >- ["maximal"] docker_targets: "with-targets-optional" - targets_optional: '$(echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file "spkg-install.in|spkg-install|requirements.txt" --no-file "huge|has_nonfree_dependencies" | grep -v sagemath_doc | grep ^[p-z]))' + targets_optional: '$(echo $(export PATH=build/bin:$PATH && sage-package list :experimental: --has-file "spkg-install.in|spkg-install|requirements.txt" --no-file "huge|has_nonfree_dependencies" | grep -v sagemath_doc))' diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml index 523118af032..1f7a2edbdf1 100644 --- a/.github/workflows/dist.yml +++ b/.github/workflows/dist.yml @@ -76,24 +76,6 @@ jobs: upstream name: release_dist - release: - - needs: release_dist - runs-on: ubuntu-latest - if: (success() || failure()) && github.repository == 'sagemath/sage' && startsWith(github.ref, 'refs/tags/') && !contains(github.ref, 'beta') && !contains(github.ref, 'rc') - steps: - - uses: actions/download-artifact@v4 - with: - name: release_dist - - uses: softprops/action-gh-release@v2 - with: - generate_release_notes: true - files: | - dist/* - upstream/* - permissions: - contents: write - sdists_for_pypi: runs-on: ubuntu-latest @@ -124,6 +106,29 @@ jobs: verbose: true if: env.CAN_DEPLOY == 'true' + release: + + needs: [release_dist, sdists_for_pypi] + runs-on: ubuntu-latest + if: (success() || failure()) && github.repository == 'sagemath/sage' && startsWith(github.ref, 'refs/tags/') + steps: + - uses: actions/download-artifact@v4 + with: + name: release_dist + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist + - uses: softprops/action-gh-release@v2 + with: + generate_release_notes: true + prerelease: ${{ contains(github.ref, 'beta') || contains(github.ref, 'rc') }} + files: | + dist/* + upstream/* + permissions: + contents: write + noarch_wheels_for_pypi: runs-on: ubuntu-latest diff --git a/.github/workflows/doc-build-pdf.yml b/.github/workflows/doc-build-pdf.yml index 0c1085138b1..dce25a132c9 100644 --- a/.github/workflows/doc-build-pdf.yml +++ b/.github/workflows/doc-build-pdf.yml @@ -84,7 +84,7 @@ jobs: - name: Build Docker image id: image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: # push and load may not be set together at the moment push: true diff --git a/.github/workflows/doc-build.yml b/.github/workflows/doc-build.yml index c5ff832b591..86418ff1f1f 100644 --- a/.github/workflows/doc-build.yml +++ b/.github/workflows/doc-build.yml @@ -95,7 +95,7 @@ jobs: - name: Build Docker image id: image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: # push and load may not be set together at the moment push: true @@ -204,9 +204,10 @@ jobs: -e 's;#L[0-9]*";";' \ && git commit -a -m 'wipe-out') # Since HEAD is at commit 'wipe-out', HEAD~1 is commit 'new' (new doc), HEAD~2 is commit 'old' (old doc) - .ci/create-changes-html.sh $(cd doc && git rev-parse HEAD~2) doc - # Restore the new doc with changes made in create-changes-html.sh but dropping changes by "wipe out" - (cd doc && git stash -q && git checkout -q -f HEAD~1 && git stash pop -q) + (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) + .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 (cd doc && mv .git ../git && mv .gitattributes ../gitattributes) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 2b6d83f6e78..4f3d1441544 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -47,7 +47,9 @@ on: "fedora-38", "fedora-39", "fedora-40", - "centos-stream-9-python3.9", + "fedora-41", + "centos-stream-9", + "centos-stream-9-python3.12", "almalinux-8-python3.9", "almalinux-9-python3.11", "gentoo-python3.10", @@ -242,9 +244,16 @@ jobs: # The arcane "find" command is a replacement for "pkill make", # which we use because pkill is not installed in the "minimal" package # configuration on many platforms. + # + # The "sed" command strips away timestamps from "docker build" (buildkit) + # such as "#25 1211.0" at the beginning of each line. The timestamps are + # redundant because GH Actions provides timestamps for each line already. + # Stripping the timestamps from the beginnings of lines also allows + # GitHub Actions to recognize workflow commands such as ::error etc. + # run: | (sleep ${{ inputs.timeout }}; for id in $(docker ps -q); do docker exec $id find /proc -maxdepth 2 -name cmdline -exec bash -c "grep -l [m][a][k][e] {} | cut -d/ -f3 | xargs --no-run-if-empty kill" \;; done) & - set -o pipefail; EXTRA_DOCKER_BUILD_ARGS="--build-arg NUMPROC=9 --build-arg USE_MAKEFLAGS=\"-k V=0 SAGE_NUM_THREADS=5\"" tox -e $TOX_ENV -- $TARGETS 2>&1 | sed "/^configure: notice:/s|^|::warning file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;/^configure: warning:/s|^|::warning file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;/^configure: error:/s|^|::error file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;" + set -o pipefail; EXTRA_DOCKER_BUILD_ARGS="--build-arg NUMPROC=9 --build-arg USE_MAKEFLAGS=\"-k V=0 SAGE_NUM_THREADS=5\"" tox -e $TOX_ENV -- $TARGETS 2>&1 | sed -E --unbuffered "s/^#[0-9]+ [0-9]+[.][0-9]+ //;/^configure: notice:/s|^|::warning file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;/^configure: warning:/s|^|::warning file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;/^configure: error:/s|^|::error file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;" - name: Copy logs from the Docker image or build container run: | mkdir -p "artifacts/$LOGS_ARTIFACT_NAME" diff --git a/.github/workflows/docker_hub.yml b/.github/workflows/docker_hub.yml index bb5b5232284..ed07bc2f03e 100644 --- a/.github/workflows/docker_hub.yml +++ b/.github/workflows/docker_hub.yml @@ -82,7 +82,7 @@ jobs: if: env.JOB_DONE == 'false' && env.CAN_LOGIN == 'true' - name: Build and push make-build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v6 with: context: . file: docker/Dockerfile diff --git a/CITATION.cff b/CITATION.cff index bc17013072e..983e656e9b4 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.beta2 +version: 10.5.beta3 doi: 10.5281/zenodo.8042260 -date-released: 2024-08-10 +date-released: 2024-09-03 repository-code: "https://github.com/sagemath/sage" url: "https://www.sagemath.org/" diff --git a/README.md b/README.md index 23d10cca6d5..7a318f53b79 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ below](#sagemath-docker-images)) or other virtualization solutions. [macOS] Preparing the Platform ------------------------------ -- If your Mac uses the Apple Silicon (M1, M2, M3; arm64) architecture and +- If your Mac uses the Apple Silicon (M1, M2, M3, M4; arm64) architecture and you set up your Mac by transferring files from an older Mac, make sure that the directory ``/usr/local`` does not contain an old copy of Homebrew (or other software) for the x86_64 architecture that you may have copied diff --git a/VERSION.txt b/VERSION.txt index edf3563b259..e6ed441beea 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -SageMath version 10.5.beta2, Release Date: 2024-08-10 +SageMath version 10.5.beta3, Release Date: 2024-09-03 diff --git a/build/make/Makefile.in b/build/make/Makefile.in index a59c81db529..420dadb9364 100644 --- a/build/make/Makefile.in +++ b/build/make/Makefile.in @@ -779,12 +779,14 @@ $(1)-sdist: FORCE python_build sage_setup cython . '$$(SAGE_ROOT)/src/bin/sage-env' && \ '$$(SAGE_ROOT)/build/pkgs/$(1)/spkg-src' -# Recursive tox invocation (note - we do not set the environment here). +# Recursive tox invocation # Setting SAGE_SPKG_WHEELS is for the benefit of sagelib's tox.ini $(1)-tox-%: FORCE $(AM_V_at)cd '$$(SAGE_ROOT)/build/pkgs/$(1)/src' && \ - export PATH="$$(SAGE_ORIG_PATH)" && \ - SAGE_SPKG_WHEELS=$$(SAGE_LOCAL)/var/lib/sage/wheels \ + . '$$(SAGE_ROOT)/src/bin/sage-src-env-config' && \ + . '$$(SAGE_ROOT)/src/bin/sage-env-config' && \ + . '$$(SAGE_ROOT)/src/bin/sage-env' && \ + SAGE_SPKG_WHEELS=$$(SAGE_VENV)/var/lib/sage/wheels \ tox -v -v -v -e $$* .PHONY: $(1) $(1)-uninstall $(1)-clean $(1)-build-deps $(1)-no-deps $(1)-clean diff --git a/build/pkgs/_python3.10/distros/fedora.txt b/build/pkgs/_python3.10/distros/fedora.txt index 02cc9cf73d1..8d607cac749 100644 --- a/build/pkgs/_python3.10/distros/fedora.txt +++ b/build/pkgs/_python3.10/distros/fedora.txt @@ -1,2 +1,3 @@ python3.10 python3.10-devel +python3.10-setuptools diff --git a/build/pkgs/_python3.11/distros/fedora.txt b/build/pkgs/_python3.11/distros/fedora.txt index 7fe5c300aed..439583212d6 100644 --- a/build/pkgs/_python3.11/distros/fedora.txt +++ b/build/pkgs/_python3.11/distros/fedora.txt @@ -1,2 +1,3 @@ python3.11 python3.11-devel +python3.11-setuptools diff --git a/build/pkgs/_python3.12/distros/fedora.txt b/build/pkgs/_python3.12/distros/fedora.txt index c3e29a02d27..bfc5e84864c 100644 --- a/build/pkgs/_python3.12/distros/fedora.txt +++ b/build/pkgs/_python3.12/distros/fedora.txt @@ -1,2 +1,3 @@ python3.12 python3.12-devel +python3.12-setuptools diff --git a/build/pkgs/_python3.9/distros/fedora.txt b/build/pkgs/_python3.9/distros/fedora.txt index 0e9352ce64c..466ad79cab3 100644 --- a/build/pkgs/_python3.9/distros/fedora.txt +++ b/build/pkgs/_python3.9/distros/fedora.txt @@ -1,3 +1,4 @@ python3.9 +python3.9-devel # Except on centos-stream-8 and almalinux-8, where it is called python39 and python39-devel; we special-case this in tox.ini -# python3.9 does not exist any more +python3.9-setuptools diff --git a/build/pkgs/cmake/spkg-configure.m4 b/build/pkgs/cmake/spkg-configure.m4 index 6149f49a7c5..62e04ffe135 100644 --- a/build/pkgs/cmake/spkg-configure.m4 +++ b/build/pkgs/cmake/spkg-configure.m4 @@ -1,5 +1,5 @@ SAGE_SPKG_CONFIGURE([cmake], [dnl - AC_CACHE_CHECK([for cmake >= 3.18], [ac_cv_path_CMAKE], [dnl + AC_CACHE_CHECK([for cmake >= 3.22], [ac_cv_path_CMAKE], [dnl dnl Do not accept cmake installed via https://pypi.org/project/cmake/ dnl in the default user scheme; it will not work in our venv because dnl we set PYTHONUSERBASE in sage-env. @@ -8,7 +8,7 @@ SAGE_SPKG_CONFIGURE([cmake], [dnl cmake_version=`$ac_path_CMAKE --version 2>&1 \ | $SED -n -e 's/cmake version *\([[0-9]]*\.[[0-9]]*\.[[0-9]]*\)/\1/p'` AS_IF([test -n "$cmake_version"], [dnl - AX_COMPARE_VERSION([$cmake_version], [ge], [3.18], [dnl + AX_COMPARE_VERSION([$cmake_version], [ge], [3.22], [dnl ac_cv_path_CMAKE="$ac_path_CMAKE" ac_path_CMAKE_found=: ]) diff --git a/build/pkgs/configure/checksums.ini b/build/pkgs/configure/checksums.ini index 69415aafab8..9882f48fdce 100644 --- a/build/pkgs/configure/checksums.ini +++ b/build/pkgs/configure/checksums.ini @@ -1,3 +1,3 @@ tarball=configure-VERSION.tar.gz -sha1=e162e0f52da5eca0c01ddf4831edcea1acd72033 -sha256=2033521228294e134368d69457d6e582706e84ff10bf3d6d0a57a2a4afad0a8b +sha1=0f6355fc136bb6619585863b9e4bc954cc6e0e3d +sha256=5b618581d51997afa78b5e6647584f7ef4e6d5844823dd44e607f2accd7abba5 diff --git a/build/pkgs/configure/package-version.txt b/build/pkgs/configure/package-version.txt index 2a5e3433ccb..f215e057b9e 100644 --- a/build/pkgs/configure/package-version.txt +++ b/build/pkgs/configure/package-version.txt @@ -1 +1 @@ -b178c10a7401b381b8ed2daab5aaf026436452c9 +b9cb7bc2559cde857d84d77f0b37a3616ce1eb6c diff --git a/build/pkgs/cypari/checksums.ini b/build/pkgs/cypari/checksums.ini index 8bedd4cf52d..d183b3c567a 100644 --- a/build/pkgs/cypari/checksums.ini +++ b/build/pkgs/cypari/checksums.ini @@ -1,4 +1,4 @@ tarball=cypari2-VERSION.tar.gz -sha1=4cb5fc43899852b7fc0c0175e610318c38f0caac -sha256=1a25865c34f20b1dc95830798e34ab6436e278b8e0c80dc7bf0ab34c5db03ab8 +sha1=4e9f14d218bc1cea29e03a2ceec9bf3dfbfd5eb3 +sha256=817606bf661b71d33e1d012421907a4f8fb09dd81b7d3e3ae179b3978020bbf1 upstream_url=https://pypi.io/packages/source/c/cypari2/cypari2-VERSION.tar.gz diff --git a/build/pkgs/cypari/dependencies b/build/pkgs/cypari/dependencies index 69dfe7e7d8a..cbf047c8027 100644 --- a/build/pkgs/cypari/dependencies +++ b/build/pkgs/cypari/dependencies @@ -1,4 +1,4 @@ - cython pari cysignals | $(PYTHON_TOOLCHAIN) $(PYTHON) +pari cysignals | $(PYTHON_TOOLCHAIN) cython $(PYTHON) ---------- All lines of this file are ignored except the first. diff --git a/build/pkgs/cypari/package-version.txt b/build/pkgs/cypari/package-version.txt index cd57a8b95d6..ccbccc3dc62 100644 --- a/build/pkgs/cypari/package-version.txt +++ b/build/pkgs/cypari/package-version.txt @@ -1 +1 @@ -2.1.5 +2.2.0 diff --git a/build/pkgs/cypari/patches/trashcan.patch b/build/pkgs/cypari/patches/trashcan.patch deleted file mode 100644 index f4918d4cd39..00000000000 --- a/build/pkgs/cypari/patches/trashcan.patch +++ /dev/null @@ -1,47 +0,0 @@ -commit 78e6dcf937c960c51132132e14f86bddbbe5b7d9 -Author: Jeroen Demeyer -Date: Tue Feb 19 11:50:49 2019 +0100 - - Use the trashcan for Gen - -diff --git a/cypari2/gen.pxd b/cypari2/gen.pxd -index 2ac0669..664d57d 100644 ---- a/cypari2/gen.pxd -+++ b/cypari2/gen.pxd -@@ -1,3 +1,4 @@ -+cimport cython - from cpython.object cimport PyObject - from .types cimport GEN, pari_sp - -diff --git a/cypari2/gen.pyx b/cypari2/gen.pyx -index d268cf1..687f5b2 100644 ---- a/cypari2/gen.pyx -+++ b/cypari2/gen.pyx -@@ -135,6 +135,7 @@ cdef extern from *: - GEN new_nfeltup(GEN nf, GEN x, GEN zknf) - - -+@cython.trashcan(True) - cdef class Gen(Gen_base): - """ - Wrapper for a PARI ``GEN`` with memory management. -diff --git a/cypari2/pari_instance.pyx b/cypari2/pari_instance.pyx -index ba82438..d13bc45 100644 ---- a/cypari2/pari_instance.pyx -+++ b/cypari2/pari_instance.pyx -@@ -243,6 +243,15 @@ Reset default precision for the following tests: - - >>> pari.set_real_precision_bits(53) - -+Test the trashcan mechanism (without the trashcan, this would cause -+a stack overflow): -+ -+>>> pari.allocatemem(2**27, silent=True) -+>>> L = [pari(i) for i in range(2**20)] -+>>> x = pari.Pi() -+>>> del L -+>>> del x -+ - Test that interrupts work properly: - - >>> pari.allocatemem(8000000, 2**29) diff --git a/build/pkgs/gcc/SPKG.rst b/build/pkgs/gcc/SPKG.rst index 1f90eb0bf67..7e01df5bea8 100644 --- a/build/pkgs/gcc/SPKG.rst +++ b/build/pkgs/gcc/SPKG.rst @@ -61,9 +61,9 @@ you need a recent version of Xcode. (Installing the ``gfortran`` SPKG becomes a no-op in this case.) -Building Sage from source on Apple Silicon (M1/M2) requires the use of -Apple's Command Line Tools, and those tools include a suitable -compiler. Sage's ``gcc`` SPKG is not suitable for M1/M2; building it +Building Sage from source on Apple Silicon (M1, M2, M3, M4; arm64) requires +the use of Apple's Command Line Tools, and those tools include a suitable +compiler. Sage's ``gcc`` SPKG is not suitable for Apple Silicon; building it will likely fail. License diff --git a/build/pkgs/gdb/SPKG.rst b/build/pkgs/gdb/SPKG.rst index 0716ac53fad..bd63d67763f 100644 --- a/build/pkgs/gdb/SPKG.rst +++ b/build/pkgs/gdb/SPKG.rst @@ -18,8 +18,3 @@ Upstream Contact ---------------- http://www.gnu.org/software/gdb/ - -Special Update/Build Instructions ---------------------------------- - -Current version needs makeinfo installed to build successfully. diff --git a/build/pkgs/gdb/checksums.ini b/build/pkgs/gdb/checksums.ini deleted file mode 100644 index ce68044ec98..00000000000 --- a/build/pkgs/gdb/checksums.ini +++ /dev/null @@ -1,3 +0,0 @@ -tarball=gdb-VERSION.tar.xz -sha1=ee66294d87a109f88a459d0da5d0bb2da5135f45 -sha256=c3a441a29c7c89720b734e5a9c6289c0a06be7e0c76ef538f7bbcef389347c39 diff --git a/build/pkgs/gdb/dependencies b/build/pkgs/gdb/dependencies deleted file mode 100644 index d6030116f99..00000000000 --- a/build/pkgs/gdb/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -mpfr zlib ncurses | $(PYTHON) xz - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/gdb/package-version.txt b/build/pkgs/gdb/package-version.txt deleted file mode 100644 index 2983cad0495..00000000000 --- a/build/pkgs/gdb/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -8.2 diff --git a/build/pkgs/gdb/spkg-install.in b/build/pkgs/gdb/spkg-install.in deleted file mode 100644 index 1c33ff83595..00000000000 --- a/build/pkgs/gdb/spkg-install.in +++ /dev/null @@ -1,11 +0,0 @@ -cd src - -# We add -ltinfo flag to let gdb compile on some 32bit VM, see #22487. -export LDFLAGS="${LDFLAGS} -L${SAGE_LOCAL}/lib -ltinfo" - -sdh_configure \ - $SAGE_CONFIGURE_MPC \ - $SAGE_CONFIGURE_MPFR \ - $SAGE_CONFIGURE_GMP -sdh_make -sdh_make_install diff --git a/build/pkgs/gdb/type b/build/pkgs/gdb/type index 9839eb20815..134d9bc32d5 100644 --- a/build/pkgs/gdb/type +++ b/build/pkgs/gdb/type @@ -1 +1 @@ -experimental +optional diff --git a/build/pkgs/libpng/checksums.ini b/build/pkgs/libpng/checksums.ini index 3ff528ccdc6..2a47aa72465 100644 --- a/build/pkgs/libpng/checksums.ini +++ b/build/pkgs/libpng/checksums.ini @@ -1,3 +1,4 @@ tarball=libpng-VERSION.tar.gz -sha1=012c842e6454dc38c6390623ed31ec4005c00584 -sha256=e30bf36cd5882e017c23a5c6a79a9aa1a744dd5841bb45ff7035ec6e3b3096b8 +sha1=eb7ed4d6d4646542fb4b4a0a3f53f7b419cf4965 +sha256=e804e465d4b109b5ad285a8fb71f0dd3f74f0068f91ce3cdfde618180c174925 +upstream_url=https://download.sourceforge.net/libpng/libpng-VERSION.tar.gz diff --git a/build/pkgs/libpng/package-version.txt b/build/pkgs/libpng/package-version.txt index 23b5c1f9732..75c0e87c8c4 100644 --- a/build/pkgs/libpng/package-version.txt +++ b/build/pkgs/libpng/package-version.txt @@ -1 +1 @@ -1.6.29.p1 +1.6.43 diff --git a/build/pkgs/libpng/spkg-install.in b/build/pkgs/libpng/spkg-install.in index 95326748188..628134cb715 100644 --- a/build/pkgs/libpng/spkg-install.in +++ b/build/pkgs/libpng/spkg-install.in @@ -1,13 +1,8 @@ # libpng needs to have no default options set for grep unset GREP_OPTIONS -export CFLAGS="$CFLAGS -fPIC -g" - -# Pick up Sage's zlib: -export CPPFLAGS="-I$SAGE_LOCAL/include $CPPFLAGS" - cd src -sdh_configure --enable-shared=yes +sdh_configure --enable-shared --disable-static sdh_make sdh_make_install diff --git a/build/pkgs/polymake/SPKG.rst b/build/pkgs/polymake/SPKG.rst index 844b603a0e1..f1e6522d65c 100644 --- a/build/pkgs/polymake/SPKG.rst +++ b/build/pkgs/polymake/SPKG.rst @@ -50,14 +50,19 @@ you will need the ``local::lib`` Perl module installed:: cpan -i XML::Writer XML::LibXML XML::LibXSLT File::Slurp Term::ReadLine::Gnu JSON SVG MongoDB -Several Sage packages should be installed before installing the ``polymake`` -package to give a more featureful Polymake installation:: +Before installing the ``polymake`` package, refer to the SPKG pages for the following packages to ensure a more featureful Polymake installation: - sage -i 4ti2 latte_int topcom qhull +- [4ti2](https://doc.sagemath.org/html/en/reference/spkg/4ti2.html) +- [latte_int](https://doc.sagemath.org/html/en/reference/spkg/latte_int.html) +- [topcom](https://doc.sagemath.org/html/en/reference/spkg/topcom.html) +- [qhull](https://doc.sagemath.org/html/en/reference/spkg/qhull.html) -Software that would need to be installed manually (no Sage package -available) for a more featureful Polymake installation: ``azove``, ``porta``, -``vinci``, ``SplitsTree4``. +For additional software that may enhance your Polymake installation (but for which no Sage package is available), you can manually install the following: + +- ``azove`` +- ``porta`` +- ``vinci`` +- ``SplitsTree4`` Information on missing Polymake prerequisites after installing polymake:: @@ -65,10 +70,8 @@ Information on missing Polymake prerequisites after installing polymake:: (sage-sh) $ polymake polytope> show_unconfigured; -In order to use Polymake from Sage, you will also need the ``jupymake`` -package:: +In order to use Polymake from Sage, please refer to the [Jupymake SPKG page](https://doc.sagemath.org/html/en/reference/spkg/jupymake.html) for installation instructions. - sage -i jupymake Debugging polymake install problems diff --git a/build/pkgs/python_build/distros/conda.txt b/build/pkgs/python_build/distros/conda.txt index 378eac25d31..162b1f739e8 100644 --- a/build/pkgs/python_build/distros/conda.txt +++ b/build/pkgs/python_build/distros/conda.txt @@ -1 +1 @@ -build +python-build diff --git a/build/pkgs/sage_conf/version_requirements.txt b/build/pkgs/sage_conf/version_requirements.txt index a0d122e1756..1c2fc34d235 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.5b2 +sage-conf ~= 10.5b3 diff --git a/build/pkgs/sage_docbuild/version_requirements.txt b/build/pkgs/sage_docbuild/version_requirements.txt index b3dd5668f62..42b2834c11f 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.5b2 +sage-docbuild ~= 10.5b3 diff --git a/build/pkgs/sage_setup/version_requirements.txt b/build/pkgs/sage_setup/version_requirements.txt index bab577d27f2..1cc1b467e16 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.5b2 +sage-setup ~= 10.5b3 diff --git a/build/pkgs/sage_sws2rst/version_requirements.txt b/build/pkgs/sage_sws2rst/version_requirements.txt index e641cf4adc8..4fc39dc2f32 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.5b2 +sage-sws2rst ~= 10.5b3 diff --git a/build/pkgs/sagelib/version_requirements.txt b/build/pkgs/sagelib/version_requirements.txt index 086538d8f55..70c35b74cca 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.5b2 +sagemath-standard ~= 10.5b3 diff --git a/build/pkgs/sagemath_bliss/version_requirements.txt b/build/pkgs/sagemath_bliss/version_requirements.txt index 3c1ecf4bcf2..21f92c61b22 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.5b2 +sagemath-bliss ~= 10.5b3 diff --git a/build/pkgs/sagemath_categories/version_requirements.txt b/build/pkgs/sagemath_categories/version_requirements.txt index 4e081e476c4..f78f1f84751 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.5b2 +sagemath-categories ~= 10.5b3 diff --git a/build/pkgs/sagemath_coxeter3/version_requirements.txt b/build/pkgs/sagemath_coxeter3/version_requirements.txt index f94c170af62..f1942993ae7 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.5b2 +sagemath-coxeter3 ~= 10.5b3 diff --git a/build/pkgs/sagemath_doc_html/dependencies b/build/pkgs/sagemath_doc_html/dependencies index 1d286fe50bc..801c36fcd9e 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 jmol ipywidgets jupyter_sphinx 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 jmol ipywidgets sage_docbuild elliptic_curves furo fpylll graphs # Building the documentation has many dependencies, because all # documented modules are imported and because we use matplotlib to diff --git a/build/pkgs/sagemath_doc_html/dependencies_optional b/build/pkgs/sagemath_doc_html/dependencies_optional new file mode 100644 index 00000000000..e9b59e89755 --- /dev/null +++ b/build/pkgs/sagemath_doc_html/dependencies_optional @@ -0,0 +1 @@ +jupyter_sphinx diff --git a/build/pkgs/sagemath_environment/version_requirements.txt b/build/pkgs/sagemath_environment/version_requirements.txt index 2915d669284..813d6d79688 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.5b2 +sagemath-environment ~= 10.5b3 diff --git a/build/pkgs/sagemath_mcqd/version_requirements.txt b/build/pkgs/sagemath_mcqd/version_requirements.txt index f066b99b596..e1297c038d3 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.5b2 +sagemath-mcqd ~= 10.5b3 diff --git a/build/pkgs/sagemath_meataxe/version_requirements.txt b/build/pkgs/sagemath_meataxe/version_requirements.txt index ad91adb1087..867597deb1e 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.5b2 +sagemath-meataxe ~= 10.5b3 diff --git a/build/pkgs/sagemath_objects/version_requirements.txt b/build/pkgs/sagemath_objects/version_requirements.txt index e8b79dc7bb5..83940689774 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.5b2 +sagemath-objects ~= 10.5b3 diff --git a/build/pkgs/sagemath_repl/version_requirements.txt b/build/pkgs/sagemath_repl/version_requirements.txt index 784aeb5cf8d..a4f097b1b6e 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.5b2 +sagemath-repl ~= 10.5b3 diff --git a/build/pkgs/sagemath_sirocco/version_requirements.txt b/build/pkgs/sagemath_sirocco/version_requirements.txt index dcfccd36238..ba5126542f8 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.5b2 +sagemath-sirocco ~= 10.5b3 diff --git a/build/pkgs/sagemath_tdlib/version_requirements.txt b/build/pkgs/sagemath_tdlib/version_requirements.txt index 3f3d3da3740..02cbd8f2d3f 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.5b2 +sagemath-tdlib ~= 10.5b3 diff --git a/build/pkgs/suitesparse/SPKG.rst b/build/pkgs/suitesparse/SPKG.rst index 7a9bd5d599c..ab673b390e7 100644 --- a/build/pkgs/suitesparse/SPKG.rst +++ b/build/pkgs/suitesparse/SPKG.rst @@ -2,26 +2,19 @@ suitesparse: A suite of sparse matrix software ============================================== SuiteSparse is a collection of software to deal with sparse matrix. It is -hosted at http://faculty.cse.tamu.edu/davis/suitesparse.html +hosted at https://people.engr.tamu.edu/davis/suitesparse.html with source code +now on github at https://github.com/DrTimothyAldenDavis/SuiteSparse -This spkg does a minimal install of suitesparse disabling the following +This spkg does a minimal install of suitesparse, only intalling the following -- metis -- GraphBLAS (need cmake) -- Mongoose (need cmake) +- AMD +- CAMD +- COLAMD +- CCOLAMD +- CHOLMOD +- UMFPACK -An external metis package can be used but we just disable its use. - -Patches: - -- The first patch disable the building of package using cmake. -- The second patch make sure we use sage's blas/lapack on OS X. By - default - suitesparse discard any configurations to use the accelerate framework. - -The building of metis is diabled by passing MY_METIS_LIB=none to make -(any value would have done) We also configure cholmod so it doesn't -require metis by passing CHOLMOD_CONFIG=-DNPARTITION to make. +Those are all the packages needed for cvxopt. Other configurations are self explanatory. diff --git a/build/pkgs/suitesparse/checksums.ini b/build/pkgs/suitesparse/checksums.ini index e05ee205baf..d3b1ad9641a 100644 --- a/build/pkgs/suitesparse/checksums.ini +++ b/build/pkgs/suitesparse/checksums.ini @@ -1,4 +1,4 @@ tarball=SuiteSparse-VERSION.tar.gz -sha1=83dd96b32701e12b7577acb7d9aea80138d7e46e -sha256=acb4d1045f48a237e70294b950153e48dce5b5f9ca8190e86c2b8c54ce00a7ee +sha1=aa2745d8e38d2c010e0a7256acd36eba1de19055 +sha256=8ea989f36be3646d0b0eecb06218698766ca06256c0de15a64350e993bf5c5f9 upstream_url=https://github.com/DrTimothyAldenDavis/SuiteSparse/archive/refs/tags/vVERSION.tar.gz diff --git a/build/pkgs/suitesparse/dependencies b/build/pkgs/suitesparse/dependencies index c9663df28f5..8ea6f6f523a 100644 --- a/build/pkgs/suitesparse/dependencies +++ b/build/pkgs/suitesparse/dependencies @@ -1 +1 @@ -$(BLAS) gfortran mpfr $(MP_LIBRARY) +$(BLAS) gfortran mpfr $(MP_LIBRARY) | cmake diff --git a/build/pkgs/suitesparse/package-version.txt b/build/pkgs/suitesparse/package-version.txt index 4e32c7b1caf..09a6d30847d 100644 --- a/build/pkgs/suitesparse/package-version.txt +++ b/build/pkgs/suitesparse/package-version.txt @@ -1 +1 @@ -5.10.1 +7.8.0 diff --git a/build/pkgs/suitesparse/patches/01-no_cmake_project.patch b/build/pkgs/suitesparse/patches/01-no_cmake_project.patch deleted file mode 100644 index 8b2b1a2666c..00000000000 --- a/build/pkgs/suitesparse/patches/01-no_cmake_project.patch +++ /dev/null @@ -1,90 +0,0 @@ -diff --git a/Makefile b/Makefile -index abd00d0f..10c31390 100644 ---- a/Makefile -+++ b/Makefile -@@ -16,7 +16,6 @@ include SuiteSparse_config/SuiteSparse_config.mk - # installs all libraries SuiteSparse/lib. - go: metis - ( cd SuiteSparse_config && $(MAKE) ) -- ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) - ( cd AMD && $(MAKE) ) - ( cd BTF && $(MAKE) ) - ( cd CAMD && $(MAKE) ) -@@ -34,7 +33,6 @@ ifneq ($(GPU_CONFIG),) - ( cd GPUQREngine && $(MAKE) ) - endif - ( cd SPQR && $(MAKE) ) -- ( cd GraphBLAS && $(MAKE) JOBS=$(JOBS) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) - ( cd SLIP_LU && $(MAKE) ) - # ( cd PIRO_BAND && $(MAKE) ) - # ( cd SKYLINE_SVD && $(MAKE) ) -@@ -46,7 +44,6 @@ endif - # (note that CSparse is not installed; CXSparse is installed instead) - install: metisinstall - ( cd SuiteSparse_config && $(MAKE) install ) -- ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) - ( cd AMD && $(MAKE) install ) - ( cd BTF && $(MAKE) install ) - ( cd CAMD && $(MAKE) install ) -@@ -63,7 +60,6 @@ ifneq (,$(GPU_CONFIG)) - ( cd GPUQREngine && $(MAKE) install ) - endif - ( cd SPQR && $(MAKE) install ) -- ( cd GraphBLAS && $(MAKE) JOBS=$(JOBS) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) - # ( cd PIRO_BAND && $(MAKE) install ) - # ( cd SKYLINE_SVD && $(MAKE) install ) - ( cd SLIP_LU && $(MAKE) install ) -@@ -126,7 +122,6 @@ endif - # the static library - library: metis - ( cd SuiteSparse_config && $(MAKE) ) -- ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' library ) - ( cd AMD && $(MAKE) library ) - ( cd BTF && $(MAKE) library ) - ( cd CAMD && $(MAKE) library ) -@@ -144,7 +139,6 @@ ifneq (,$(GPU_CONFIG)) - ( cd GPUQREngine && $(MAKE) library ) - endif - ( cd SPQR && $(MAKE) library ) -- ( cd GraphBLAS && $(MAKE) JOBS=$(JOBS) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' library ) - ( cd SLIP_LU && $(MAKE) library ) - # ( cd PIRO_BAND && $(MAKE) library ) - # ( cd SKYLINE_SVD && $(MAKE) library ) -@@ -154,7 +148,6 @@ endif - # both the dynamic and static libraries. - static: metis - ( cd SuiteSparse_config && $(MAKE) static ) -- ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' static ) - ( cd AMD && $(MAKE) static ) - ( cd BTF && $(MAKE) static ) - ( cd CAMD && $(MAKE) static ) -@@ -172,7 +165,6 @@ ifneq (,$(GPU_CONFIG)) - ( cd GPUQREngine && $(MAKE) static ) - endif - ( cd SPQR && $(MAKE) static ) -- ( cd GraphBLAS && $(MAKE) JOBS=$(JOBS) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' static ) - ( cd SLIP_LU && $(MAKE) static ) - # ( cd PIRO_BAND && $(MAKE) static ) - # ( cd SKYLINE_SVD && $(MAKE) static ) -@@ -291,21 +283,3 @@ else - @echo 'Using pre-installed METIS 5.1.0 library at ' '[$(MY_METIS_LIB)]' - endif - --# just compile GraphBLAS --gb: -- echo $(CMAKE_OPTIONS) -- ( cd GraphBLAS && $(MAKE) JOBS=$(JOBS) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) -- --# just install GraphBLAS --gbinstall: -- echo $(CMAKE_OPTIONS) -- ( cd GraphBLAS && $(MAKE) JOBS=$(JOBS) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) -- --# just compile Mongoose --mon: -- ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' ) -- --# just install Mongoose --moninstall: -- ( cd Mongoose && $(MAKE) CMAKE_OPTIONS='$(CMAKE_OPTIONS)' install ) -- diff --git a/build/pkgs/suitesparse/patches/02-darwin_blas.patch b/build/pkgs/suitesparse/patches/02-darwin_blas.patch deleted file mode 100644 index 546bfc80642..00000000000 --- a/build/pkgs/suitesparse/patches/02-darwin_blas.patch +++ /dev/null @@ -1,15 +0,0 @@ -diff --git a/SuiteSparse_config/SuiteSparse_config.mk b/SuiteSparse_config/SuiteSparse_config.mk -index 2fe1ab09..352ff593 100644 ---- a/SuiteSparse_config/SuiteSparse_config.mk -+++ b/SuiteSparse_config/SuiteSparse_config.mk -@@ -370,8 +370,8 @@ SUITESPARSE_VERSION = 5.10.1 - # command line in the Terminal, before doing 'make': - # xcode-select --install - CF += -fno-common -- BLAS ?= -framework Accelerate -- LAPACK ?= -framework Accelerate -+ #BLAS ?= -framework Accelerate -+ #LAPACK ?= -framework Accelerate - # OpenMP is not yet supported by default in clang - CFOPENMP = - LDLIBS += -rpath $(INSTALL_LIB) diff --git a/build/pkgs/suitesparse/patches/03-buildflags.patch b/build/pkgs/suitesparse/patches/03-buildflags.patch deleted file mode 100644 index 8a2c312be39..00000000000 --- a/build/pkgs/suitesparse/patches/03-buildflags.patch +++ /dev/null @@ -1,35 +0,0 @@ -diff --git a/SuiteSparse_config/SuiteSparse_config.mk b/SuiteSparse_config/SuiteSparse_config.mk -index 352ff593..61f0076e 100644 ---- a/SuiteSparse_config/SuiteSparse_config.mk -+++ b/SuiteSparse_config/SuiteSparse_config.mk -@@ -72,9 +72,9 @@ SUITESPARSE_VERSION = 5.10.1 - # which puts the libraries in /yada/mylibs, include files in /yoda/myinc, - # and documentation in /solo/mydox. - INSTALL ?= $(SUITESPARSE) -- INSTALL_LIB ?= $(INSTALL)/lib -- INSTALL_INCLUDE ?= $(INSTALL)/include -- INSTALL_DOC ?= $(INSTALL)/share/doc/suitesparse-$(SUITESPARSE_VERSION) -+ INSTALL_LIB ?= $(DESTDIR)$(INSTALL)/lib -+ INSTALL_INCLUDE ?= $(DESTDIR)$(INSTALL)/include -+ INSTALL_DOC ?= $(DESTDIR)$(INSTALL)/share/doc/suitesparse-$(SUITESPARSE_VERSION) - - #--------------------------------------------------------------------------- - # parallel make -@@ -358,7 +358,7 @@ SUITESPARSE_VERSION = 5.10.1 - - ifeq ($(UNAME),Linux) - # add the realtime library, librt, and SuiteSparse/lib -- LDLIBS += -lrt -Wl,-rpath=$(INSTALL_LIB) -+ LDLIBS += -lrt - endif - - #--------------------------------------------------------------------------- -@@ -464,7 +464,7 @@ else - SO_TARGET = $(LIBRARY).$(VERSION).dylib - SO_OPTS += -dynamiclib -compatibility_version $(SO_VERSION) \ - -current_version $(VERSION) \ -- -Wl,-install_name -Wl,@rpath/$(SO_MAIN) \ -+ -Wl,-install_name -Wl,$(INSTALL)/lib/$(SO_MAIN) \ - -shared -undefined dynamic_lookup - # When a Mac *.dylib file is moved, this command is required - # to change its internal name to match its location in the filesystem: diff --git a/build/pkgs/suitesparse/patches/04-cygwin.patch b/build/pkgs/suitesparse/patches/04-cygwin.patch deleted file mode 100644 index f4118f86670..00000000000 --- a/build/pkgs/suitesparse/patches/04-cygwin.patch +++ /dev/null @@ -1,802 +0,0 @@ -diff --git a/AMD/Lib/Makefile b/AMD/Lib/Makefile -index 3b92f6a0..582bef2a 100644 ---- a/AMD/Lib/Makefile -+++ b/AMD/Lib/Makefile -@@ -2,7 +2,7 @@ - # AMD Lib/Makefile - #------------------------------------------------------------------------------- - --LIBRARY = libamd -+LIBRARY = amd - VERSION = 2.4.6 - SO_VERSION = 2 - -@@ -81,19 +81,22 @@ libamdf77.a: $(AMDF77) - #------------------------------------------------------------------------------- - - # install AMD --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/amd.h $(INSTALL_INCLUDE) - $(CP) ../Doc/AMD_UserGuide.pdf $(INSTALL_DOC) - $(CP) ../README.txt $(INSTALL_DOC)/AMD_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/amd.h - chmod 644 $(INSTALL_DOC)/AMD_UserGuide.pdf - chmod 644 $(INSTALL_DOC)/AMD_README.txt -diff --git a/BTF/Lib/Makefile b/BTF/Lib/Makefile -index 85b7a264..6e4e2ec4 100644 ---- a/BTF/Lib/Makefile -+++ b/BTF/Lib/Makefile -@@ -2,7 +2,7 @@ - # BTF Lib/Makefile - #------------------------------------------------------------------------------- - --LIBRARY = libbtf -+LIBRARY = btf - VERSION = 1.2.6 - SO_VERSION = 1 - -@@ -66,18 +66,21 @@ btf_l_strongcomp.o: ../Source/btf_strongcomp.c - #------------------------------------------------------------------------------- - - # install BTF --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/btf.h $(INSTALL_INCLUDE) - $(CP) ../README.txt $(INSTALL_DOC)/BTF_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/btf.h - chmod 644 $(INSTALL_DOC)/BTF_README.txt - -diff --git a/CAMD/Lib/Makefile b/CAMD/Lib/Makefile -index b3ae159e..27cb072a 100644 ---- a/CAMD/Lib/Makefile -+++ b/CAMD/Lib/Makefile -@@ -2,7 +2,7 @@ - # CAMD Lib/Makefile - #------------------------------------------------------------------------------- - --LIBRARY = libcamd -+LIBRARY = camd - VERSION = 2.4.6 - SO_VERSION = 2 - -@@ -62,19 +62,22 @@ $(AR_TARGET): $(OBJ) - #------------------------------------------------------------------------------- - - # install CAMD --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/camd.h $(INSTALL_INCLUDE) - $(CP) ../Doc/CAMD_UserGuide.pdf $(INSTALL_DOC) - $(CP) ../README.txt $(INSTALL_DOC)/CAMD_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/camd.h - chmod 644 $(INSTALL_DOC)/CAMD_UserGuide.pdf - chmod 644 $(INSTALL_DOC)/CAMD_README.txt -diff --git a/CCOLAMD/Lib/Makefile b/CCOLAMD/Lib/Makefile -index 52c52eb9..18190be0 100644 ---- a/CCOLAMD/Lib/Makefile -+++ b/CCOLAMD/Lib/Makefile -@@ -2,7 +2,7 @@ - # CCOLAMD Lib/Makefile - #------------------------------------------------------------------------------- - --LIBRARY = libccolamd -+LIBRARY = ccolamd - VERSION = 2.9.6 - SO_VERSION = 2 - -@@ -49,18 +49,21 @@ distclean: clean - - $(RM) -r $(PURGE) - - # install CCOLAMD --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/ccolamd.h $(INSTALL_INCLUDE) - $(CP) ../README.txt $(INSTALL_DOC)/CCOLAMD_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/ccolamd.h - chmod 644 $(INSTALL_DOC)/CCOLAMD_README.txt - -diff --git a/CHOLMOD/Lib/Makefile b/CHOLMOD/Lib/Makefile -index bc3eab69..d240b4cd 100644 ---- a/CHOLMOD/Lib/Makefile -+++ b/CHOLMOD/Lib/Makefile -@@ -2,7 +2,7 @@ - # CHOLMOD/Lib/Makefile: for compiling the CHOLMOD library - #=============================================================================== - --LIBRARY = libcholmod -+LIBRARY = cholmod - VERSION = 3.0.14 - SO_VERSION = 3 - -@@ -535,20 +535,23 @@ cholmod_l_gpu.o: ../GPU/cholmod_gpu.c - #------------------------------------------------------------------------------- - - # install CHOLMOD --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CXX) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/cholmod*.h $(INSTALL_INCLUDE) - $(RM) $(INSTALL_INCLUDE)/cholmod_internal.h - $(CP) ../Doc/CHOLMOD_UserGuide.pdf $(INSTALL_DOC) - $(CP) ../README.txt $(INSTALL_DOC)/CHOLMOD_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/cholmod*.h - chmod 644 $(INSTALL_DOC)/CHOLMOD_UserGuide.pdf - chmod 644 $(INSTALL_DOC)/CHOLMOD_README.txt -diff --git a/COLAMD/Lib/Makefile b/COLAMD/Lib/Makefile -index 2d0c5aa6..26720b62 100644 ---- a/COLAMD/Lib/Makefile -+++ b/COLAMD/Lib/Makefile -@@ -2,7 +2,7 @@ - # COLAMD Lib/Makefile - #------------------------------------------------------------------------------- - --LIBRARY = libcolamd -+LIBRARY = colamd - VERSION = 2.9.6 - SO_VERSION = 2 - -@@ -49,18 +49,21 @@ distclean: clean - - $(RM) -r $(PURGE) - - # install COLAMD --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/colamd.h $(INSTALL_INCLUDE) - $(CP) ../README.txt $(INSTALL_DOC)/COLAMD_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/colamd.h - chmod 644 $(INSTALL_DOC)/COLAMD_README.txt - -diff --git a/CSparse/Lib/Makefile b/CSparse/Lib/Makefile -index e3f32cec..468f7a47 100644 ---- a/CSparse/Lib/Makefile -+++ b/CSparse/Lib/Makefile -@@ -14,7 +14,7 @@ - # install' in this Makefile only installs a static compiled library in - # CSparse/Lib. It does not install it for system-wide usage. - --LIBRARY = libcsparse -+LIBRARY = csparse - CF = $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -O - - I = -I../Include -diff --git a/CXSparse/Lib/Makefile b/CXSparse/Lib/Makefile -index a21e3607..270b8027 100644 ---- a/CXSparse/Lib/Makefile -+++ b/CXSparse/Lib/Makefile -@@ -2,7 +2,7 @@ - # CXSparse Lib/Makefile - #------------------------------------------------------------------------------- - --LIBRARY = libcxsparse -+LIBRARY = cxsparse - VERSION = 3.2.0 - SO_VERSION = 3 - -@@ -113,18 +113,21 @@ distclean: clean - - $(RM) -r $(PURGE) - - # install CXSparse --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(CS) -+$(INSTALL_SO): $(CS) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/cs.h $(INSTALL_INCLUDE) - $(CP) ../README.txt $(INSTALL_DOC)/CXSPARSE_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/cs.h - chmod 644 $(INSTALL_DOC)/CXSPARSE_README.txt - -diff --git a/CXSparse_newfiles/Lib/Makefile b/CXSparse_newfiles/Lib/Makefile -index a21e3607..270b8027 100644 ---- a/CXSparse_newfiles/Lib/Makefile -+++ b/CXSparse_newfiles/Lib/Makefile -@@ -2,7 +2,7 @@ - # CXSparse Lib/Makefile - #------------------------------------------------------------------------------- - --LIBRARY = libcxsparse -+LIBRARY = cxsparse - VERSION = 3.2.0 - SO_VERSION = 3 - -@@ -113,18 +113,21 @@ distclean: clean - - $(RM) -r $(PURGE) - - # install CXSparse --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(CS) -+$(INSTALL_SO): $(CS) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/cs.h $(INSTALL_INCLUDE) - $(CP) ../README.txt $(INSTALL_DOC)/CXSPARSE_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/cs.h - chmod 644 $(INSTALL_DOC)/CXSPARSE_README.txt - -diff --git a/GPUQREngine/Lib/Makefile b/GPUQREngine/Lib/Makefile -index adf46039..7bb34807 100644 ---- a/GPUQREngine/Lib/Makefile -+++ b/GPUQREngine/Lib/Makefile -@@ -2,7 +2,7 @@ - # GPUQREngine/Lib/Makefile: for compiling the GPUQREngine library - #------------------------------------------------------------------------------- - --LIBRARY = libGPUQREngine -+LIBRARY = GPUQREngine - VERSION = 1.0.5 - SO_VERSION = 1 - -@@ -129,17 +129,20 @@ $(AR_TARGET): $(OBJS) - #------------------------------------------------------------------------------- - - # install GPUQREngine. Note that the include files are not installed. --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJS) -+$(INSTALL_SO): $(OBJS) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CXX) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -- $(CP) ../README.txt $(INSTALL_DOC)/GPUQRENGINE_README.txt - chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif -+ $(CP) ../README.txt $(INSTALL_DOC)/GPUQRENGINE_README.txt - chmod 644 $(INSTALL_DOC)/GPUQRENGINE_README.txt - - # uninstall GPUQREngine -diff --git a/KLU/Lib/Makefile b/KLU/Lib/Makefile -index 2dc62cb4..35e2ed3a 100644 ---- a/KLU/Lib/Makefile -+++ b/KLU/Lib/Makefile -@@ -2,7 +2,7 @@ - # KLU Lib/Makefile - #------------------------------------------------------------------------------- - --LIBRARY = libklu -+LIBRARY = klu - VERSION = 1.3.8 - SO_VERSION = 1 - -@@ -263,19 +263,22 @@ klu_l_memory.o: ../Source/klu_memory.c - #------------------------------------------------------------------------------- - - # install KLU --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/klu.h $(INSTALL_INCLUDE) - $(CP) ../Doc/KLU_UserGuide.pdf $(INSTALL_DOC) - $(CP) ../README.txt $(INSTALL_DOC)/KLU_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/klu.h - chmod 644 $(INSTALL_DOC)/KLU_UserGuide.pdf - chmod 644 $(INSTALL_DOC)/KLU_README.txt -diff --git a/LDL/Lib/Makefile b/LDL/Lib/Makefile -index 604ffa27..da5ecd53 100644 ---- a/LDL/Lib/Makefile -+++ b/LDL/Lib/Makefile -@@ -2,7 +2,7 @@ - # LDL Lib/Makefile - #------------------------------------------------------------------------------- - --LIBRARY = libldl -+LIBRARY = ldl - VERSION = 2.2.6 - SO_VERSION = 2 - -@@ -46,19 +46,22 @@ clean: - - $(RM) -r $(CLEAN) - - # install LDL --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/ldl.h $(INSTALL_INCLUDE) - $(CP) ../Doc/ldl_userguide.pdf $(INSTALL_DOC) - $(CP) ../README.txt $(INSTALL_DOC)/LDL_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/ldl.h - chmod 644 $(INSTALL_DOC)/ldl_userguide.pdf - chmod 644 $(INSTALL_DOC)/LDL_README.txt -diff --git a/RBio/Lib/Makefile b/RBio/Lib/Makefile -index 056715de..4ba42157 100644 ---- a/RBio/Lib/Makefile -+++ b/RBio/Lib/Makefile -@@ -2,7 +2,7 @@ - # RBio/Lib/Makefile: for compiling the RBio library - #=============================================================================== - --LIBRARY = librbio -+LIBRARY = rbio - VERSION = 2.2.6 - SO_VERSION = 2 - -@@ -60,18 +60,21 @@ RBio_i.o: ../Source/RBio.c - #------------------------------------------------------------------------------- - - # install RBio --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/RBio.h $(INSTALL_INCLUDE) - $(CP) ../README.txt $(INSTALL_DOC)/RBIO_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/RBio.h - chmod 644 $(INSTALL_DOC)/RBIO_README.txt - -diff --git a/SLIP_LU/Lib/Makefile b/SLIP_LU/Lib/Makefile -index 8b2221f1..b2153824 100644 ---- a/SLIP_LU/Lib/Makefile -+++ b/SLIP_LU/Lib/Makefile -@@ -8,7 +8,7 @@ - # To run a demo using the library - # cd ../Demo ; make - --LIBRARY = libsliplu -+LIBRARY = sliplu - VERSION = 1.0.2 - SO_VERSION = 1 - -@@ -63,19 +63,22 @@ $(AR_TARGET): $(OBJ) - #------------------------------------------------------------------------------- - - # install SLIP_LU --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/SLIP_LU.h $(INSTALL_INCLUDE) - $(CP) ../Doc/SLIP_LU_UserGuide.pdf $(INSTALL_DOC) - $(CP) ../README.md $(INSTALL_DOC)/SLIP_LU_README.md -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/SLIP_LU.h - chmod 644 $(INSTALL_DOC)/SLIP_LU_UserGuide.pdf - chmod 644 $(INSTALL_DOC)/SLIP_LU_README.md -diff --git a/SPQR/Lib/Makefile b/SPQR/Lib/Makefile -index 06c142ae..10e32007 100644 ---- a/SPQR/Lib/Makefile -+++ b/SPQR/Lib/Makefile -@@ -2,7 +2,7 @@ - # SuiteSparseQR/Lib/Makefile - #=============================================================================== - --LIBRARY = libspqr -+LIBRARY = spqr - VERSION = 2.0.9 - SO_VERSION = 2 - -@@ -242,22 +242,25 @@ spqrgpu_computeFrontStaging.o: ../SPQRGPU/spqrgpu_computeFrontStaging.cpp - #------------------------------------------------------------------------------- - - # install SPQR --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CXX) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/SuiteSparseQR.hpp $(INSTALL_INCLUDE) - $(CP) ../Include/SuiteSparseQR_C.h $(INSTALL_INCLUDE) - $(CP) ../Include/SuiteSparseQR_definitions.h $(INSTALL_INCLUDE) - $(CP) ../Include/spqr.hpp $(INSTALL_INCLUDE) - $(CP) ../Doc/spqr_user_guide.pdf $(INSTALL_DOC) - $(CP) ../README.txt $(INSTALL_DOC)/SPQR_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/SuiteSparseQR.hpp - chmod 644 $(INSTALL_INCLUDE)/SuiteSparseQR_C.h - chmod 644 $(INSTALL_INCLUDE)/SuiteSparseQR_definitions.h -diff --git a/SuiteSparse_GPURuntime/Lib/Makefile b/SuiteSparse_GPURuntime/Lib/Makefile -index 31f536a5..2f6c54d0 100644 ---- a/SuiteSparse_GPURuntime/Lib/Makefile -+++ b/SuiteSparse_GPURuntime/Lib/Makefile -@@ -2,7 +2,7 @@ - # SuiteSparse_GPURuntime/Lib/Makfile - #------------------------------------------------------------------------------- - --LIBRARY = libSuiteSparse_GPURuntime -+LIBRARY = SuiteSparse_GPURuntime - VERSION = 1.0.5 - SO_VERSION = 1 - -@@ -70,17 +70,20 @@ SuiteSparseGPU_Workspace_transfer.o: ../Source/SuiteSparseGPU_Workspace_transfer - #------------------------------------------------------------------------------- - - # install SuiteSparse_GPURuntime (just the library, not the include files) --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJS) -+$(INSTALL_SO): $(OBJS) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CXX) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -- $(CP) ../README.txt $(INSTALL_DOC)/GPURUNTIME_README.txt - chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif -+ $(CP) ../README.txt $(INSTALL_DOC)/GPURUNTIME_README.txt - chmod 644 $(INSTALL_DOC)/GPURUNTIME_README.txt - - # uninstall SuiteSparse_GPURuntime -diff --git a/SuiteSparse_config/Makefile b/SuiteSparse_config/Makefile -index 6a5814d4..e2acc53e 100644 ---- a/SuiteSparse_config/Makefile -+++ b/SuiteSparse_config/Makefile -@@ -6,7 +6,7 @@ SUITESPARSE ?= $(realpath $(CURDIR)/..) - export SUITESPARSE - - # version of SuiteSparse_config is also version of SuiteSparse meta-package --LIBRARY = libsuitesparseconfig -+LIBRARY = suitesparseconfig - VERSION = 5.10.1 - SO_VERSION = 5 - -@@ -44,19 +44,23 @@ clean: - - $(RM) -r $(CLEAN) - - # install SuiteSparse_config --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+# Likely redundant with the above but not on Cygwin -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -- $(CP) SuiteSparse_config.h $(INSTALL_INCLUDE) -- $(CP) README.txt $(INSTALL_DOC)/SUITESPARSECONFIG_README.txt - chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 755 $(INSTALL_LIB)/$(SO_PLAIN) -+endif -+ $(CP) SuiteSparse_config.h $(INSTALL_INCLUDE) -+ $(CP) README.txt $(INSTALL_DOC)/SUITESPARSECONFIG_README.txt - chmod 644 $(INSTALL_INCLUDE)/SuiteSparse_config.h - chmod 644 $(INSTALL_DOC)/SUITESPARSECONFIG_README.txt - -diff --git a/SuiteSparse_config/SuiteSparse_config.mk b/SuiteSparse_config/SuiteSparse_config.mk -index 61f0076e..5caa89dd 100644 ---- a/SuiteSparse_config/SuiteSparse_config.mk -+++ b/SuiteSparse_config/SuiteSparse_config.mk -@@ -16,14 +16,14 @@ SUITESPARSE_VERSION = 5.10.1 - # To disable these auto configurations, use 'make UNAME=custom' - - ifndef UNAME -- ifeq ($(OS),Windows_NT) -- # Cygwin Make on Windows has an $(OS) variable, but not uname. -- # Note that this option is untested. -- UNAME = Windows -- else -- # Linux and Darwin (Mac OSX) have been tested. -- UNAME := $(shell uname) -- endif -+ # Linux and Darwin (Mac OSX) have been tested. -+ UNAME := $(shell uname) -+ endif -+ -+ # On Cygwin we'll typically have UNAME=CYGWIN but just normalize -+ # to "CYGWIN" -+ ifeq ($(findstring CYGWIN,$(UNAME)),CYGWIN) -+ UNAME := Cygwin - endif - - #=============================================================================== -@@ -170,6 +170,11 @@ SUITESPARSE_VERSION = 5.10.1 - # It places its shared *.so libraries in SuiteSparse/lib. - # Linux also requires the -lrt library (see below) - LDLIBS ?= -lm -+ # Note: Because suitesparse doesn't really do install staging properly -+ # (it just outputs final build artifacts directly to their install paths) -+ # we must add that path to our linker flags in order to link properly -+ # against built libraries; it might be better to fix the whole build -+ # system though). - LDFLAGS += -L$(INSTALL_LIB) - - # NOTE: Use of the Intel MKL BLAS is strongly recommended. The OpenBLAS can -@@ -447,21 +452,23 @@ SUITESPARSE_VERSION = 5.10.1 - - SO_OPTS = $(LDFLAGS) - --ifeq ($(UNAME),Windows) -- # Cygwin Make on Windows (untested) -- AR_TARGET = $(LIBRARY).lib -- SO_PLAIN = $(LIBRARY).dll -- SO_MAIN = $(LIBRARY).$(SO_VERSION).dll -- SO_TARGET = $(LIBRARY).$(VERSION).dll -- SO_INSTALL_NAME = echo -+ifeq ($(UNAME),Cygwin) -+ # Cygwin Make on Windows -+ AR_TARGET = lib$(LIBRARY).a -+ SO_TARGET = cyg$(LIBRARY)-$(SO_VERSION).dll -+ IMPLIB = lib$(LIBRARY).dll.a -+ SO_OPTS += -shared -Wl,--no-undefined -Wl,--out-implib -Wl,$(INSTALL_LIB)/$(IMPLIB) -+ INSTALL_DLL := $(DESTDIR)$(INSTALL)/bin -+ INSTALL_SO = $(INSTALL_DLL)/$(SO_TARGET) - else - # Mac or Linux/Unix -- AR_TARGET = $(LIBRARY).a -+ AR_TARGET = lib$(LIBRARY).a -+ INSTALL_SO = $(INSTALL_LIB)/$(SO_TARGET) - ifeq ($(UNAME),Darwin) - # Mac -- SO_PLAIN = $(LIBRARY).dylib -- SO_MAIN = $(LIBRARY).$(SO_VERSION).dylib -- SO_TARGET = $(LIBRARY).$(VERSION).dylib -+ SO_PLAIN = lib$(LIBRARY).dylib -+ SO_MAIN = lib$(LIBRARY).$(SO_VERSION).dylib -+ SO_TARGET = lib$(LIBRARY).$(VERSION).dylib - SO_OPTS += -dynamiclib -compatibility_version $(SO_VERSION) \ - -current_version $(VERSION) \ - -Wl,-install_name -Wl,$(INSTALL)/lib/$(SO_MAIN) \ -@@ -471,9 +478,9 @@ else - SO_INSTALL_NAME = install_name_tool -id - else - # Linux and other variants of Unix -- SO_PLAIN = $(LIBRARY).so -- SO_MAIN = $(LIBRARY).so.$(SO_VERSION) -- SO_TARGET = $(LIBRARY).so.$(VERSION) -+ SO_PLAIN = lib$(LIBRARY).so -+ SO_MAIN = lib$(LIBRARY).so.$(SO_VERSION) -+ SO_TARGET = lib$(LIBRARY).so.$(VERSION) - SO_OPTS += -shared -Wl,-soname -Wl,$(SO_MAIN) -Wl,--no-undefined - # Linux/Unix *.so files can be moved without modification: - SO_INSTALL_NAME = echo -diff --git a/SuiteSparse_config/xerbla/Makefile b/SuiteSparse_config/xerbla/Makefile -index db68a2ea..c59820c2 100644 ---- a/SuiteSparse_config/xerbla/Makefile -+++ b/SuiteSparse_config/xerbla/Makefile -@@ -16,9 +16,9 @@ library: - all: library - - ifeq ($(USE_FORTRAN),0) -- LIBRARY = libcerbla -+ LIBRARY = cerbla - else -- LIBRARY = libxerbla -+ LIBRARY = xerbla - endif - - include ../SuiteSparse_config.mk -@@ -44,19 +44,22 @@ $(AR_TARGET): $(DEPENDS) - - $(RM) xerbla.o - - # install libcerbla / libxerbla --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(DEPENDS) -+$(INSTALL_SO): $(DEPENDS) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(COMPILE) - $(CC) $(SO_OPTS) xerbla.o -o $@ - - $(RM) xerbla.o -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -- $(CP) xerbla.h $(INSTALL_INCLUDE) - chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif -+ $(CP) xerbla.h $(INSTALL_INCLUDE) - chmod 644 $(INSTALL_INCLUDE)/xerbla.h - - # uninstall libcerbla / libxerbla -diff --git a/UMFPACK/Lib/Makefile b/UMFPACK/Lib/Makefile -index 78436de1..0f291068 100644 ---- a/UMFPACK/Lib/Makefile -+++ b/UMFPACK/Lib/Makefile -@@ -2,7 +2,7 @@ - # UMFPACK Makefile for compiling on Unix systems - #------------------------------------------------------------------------------- - --LIBRARY = libumfpack -+LIBRARY = umfpack - VERSION = 5.7.9 - SO_VERSION = 5 - -@@ -288,20 +288,23 @@ clean: - - #------------------------------------------------------------------------------- - # install UMFPACK --install: $(AR_TARGET) $(INSTALL_LIB)/$(SO_TARGET) -+install: $(AR_TARGET) $(INSTALL_SO) - --$(INSTALL_LIB)/$(SO_TARGET): $(OBJ) -+$(INSTALL_SO): $(OBJ) - @mkdir -p $(INSTALL_LIB) -+ @mkdir -p $(dir $(INSTALL_SO)) - @mkdir -p $(INSTALL_INCLUDE) - @mkdir -p $(INSTALL_DOC) - $(CC) $(SO_OPTS) $^ -o $@ $(LDLIBS) -+ifneq ($(UNAME),Cygwin) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_PLAIN) ) - ( cd $(INSTALL_LIB) ; ln -sf $(SO_TARGET) $(SO_MAIN) ) -+ chmod 755 $(INSTALL_LIB)/$(SO_TARGET) -+endif - $(CP) ../Include/umfpack*.h $(INSTALL_INCLUDE) - $(CP) ../Doc/UMFPACK_UserGuide.pdf $(INSTALL_DOC) - $(CP) ../Doc/UMFPACK_QuickStart.pdf $(INSTALL_DOC) - $(CP) ../README.txt $(INSTALL_DOC)/UMFPACK_README.txt -- chmod 755 $(INSTALL_LIB)/$(SO_TARGET) - chmod 644 $(INSTALL_INCLUDE)/umfpack*.h - chmod 644 $(INSTALL_DOC)/UMFPACK_UserGuide.pdf - chmod 644 $(INSTALL_DOC)/UMFPACK_QuickStart.pdf diff --git a/build/pkgs/suitesparse/spkg-install.in b/build/pkgs/suitesparse/spkg-install.in index b6944a409ba..ab5253d2e77 100644 --- a/build/pkgs/suitesparse/spkg-install.in +++ b/build/pkgs/suitesparse/spkg-install.in @@ -1,14 +1,18 @@ -# -*- shell-script -*- cd src -export CC="${CC-gcc} -std=c99" - -echo "print configuration" -$MAKE MY_METIS_LIB=none CHOLMOD_CONFIG=-DNPARTITION \ - BLAS="$(pkg-config --libs blas)" LAPACK="$(pkg-config --libs lapack)" \ - INSTALL="$SAGE_LOCAL" DESTDIR="$SAGE_DESTDIR" config -# build and install -$MAKE MY_METIS_LIB=none CHOLMOD_CONFIG=-DNPARTITION \ - BLAS="$(pkg-config --libs blas)" LAPACK="$(pkg-config --libs lapack)" \ - INSTALL="$SAGE_LOCAL" DESTDIR="$SAGE_DESTDIR" install +echo "Configuring suitesparse" +# * NSTATIC suitesparse defines some negative options like this one "NSTATIC=ON" means no static libraries. +# 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 +# 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. +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" +sdh_make_install diff --git a/build/pkgs/sympy/checksums.ini b/build/pkgs/sympy/checksums.ini index 30e67c20de6..17e31ea9f3d 100644 --- a/build/pkgs/sympy/checksums.ini +++ b/build/pkgs/sympy/checksums.ini @@ -1,4 +1,4 @@ tarball=sympy-VERSION-py3-none-any.whl -sha1=80fa00ab605295d61992ca3faa76771a62944527 -sha256=9b2cbc7f1a640289430e13d2a56f02f867a1da0190f2f99d8968c2f74da0e515 +sha1=e34c28a2aa2b677efe2f1b7cefe275e20d2e652c +sha256=c51d75517712f1aed280d4ce58506a4a88d635d6b5dd48b39102a7ae1f3fcfe9 upstream_url=https://pypi.io/packages/py3/s/sympy/sympy-VERSION-py3-none-any.whl diff --git a/build/pkgs/sympy/package-version.txt b/build/pkgs/sympy/package-version.txt index f8f4f03b3dc..61ce01b3011 100644 --- a/build/pkgs/sympy/package-version.txt +++ b/build/pkgs/sympy/package-version.txt @@ -1 +1 @@ -1.12.1 +1.13.2 diff --git a/build/pkgs/tachyon/package-version.txt b/build/pkgs/tachyon/package-version.txt index 2d666706df4..fcdf7816d66 100644 --- a/build/pkgs/tachyon/package-version.txt +++ b/build/pkgs/tachyon/package-version.txt @@ -1 +1 @@ -0.99.5 +0.99.5.p0 diff --git a/build/pkgs/tachyon/patches/Make-config.patch b/build/pkgs/tachyon/patches/Make-config.patch deleted file mode 100644 index 49462387134..00000000000 --- a/build/pkgs/tachyon/patches/Make-config.patch +++ /dev/null @@ -1,56 +0,0 @@ ---- a/unix/Make-config 2011-03-13 11:01:07.000000000 +0000 -+++ b/unix/Make-config 2016-07-04 15:29:57.982923000 +0000 -@@ -122,29 +122,25 @@ - # PNG support configuration: - # PNGINC is the directory where your libpng and libz include files - # are made available. PNGLIB is the directory where your libpng --# and libz libraries are made available. -+# and libz libraries are made available. - # - # LibPNG can be downlaoded from: - # http://www.libpng.org/ - ########################################################################## - # Uncomment the following lines to disable PNG support --USEPNG= --PNGINC= --PNGLIB= -+USEPNG= -DUSEPNG -+PNGINC= -I$(SAGE_LOCAL)/include -+PNGLIB= -L$(SAGE_LOCAL)/lib -lpng -lz - --# Uncomment the following lines to enable PNG support --#USEPNG= -DUSEPNG --#PNGINC= -I/usr/local/include --#PNGLIB= -L/usr/local/lib -lpng -lz - - - ########################################################################## --# OMF (Open Media Framework) configuration -+# OMF (Open Media Framework) configuration - # Requires OMF Toolkit version 2.x - ########################################################################## - #OMFDIR = /disk5/users/johns/graphics/OMFKT202/Toolkit - #OMFINC = -I$(OMFDIR)/include -I$(OMFDIR)/kitomfi -I$(OMFDIR)/bento -I$(OMFDIR)/jpeg -I$(OMFDIR)/portinc -I$(OMFDIR)/avidjpg --#OMFLIB = -L$(OMFDIR)/DO_sun5_opt/usr/lib -lAJPG -lOMFI -lbento -ljpeg -+#OMFLIB = -L$(OMFDIR)/DO_sun5_opt/usr/lib -lAJPG -lOMFI -lbento -ljpeg - #OMFDEF = -DUSEOMF - - -@@ -159,7 +155,7 @@ - - ########################################################################## - # Spaceball I/O library configuration: --# A spaceball can used for fly-throughs of scenes when running on -+# A spaceball can used for fly-throughs of scenes when running on - # a fast multiprocessor, parallel machine, or PC cluster. - # - # Libsball can be downloaded from: -@@ -172,7 +168,7 @@ - - ########################################################################## - # MGF Materials and Geometry Format scene parser library --# If enabled, this allows Tachyon to read MGF scene files using -+# If enabled, this allows Tachyon to read MGF scene files using - # compiled-in MGF scene parser code. - ########################################################################## - #MGFDIR=../../libmgf diff --git a/build/pkgs/tachyon/spkg-install.in b/build/pkgs/tachyon/spkg-install.in index dc1ebb49740..6a68d95688c 100644 --- a/build/pkgs/tachyon/spkg-install.in +++ b/build/pkgs/tachyon/spkg-install.in @@ -52,7 +52,8 @@ if [ -z "$TARGET" ]; then sdh_die "Error: Sorry, your platform isn't supported by Tachyon and/or Sage. Exiting..." fi -sdh_make "$TARGET" +# The Makefile ignores LDFLAGS; we include it here so that rpath is set on Linux +sdh_make "$TARGET" USEPNG=-DUSEPNG PNGLIB="$LDFLAGS -lpng -lz" echo "Installing the Tachyon binary..." cd "$CUR" diff --git a/build/pkgs/valgrind/SPKG.rst b/build/pkgs/valgrind/SPKG.rst index 99a7ab96ed2..251e871a1a8 100644 --- a/build/pkgs/valgrind/SPKG.rst +++ b/build/pkgs/valgrind/SPKG.rst @@ -4,9 +4,6 @@ valgrind: Memory error detector, call graph generator, runtime profiler Description ----------- -This is an optional spkg. It supports Linux on x86, x86-64, ppc, ppc64 -and ARM as well as Darwin (Mac OS X 10.5 and 10.6) on x86 and x86-64. - Valgrind is an instrumentation framework for building dynamic analysis tools. There are Valgrind tools that can automatically detect many memory management and threading bugs, and profile your programs in @@ -18,10 +15,7 @@ branch-prediction profiler, a call-graph generating cache and branch-prediction profiler, and a heap profiler. It also includes three experimental tools: a heap/stack/global array overrun detector, a second heap profiler that examines how heap blocks are used, and a SimPoint -basic block vector generator. It runs on the following platforms: -X86/Linux, AMD64/Linux, ARM/Linux, PPC32/Linux, PPC64/Linux, -S390X/Linux, ARM/Android (2.3.x), X86/Darwin and AMD64/Darwin (Mac OS X -10.6 and 10.7). +basic block vector generator. License ------- @@ -35,20 +29,3 @@ Upstream Contact - http://www.valgrind.org/ - valgrind-user, valgrind-devel mailing lists - -Dependencies ------------- - -- None - - -Special Build Instructions --------------------------- - -- To build on OS X, you need to use Apple's compiler. FSF GCC is - unsupported. - -Patches -~~~~~~~ - -- None. diff --git a/build/pkgs/valgrind/checksums.ini b/build/pkgs/valgrind/checksums.ini deleted file mode 100644 index 3ffe6ab866a..00000000000 --- a/build/pkgs/valgrind/checksums.ini +++ /dev/null @@ -1,3 +0,0 @@ -tarball=valgrind-VERSION.tar.bz2 -sha1=182afd405b92ddb6f52c6729e848eacf4b1daf46 -sha256=037c11bfefd477cc6e9ebe8f193bb237fe397f7ce791b4a4ce3fa1c6a520baa5 diff --git a/build/pkgs/valgrind/dependencies b/build/pkgs/valgrind/dependencies deleted file mode 100644 index 4f00de20375..00000000000 --- a/build/pkgs/valgrind/dependencies +++ /dev/null @@ -1,4 +0,0 @@ -# no dependencies - ----------- -All lines of this file are ignored except the first. diff --git a/build/pkgs/valgrind/package-version.txt b/build/pkgs/valgrind/package-version.txt deleted file mode 100644 index f982feb41bd..00000000000 --- a/build/pkgs/valgrind/package-version.txt +++ /dev/null @@ -1 +0,0 @@ -3.14.0 diff --git a/build/pkgs/valgrind/spkg-install.in b/build/pkgs/valgrind/spkg-install.in deleted file mode 100644 index 2aa2762a7ed..00000000000 --- a/build/pkgs/valgrind/spkg-install.in +++ /dev/null @@ -1,20 +0,0 @@ -cd src - -./configure --prefix=$SAGE_LOCAL -if [ $? -ne 0 ]; then - echo >&2 "Error configuring Valgrind" - exit 1 -fi - -$MAKE -if [ $? -ne 0 ]; then - echo >&2 "Error building Valgrind" - exit 1 -fi - -$MAKE install -if [ $? -ne 0 ]; then - echo >&2 "Error installing Valgrind" - exit 1 -fi - diff --git a/build/pkgs/valgrind/type b/build/pkgs/valgrind/type index 9839eb20815..134d9bc32d5 100644 --- a/build/pkgs/valgrind/type +++ b/build/pkgs/valgrind/type @@ -1 +1 @@ -experimental +optional diff --git a/configure.ac b/configure.ac index df6a785251e..58adf54f78f 100644 --- a/configure.ac +++ b/configure.ac @@ -450,7 +450,7 @@ AC_ARG_ENABLE([cvxopt], AC_ARG_ENABLE([notebook], AS_HELP_STRING([--disable-notebook], [disable build of the Jupyter notebook and related packages]), [ - for pkg in notebook nbconvert beautifulsoup4 sagenb_export nbformat nbclient terminado send2trash prometheus_client mistune pandocfilters bleach defusedxml jsonschema jupyter_jsmol argon2_cffi argon2_cffi_bindings webencodings tinycss2 ipympl soupsieve fastjsonschema anyio arrow async_lru fqdn isoduration json5 jsonpointer jsonschema_specifications jupyter_events jupyter_lsp jupyter_server jupyter_server_terminals jupyterlab jupyterlab_server jupyterlab_pygments jupyterlab_mathjax2 notebook_shim overrides python_json_logger pyyaml referencing rfc3339_validator rfc3986_validator sniffio types_python_dateutil uri_template webcolors websocket_client; do + for pkg in notebook nbconvert beautifulsoup4 sagenb_export nbformat nbclient terminado send2trash prometheus_client mistune pandocfilters bleach defusedxml jsonschema jupyter_jsmol argon2_cffi argon2_cffi_bindings webencodings tinycss2 ipympl soupsieve fastjsonschema anyio arrow async_lru fqdn isoduration json5 jsonpointer jsonschema_specifications jupyter_events jupyter_lsp jupyter_server jupyter_server_terminals jupyterlab jupyterlab_server jupyterlab_pygments jupyterlab_mathjax2 jupyter_sphinx notebook_shim overrides python_json_logger pyyaml referencing rfc3339_validator rfc3986_validator sniffio types_python_dateutil uri_template webcolors websocket_client; do AS_VAR_SET([SAGE_ENABLE_$pkg], [$enableval]) done ]) diff --git a/constraints_pkgs.txt b/constraints_pkgs.txt new file mode 100644 index 00000000000..9e4fe969fbc --- /dev/null +++ b/constraints_pkgs.txt @@ -0,0 +1,39 @@ +# This "constraints file" can be used for forcing pip +# (and any tools that delegate to pip, such as pypa/build) +# to install the distribution packages included in +# the SageMath monorepository only from their source trees +# in SAGE_ROOT/pkgs/ instead of from PyPI. +# +# Example: Building a sagemath-standard wheel +# +# [alice@localhost sage]$ ./bootstrap +# [alice@localhost sage]$ ./configure +# [alice@localhost sage]$ export MAKE="make -j16" SAGE_NUM_THREADS=16 +# [alice@localhost sage]$ make all-sage-local +# [alice@localhost sage]$ export PIP_CONSTRAINT="$(pwd)/constraints_pkgs.txt" +# [alice@localhost sage]$ ./sage -sh -c 'python3 -m build -v -v pkgs/sagemath-standard' +# +# Non-example: Installing the built wheel using the same +# constraints file will fail because sagemath-standard is one +# of the distribution packages listed below. It will conflict +# with the built wheel for sagemath-standard! +# Use "pkgs/sagemath-standard/constraints_pkgs.txt" instead. + +# Reference on the format: +# https://pip.pypa.io/en/stable/user_guide/#constraints-files +# +sage_conf @ file://${SAGE_ROOT}/pkgs/sage-conf +sage_docbuild @ file://${SAGE_ROOT}/pkgs/sage-docbuild +sage_setup @ file://${SAGE_ROOT}/pkgs/sage-setup +sage_sws2rst @ file://${SAGE_ROOT}/pkgs/sage-sws2rst +sagemath-bliss @ file://${SAGE_ROOT}/pkgs/sagemath-bliss +sagemath-categories @ file://${SAGE_ROOT}/pkgs/sagemath-categories +sagemath-coxeter3 @ file://${SAGE_ROOT}/pkgs/sagemath-coxeter3 +sagemath-environment @ file://${SAGE_ROOT}/pkgs/sagemath-environment +sagemath-mcqd @ file://${SAGE_ROOT}/pkgs/sagemath-mcqd +sagemath-meataxe @ file://${SAGE_ROOT}/pkgs/sagemath-meataxe +sagemath-objects @ file://${SAGE_ROOT}/pkgs/sagemath-objects +sagemath-repl @ file://${SAGE_ROOT}/pkgs/sagemath-repl +sagemath-sirocco @ file://${SAGE_ROOT}/pkgs/sagemath-sirocco +sagemath-standard @ file://${SAGE_ROOT}/pkgs/sagemath-standard +sagemath-tdlib @ file://${SAGE_ROOT}/pkgs/sagemath-tdlib diff --git a/docker/README.md b/docker/README.md index 190793c202d..404cf973490 100644 --- a/docker/README.md +++ b/docker/README.md @@ -49,7 +49,7 @@ Have a look at `.gitlab-ci.yml` if you want to setup GitLab CI for your own fork # Report bugs and issues -Please tell us of any bugs or omissions at our [Issue Tracker](https://trac.sagemath.org) or contact us through the [sage-support](https://groups.google.com/forum/#!forum/sage-support) or the [sage-devel](https://groups.google.com/forum/#!forum/sage-devel) mailing lists. +Please tell us of any bugs or omissions at our [Issue Tracker](https://github.com/sagemath/sage/issues) or contact us through the [sage-support](https://groups.google.com/forum/#!forum/sage-support) or the [sage-devel](https://groups.google.com/forum/#!forum/sage-devel) mailing lists. # License diff --git a/pkgs/sage-conf/VERSION.txt b/pkgs/sage-conf/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sage-conf/VERSION.txt +++ b/pkgs/sage-conf/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sage-conf_conda/VERSION.txt b/pkgs/sage-conf_conda/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sage-conf_conda/VERSION.txt +++ b/pkgs/sage-conf_conda/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sage-conf_pypi/VERSION.txt b/pkgs/sage-conf_pypi/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sage-conf_pypi/VERSION.txt +++ b/pkgs/sage-conf_pypi/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sage-docbuild/VERSION.txt b/pkgs/sage-docbuild/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sage-docbuild/VERSION.txt +++ b/pkgs/sage-docbuild/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sage-setup/VERSION.txt b/pkgs/sage-setup/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sage-setup/VERSION.txt +++ b/pkgs/sage-setup/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sage-sws2rst/VERSION.txt b/pkgs/sage-sws2rst/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sage-sws2rst/VERSION.txt +++ b/pkgs/sage-sws2rst/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sagemath-bliss/VERSION.txt b/pkgs/sagemath-bliss/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sagemath-bliss/VERSION.txt +++ b/pkgs/sagemath-bliss/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sagemath-categories/VERSION.txt b/pkgs/sagemath-categories/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sagemath-categories/VERSION.txt +++ b/pkgs/sagemath-categories/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sagemath-coxeter3/VERSION.txt b/pkgs/sagemath-coxeter3/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sagemath-coxeter3/VERSION.txt +++ b/pkgs/sagemath-coxeter3/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sagemath-environment/VERSION.txt b/pkgs/sagemath-environment/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sagemath-environment/VERSION.txt +++ b/pkgs/sagemath-environment/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sagemath-mcqd/VERSION.txt b/pkgs/sagemath-mcqd/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sagemath-mcqd/VERSION.txt +++ b/pkgs/sagemath-mcqd/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sagemath-meataxe/VERSION.txt b/pkgs/sagemath-meataxe/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sagemath-meataxe/VERSION.txt +++ b/pkgs/sagemath-meataxe/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sagemath-objects/VERSION.txt b/pkgs/sagemath-objects/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sagemath-objects/VERSION.txt +++ b/pkgs/sagemath-objects/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sagemath-repl/VERSION.txt b/pkgs/sagemath-repl/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sagemath-repl/VERSION.txt +++ b/pkgs/sagemath-repl/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sagemath-sirocco/VERSION.txt b/pkgs/sagemath-sirocco/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sagemath-sirocco/VERSION.txt +++ b/pkgs/sagemath-sirocco/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/pkgs/sagemath-standard/README.rst b/pkgs/sagemath-standard/README.rst index f429984aa4c..b5d44eb1f9b 100644 --- a/pkgs/sagemath-standard/README.rst +++ b/pkgs/sagemath-standard/README.rst @@ -8,24 +8,26 @@ About SageMath "Creating a Viable Open Source Alternative to Magma, Maple, Mathematica, and MATLAB" - Copyright (C) 2005-2020 The Sage Development Team + Copyright (C) 2005-2024 The Sage Development Team https://www.sagemath.org SageMath fully supports all major Linux distributions, recent versions of macOS, and Windows (Windows Subsystem for Linux). -The traditional and recommended way to install SageMath is from source via Sage-the-distribution (https://www.sagemath.org/download-source.html). Sage-the-distribution first builds a large number of open source packages from source (unless it finds suitable versions installed in the system) and then installs the Sage Library (sagelib, implemented in Python and Cython). +See https://doc.sagemath.org/html/en/installation/index.html +for general installation instructions. -About this experimental pip-installable source distribution ------------------------------------------------------------ +About this pip-installable distribution package +----------------------------------------------- -This pip-installable source distribution `sagemath-standard` is an experimental distribution of the Sage Library. Use at your own risk. +This pip-installable source distribution `sagemath-standard` is a +distribution of the Sage Library. Building `sagemath-standard` has a large number of system packages as prerequisites. See https://doc.sagemath.org/html/en/installation/source.html#linux-recommended-installation for partial lists for various systems. -The connection to the system environment is facilitated through the https://pypi.org/project/sage-conf/ distribution package. +The connection to the system environment is facilitated through the https://pypi.org/project/sage-conf/ distribution package; for step-by-step installation instructions, see https://github.com/sagemath/sage/blob/develop/README.md#alternative-installation-using-pypi A modularization effort is in progress with the goal of making it possible to install parts of the Sage Library with fewer prerequisites. https://github.com/sagemath/sage/issues/29705 diff --git a/pkgs/sagemath-standard/constraints_pkgs.txt b/pkgs/sagemath-standard/constraints_pkgs.txt new file mode 100644 index 00000000000..139aae58f86 --- /dev/null +++ b/pkgs/sagemath-standard/constraints_pkgs.txt @@ -0,0 +1,21 @@ +# This "constraints file" can be used for forcing pip +# (and any tools that delegate to pip, such as pypa/build) +# to install the dependencies of sagemath-standard that are +# distribution packages included in the SageMath monorepository +# only from their source trees in SAGE_ROOT/pkgs/ +# instead of from PyPI. +# +# Example: +# +# [alice@localhost sage]$ ./bootstrap +# [alice@localhost sage]$ ./configure +# [alice@localhost sage]$ export MAKE="make -j16" SAGE_NUM_THREADS=16 +# [alice@localhost sage]$ make all-sage-local +# [alice@localhost sage]$ export PIP_CONSTRAINT="$(pwd)/pkgs/sagemath-standard/constraints_pkgs.txt" +# [alice@localhost sage]$ ./sage -sh -c 'python3 -m build -v -v pkgs/sagemath-standard' +# +# Reference on the format: +# https://pip.pypa.io/en/stable/user_guide/#constraints-files +# +sage_conf @ file://${SAGE_ROOT}/pkgs/sage-conf +sage_setup @ file://${SAGE_ROOT}/pkgs/sage-setup diff --git a/pkgs/sagemath-standard/tox.ini b/pkgs/sagemath-standard/tox.ini index c197f49d9be..0ac97f8a021 100644 --- a/pkgs/sagemath-standard/tox.ini +++ b/pkgs/sagemath-standard/tox.ini @@ -31,6 +31,19 @@ envlist = # # ./sage -sh -c '(cd pkgs/sagemath-standard && tox -v -v -v -e sagepython-sagewheels-nopypi)' # + # Build and test without using the concrete dependencies specified by requirements.txt, + # using the dependencies declared in pyproject.toml and setup.cfg (install-requires) only: + # Install the distribution packages included in the SageMath monorepository only from + # their source trees in SAGE_ROOT/pkgs/ (not from PyPI). + # + # ./sage -sh -c '(cd pkgs/sagemath-standard && tox -v -v -v -e sagepython-constraints_pkgs-norequirements)' + # + # Build dependencies according to requirements.txt (all versions fixed). + # Install the distribution packages included in the SageMath monorepository only from + # their source trees in SAGE_ROOT/pkgs/ (not from PyPI). + # + # ./sage -sh -c '(cd pkgs/sagemath-standard && tox -v -v -v -e sagepython-constraints_pkgs)' + # # EXPERIMENTAL ENVIRONMENTS: # # Build dependencies according to requirements.txt (all versions fixed). @@ -80,6 +93,8 @@ passenv = MAKEFLAGS # SAGE_VENV only for referring to the basepython or finding the wheels sagepython, sagewheels: SAGE_VENV + # Used as an environment variable in constraints_pkgs.txt + constraints_pkgs: SAGE_ROOT # Location of the wheels sagewheels: SAGE_SPKG_WHEELS @@ -88,6 +103,7 @@ setenv = # apply both to the installation of the dependencies and of the package sagewheels: PIP_FIND_LINKS=file://{env:SAGE_SPKG_WHEELS:{env:SAGE_VENV:{toxinidir}/../../../../venv}/var/lib/sage/wheels} nopypi: PIP_NO_INDEX=true + constraints_pkgs: PIP_CONSTRAINT={toxinidir}/constraints_pkgs.txt # No build isolation for PEP 517 packages - use what is already in the environment # Note that this pip env "NO" variable uses inverted logic: # PIP_NO_BUILD_ISOLATION=False means don't use build isolation. @@ -153,6 +169,17 @@ setenv = {[pkgenv]setenv} basepython = {env:SAGE_VENV}/bin/python3 +[testenv:.pkg-sagepython-constraints_pkgs] +passenv = {[pkgenv]passenv} + SAGE_VENV + # Location of constraints_pkgs.txt + SAGE_ROOT + +setenv = {[pkgenv]setenv} + PIP_CONSTRAINT={env:SAGE_ROOT}/constraints_pkgs.txt + +basepython = {env:SAGE_VENV}/bin/python3 + [testenv:sagepython] basepython = {env:SAGE_VENV}/bin/python3 package_env = .pkg-sagepython @@ -177,6 +204,14 @@ package_env = .pkg-sagepython basepython = {env:SAGE_VENV}/bin/python3 package_env = .pkg-sagepython +[testenv:sagepython-constraints_pkgs] +basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-constraints_pkgs + +[testenv:sagepython-constraints_pkgs-norequirements] +basepython = {env:SAGE_VENV}/bin/python3 +package_env = .pkg-sagepython-constraints_pkgs + [testenv:sagepython-sagewheels-nopypi-norequirements] basepython = {env:SAGE_VENV}/bin/python3 diff --git a/pkgs/sagemath-tdlib/VERSION.txt b/pkgs/sagemath-tdlib/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/pkgs/sagemath-tdlib/VERSION.txt +++ b/pkgs/sagemath-tdlib/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/src/VERSION.txt b/src/VERSION.txt index c4777d00d87..674fddc2fcd 100644 --- a/src/VERSION.txt +++ b/src/VERSION.txt @@ -1 +1 @@ -10.5.beta2 +10.5.beta3 diff --git a/src/bin/sage-version.sh b/src/bin/sage-version.sh index 92d914d9c6e..0ee1864e8ee 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.beta2' -SAGE_RELEASE_DATE='2024-08-10' -SAGE_VERSION_BANNER='SageMath version 10.5.beta2, Release Date: 2024-08-10' +SAGE_VERSION='10.5.beta3' +SAGE_RELEASE_DATE='2024-09-03' +SAGE_VERSION_BANNER='SageMath version 10.5.beta3, Release Date: 2024-09-03' diff --git a/src/doc/ca/intro/conf.py b/src/doc/ca/intro/conf.py index 71d81dcdbf3..877eba7eeb7 100644 --- a/src/doc/ca/intro/conf.py +++ b/src/doc/ca/intro/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/de/a_tour_of_sage/conf.py b/src/doc/de/a_tour_of_sage/conf.py index 71fc7ef9012..fb960f06ffd 100644 --- a/src/doc/de/a_tour_of_sage/conf.py +++ b/src/doc/de/a_tour_of_sage/conf.py @@ -15,6 +15,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/de/thematische_anleitungen/conf.py b/src/doc/de/thematische_anleitungen/conf.py index 337f1a98c68..b8ec2573f90 100644 --- a/src/doc/de/thematische_anleitungen/conf.py +++ b/src/doc/de/thematische_anleitungen/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/de/tutorial/conf.py b/src/doc/de/tutorial/conf.py index 399a915e9f4..da1c19e0ffc 100644 --- a/src/doc/de/tutorial/conf.py +++ b/src/doc/de/tutorial/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/el/a_tour_of_sage/conf.py b/src/doc/el/a_tour_of_sage/conf.py index 5548c31525e..ff4e9436313 100644 --- a/src/doc/el/a_tour_of_sage/conf.py +++ b/src/doc/el/a_tour_of_sage/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/a_tour_of_sage/conf.py b/src/doc/en/a_tour_of_sage/conf.py index 7cf31297409..689eed59af3 100644 --- a/src/doc/en/a_tour_of_sage/conf.py +++ b/src/doc/en/a_tour_of_sage/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/constructions/conf.py b/src/doc/en/constructions/conf.py index b6bbbbaab3b..a28d011781c 100644 --- a/src/doc/en/constructions/conf.py +++ b/src/doc/en/constructions/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/developer/conf.py b/src/doc/en/developer/conf.py index e8877d61770..6e80447f4c7 100644 --- a/src/doc/en/developer/conf.py +++ b/src/doc/en/developer/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/developer/index.rst b/src/doc/en/developer/index.rst index 7dc5cefd440..bc4f982ffe0 100644 --- a/src/doc/en/developer/index.rst +++ b/src/doc/en/developer/index.rst @@ -4,14 +4,6 @@ Welcome to Sage Developer Guide =============================== -.. NOTE:: - - Sage development moved to `GitHub `_ in - February 2023, from `the Sage Trac server `_, - which had been the center of Sage development for a long time. After the - transition, this guide was updated accordingly. However, the legacy is - still with us in many aspects of the current Sage development. - Everybody who uses Sage is encouraged to contribute something back to Sage at some point. You could: diff --git a/src/doc/en/developer/portability_platform_table.rst b/src/doc/en/developer/portability_platform_table.rst index 617dfd0f868..d8d56329d4d 100644 --- a/src/doc/en/developer/portability_platform_table.rst +++ b/src/doc/en/developer/portability_platform_table.rst @@ -1564,59 +1564,167 @@ .. |codespace-fedora-40-maximal| image:: https://github.com/codespaces/badge.svg :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-fedora-40-maximal%2Fdevcontainer.json -.. |image-centos-stream-9-python3.9-minimal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-minimal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-minimal-with-system-packages +.. |image-fedora-41-minimal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-minimal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-minimal-with-system-packages -.. |image-centos-stream-9-python3.9-minimal-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-minimal-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-minimal-configured +.. |image-fedora-41-minimal-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-minimal-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-minimal-configured -.. |image-centos-stream-9-python3.9-minimal-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-minimal-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%23677895 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-minimal-with-targets-pre +.. |image-fedora-41-minimal-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-minimal-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%23677895 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-minimal-with-targets-pre -.. |image-centos-stream-9-python3.9-minimal-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-minimal-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%236686c1 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-minimal-with-targets +.. |image-fedora-41-minimal-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-minimal-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%236686c1 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-minimal-with-targets -.. |image-centos-stream-9-python3.9-minimal-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-minimal-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%236495ed - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-minimal-with-targets-optional +.. |image-fedora-41-minimal-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-minimal-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%236495ed + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-minimal-with-targets-optional -.. |codespace-centos-stream-9-python3.9-minimal| image:: https://github.com/codespaces/badge.svg - :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-9-python3.9-minimal%2Fdevcontainer.json +.. |codespace-fedora-41-minimal| image:: https://github.com/codespaces/badge.svg + :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-fedora-41-minimal%2Fdevcontainer.json -.. |image-centos-stream-9-python3.9-standard-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-standard-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-standard-with-system-packages +.. |image-fedora-41-standard-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-standard-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-standard-with-system-packages -.. |image-centos-stream-9-python3.9-standard-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-standard-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-standard-configured +.. |image-fedora-41-standard-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-standard-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-standard-configured -.. |image-centos-stream-9-python3.9-standard-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-standard-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%235d8a4c - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-standard-with-targets-pre +.. |image-fedora-41-standard-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-standard-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%235d8a4c + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-standard-with-targets-pre -.. |image-centos-stream-9-python3.9-standard-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-standard-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%2350ab2e - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-standard-with-targets +.. |image-fedora-41-standard-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-standard-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%2350ab2e + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-standard-with-targets -.. |image-centos-stream-9-python3.9-standard-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-standard-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%2344cc11 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-standard-with-targets-optional +.. |image-fedora-41-standard-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-standard-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%2344cc11 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-standard-with-targets-optional -.. |codespace-centos-stream-9-python3.9-standard| image:: https://github.com/codespaces/badge.svg - :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-9-python3.9-standard%2Fdevcontainer.json +.. |codespace-fedora-41-standard| image:: https://github.com/codespaces/badge.svg + :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-fedora-41-standard%2Fdevcontainer.json -.. |image-centos-stream-9-python3.9-maximal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-maximal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-maximal-with-system-packages +.. |image-fedora-41-maximal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-maximal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-maximal-with-system-packages -.. |image-centos-stream-9-python3.9-maximal-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-maximal-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-maximal-configured +.. |image-fedora-41-maximal-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-maximal-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-maximal-configured -.. |image-centos-stream-9-python3.9-maximal-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-maximal-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%238f6b8d - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-maximal-with-targets-pre +.. |image-fedora-41-maximal-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-maximal-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%238f6b8d + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-maximal-with-targets-pre -.. |image-centos-stream-9-python3.9-maximal-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-maximal-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%23b46eb2 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-maximal-with-targets +.. |image-fedora-41-maximal-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-maximal-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%23b46eb2 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-maximal-with-targets -.. |image-centos-stream-9-python3.9-maximal-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.9-maximal-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%23da70d6 - :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.9-maximal-with-targets-optional +.. |image-fedora-41-maximal-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-fedora-41-maximal-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%23da70d6 + :target: https://ghcr.io/sagemath/sage/sage-fedora-41-maximal-with-targets-optional -.. |codespace-centos-stream-9-python3.9-maximal| image:: https://github.com/codespaces/badge.svg - :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-9-python3.9-maximal%2Fdevcontainer.json +.. |codespace-fedora-41-maximal| image:: https://github.com/codespaces/badge.svg + :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-fedora-41-maximal%2Fdevcontainer.json + +.. |image-centos-stream-9-minimal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-minimal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-minimal-with-system-packages + +.. |image-centos-stream-9-minimal-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-minimal-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-minimal-configured + +.. |image-centos-stream-9-minimal-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-minimal-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%23677895 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-minimal-with-targets-pre + +.. |image-centos-stream-9-minimal-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-minimal-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%236686c1 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-minimal-with-targets + +.. |image-centos-stream-9-minimal-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-minimal-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%236495ed + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-minimal-with-targets-optional + +.. |codespace-centos-stream-9-minimal| image:: https://github.com/codespaces/badge.svg + :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-9-minimal%2Fdevcontainer.json + +.. |image-centos-stream-9-standard-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-standard-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-standard-with-system-packages + +.. |image-centos-stream-9-standard-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-standard-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-standard-configured + +.. |image-centos-stream-9-standard-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-standard-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%235d8a4c + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-standard-with-targets-pre + +.. |image-centos-stream-9-standard-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-standard-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%2350ab2e + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-standard-with-targets + +.. |image-centos-stream-9-standard-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-standard-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%2344cc11 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-standard-with-targets-optional + +.. |codespace-centos-stream-9-standard| image:: https://github.com/codespaces/badge.svg + :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-9-standard%2Fdevcontainer.json + +.. |image-centos-stream-9-maximal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-maximal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-maximal-with-system-packages + +.. |image-centos-stream-9-maximal-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-maximal-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-maximal-configured + +.. |image-centos-stream-9-maximal-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-maximal-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%238f6b8d + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-maximal-with-targets-pre + +.. |image-centos-stream-9-maximal-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-maximal-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%23b46eb2 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-maximal-with-targets + +.. |image-centos-stream-9-maximal-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-maximal-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%23da70d6 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-maximal-with-targets-optional + +.. |codespace-centos-stream-9-maximal| image:: https://github.com/codespaces/badge.svg + :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-9-maximal%2Fdevcontainer.json + +.. |image-centos-stream-9-python3.12-minimal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-minimal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-minimal-with-system-packages + +.. |image-centos-stream-9-python3.12-minimal-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-minimal-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-minimal-configured + +.. |image-centos-stream-9-python3.12-minimal-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-minimal-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%23677895 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-minimal-with-targets-pre + +.. |image-centos-stream-9-python3.12-minimal-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-minimal-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%236686c1 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-minimal-with-targets + +.. |image-centos-stream-9-python3.12-minimal-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-minimal-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%236495ed + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-minimal-with-targets-optional + +.. |codespace-centos-stream-9-python3.12-minimal| image:: https://github.com/codespaces/badge.svg + :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-9-python3.12-minimal%2Fdevcontainer.json + +.. |image-centos-stream-9-python3.12-standard-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-standard-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-standard-with-system-packages + +.. |image-centos-stream-9-python3.12-standard-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-standard-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-standard-configured + +.. |image-centos-stream-9-python3.12-standard-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-standard-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%235d8a4c + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-standard-with-targets-pre + +.. |image-centos-stream-9-python3.12-standard-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-standard-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%2350ab2e + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-standard-with-targets + +.. |image-centos-stream-9-python3.12-standard-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-standard-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%2344cc11 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-standard-with-targets-optional + +.. |codespace-centos-stream-9-python3.12-standard| image:: https://github.com/codespaces/badge.svg + :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-9-python3.12-standard%2Fdevcontainer.json + +.. |image-centos-stream-9-python3.12-maximal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-maximal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-maximal-with-system-packages + +.. |image-centos-stream-9-python3.12-maximal-configured| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-maximal-configured/latest_tag?ignore=latest,dev,*-failed&label=configured&color=%23696969 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-maximal-configured + +.. |image-centos-stream-9-python3.12-maximal-with-targets-pre| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-maximal-with-targets-pre/latest_tag?ignore=latest,dev,*-failed&label=with-targets-pre&color=%238f6b8d + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-maximal-with-targets-pre + +.. |image-centos-stream-9-python3.12-maximal-with-targets| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-maximal-with-targets/latest_tag?ignore=latest,dev,*-failed&label=with-targets&color=%23b46eb2 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-maximal-with-targets + +.. |image-centos-stream-9-python3.12-maximal-with-targets-optional| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-centos-stream-9-python3.12-maximal-with-targets-optional/latest_tag?ignore=latest,dev,*-failed&label=with-targets-optional&color=%23da70d6 + :target: https://ghcr.io/sagemath/sage/sage-centos-stream-9-python3.12-maximal-with-targets-optional + +.. |codespace-centos-stream-9-python3.12-maximal| image:: https://github.com/codespaces/badge.svg + :target: https://codespaces.new/sagemath/sage?devcontainer_path=.devcontainer%2Fportability-centos-stream-9-python3.12-maximal%2Fdevcontainer.json .. |image-almalinux-8-python3.9-minimal-with-system-packages| image:: https://ghcr-badge.egpl.dev/sagemath/sage/sage-almalinux-8-python3.9-minimal-with-system-packages/size?tag=dev&label=with-system-packages&color=%23696969 :target: https://ghcr.io/sagemath/sage/sage-almalinux-8-python3.9-minimal-with-system-packages @@ -2593,16 +2701,38 @@ * -    ‑*maximal* - |image-fedora-40-maximal-with-system-packages| |image-fedora-40-maximal-with-targets-pre| - - * - **centos**-stream-9-python3.9 + * - **fedora**-41 + +    ‑*minimal* + - |image-fedora-41-minimal-with-system-packages| |image-fedora-41-minimal-with-targets-pre| |image-fedora-41-minimal-with-targets| |image-fedora-41-minimal-with-targets-optional| + - |codespace-fedora-41-minimal| + * -    ‑*standard* + - |image-fedora-41-standard-with-system-packages| |image-fedora-41-standard-with-targets-pre| |image-fedora-41-standard-with-targets| |image-fedora-41-standard-with-targets-optional| + - |codespace-fedora-41-standard| + * -    ‑*maximal* + - |image-fedora-41-maximal-with-system-packages| |image-fedora-41-maximal-with-targets-pre| + - + * - **centos**-stream-9 + +    ‑*minimal* + - |image-centos-stream-9-minimal-with-system-packages| |image-centos-stream-9-minimal-with-targets-pre| |image-centos-stream-9-minimal-with-targets| |image-centos-stream-9-minimal-with-targets-optional| + - |codespace-centos-stream-9-minimal| + * -    ‑*standard* + - |image-centos-stream-9-standard-with-system-packages| |image-centos-stream-9-standard-with-targets-pre| |image-centos-stream-9-standard-with-targets| |image-centos-stream-9-standard-with-targets-optional| + - |codespace-centos-stream-9-standard| + * -    ‑*maximal* + - |image-centos-stream-9-maximal-with-system-packages| |image-centos-stream-9-maximal-with-targets-pre| + - + * - **centos**-stream-9-python3.12    ‑*minimal* - - |image-centos-stream-9-python3.9-minimal-with-system-packages| |image-centos-stream-9-python3.9-minimal-with-targets-pre| |image-centos-stream-9-python3.9-minimal-with-targets| |image-centos-stream-9-python3.9-minimal-with-targets-optional| - - |codespace-centos-stream-9-python3.9-minimal| + - |image-centos-stream-9-python3.12-minimal-with-system-packages| |image-centos-stream-9-python3.12-minimal-with-targets-pre| |image-centos-stream-9-python3.12-minimal-with-targets| |image-centos-stream-9-python3.12-minimal-with-targets-optional| + - |codespace-centos-stream-9-python3.12-minimal| * -    ‑*standard* - - |image-centos-stream-9-python3.9-standard-with-system-packages| |image-centos-stream-9-python3.9-standard-with-targets-pre| |image-centos-stream-9-python3.9-standard-with-targets| |image-centos-stream-9-python3.9-standard-with-targets-optional| - - |codespace-centos-stream-9-python3.9-standard| + - |image-centos-stream-9-python3.12-standard-with-system-packages| |image-centos-stream-9-python3.12-standard-with-targets-pre| |image-centos-stream-9-python3.12-standard-with-targets| |image-centos-stream-9-python3.12-standard-with-targets-optional| + - |codespace-centos-stream-9-python3.12-standard| * -    ‑*maximal* - - |image-centos-stream-9-python3.9-maximal-with-system-packages| |image-centos-stream-9-python3.9-maximal-with-targets-pre| + - |image-centos-stream-9-python3.12-maximal-with-system-packages| |image-centos-stream-9-python3.12-maximal-with-targets-pre| - * - **almalinux**-8-python3.9 diff --git a/src/doc/en/developer/review.rst b/src/doc/en/developer/review.rst index 0a55393955b..cdcbd42c375 100644 --- a/src/doc/en/developer/review.rst +++ b/src/doc/en/developer/review.rst @@ -76,6 +76,13 @@ The following should generally be checked while reading and testing the code: optional doctests related to the functionality. See :ref:`chapter-doctesting` for more information. +For changes that affect the **user interface**, in particular, upgrades to +IPython and Jupyter component packages, manual testing is crucial because +our automatic tests do not cover the user interface. We recommend to use +a `Jupyter notebook with comprehensive tests of graphics and typesetting +`_, +some of which is Sage-specific. + You are now ready to change the PR's status (see :ref:`section-github-pr-status`): diff --git a/src/doc/en/faq/conf.py b/src/doc/en/faq/conf.py index 4c8a71bd9d1..a175e9cf0ee 100644 --- a/src/doc/en/faq/conf.py +++ b/src/doc/en/faq/conf.py @@ -15,6 +15,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/installation/conda.rst b/src/doc/en/installation/conda.rst index 566fea4ff1a..69369767854 100644 --- a/src/doc/en/installation/conda.rst +++ b/src/doc/en/installation/conda.rst @@ -7,7 +7,7 @@ SageMath can be installed on Linux and macOS via Conda from the `conda-forge `_ conda channel. Both the ``x86_64`` (Intel) architecture and the ``arm64``/``aarch64`` -architectures (including Apple Silicon, M1) are supported. +architectures (including Apple Silicon, M1, M2, M3, M4) are supported. You will need a working Conda installation: either Miniforge (or Mambaforge), Miniconda or Anaconda. If you don't have one yet, we recommend installing diff --git a/src/doc/en/installation/conf.py b/src/doc/en/installation/conf.py index ea6956d2678..7e6174b0d90 100644 --- a/src/doc/en/installation/conf.py +++ b/src/doc/en/installation/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/prep/conf.py b/src/doc/en/prep/conf.py index 645d451644d..03ff6ed7afc 100644 --- a/src/doc/en/prep/conf.py +++ b/src/doc/en/prep/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/reference/conf.py b/src/doc/en/reference/conf.py index 984c43363f2..92b8a8d45b4 100644 --- a/src/doc/en/reference/conf.py +++ b/src/doc/en/reference/conf.py @@ -15,6 +15,11 @@ from sage_docbuild.conf import release, latex_elements, exclude_patterns from sage_docbuild.conf import * + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/reference/conf_sub.py b/src/doc/en/reference/conf_sub.py index 479e9c306d2..c7adc1da994 100644 --- a/src/doc/en/reference/conf_sub.py +++ b/src/doc/en/reference/conf_sub.py @@ -15,6 +15,11 @@ from sage_docbuild.conf import release, exclude_patterns from sage_docbuild.conf import * + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/reference/polynomial_rings/index.rst b/src/doc/en/reference/polynomial_rings/index.rst index 0035c50021f..a3b32b51ce7 100644 --- a/src/doc/en/reference/polynomial_rings/index.rst +++ b/src/doc/en/reference/polynomial_rings/index.rst @@ -62,6 +62,16 @@ Infinite Polynomial Rings sage/rings/polynomial/symmetric_ideal sage/rings/polynomial/symmetric_reduction +Tropical Polynomials +-------------------- + +.. toctree:: + :maxdepth: 1 + + sage/rings/semirings/tropical_polynomial + sage/rings/semirings/tropical_mpolynomial + sage/rings/semirings/tropical_variety + Boolean Polynomials ------------------- diff --git a/src/doc/en/reference/references/index.rst b/src/doc/en/reference/references/index.rst index 872f054f67f..d7fe85422ba 100644 --- a/src/doc/en/reference/references/index.rst +++ b/src/doc/en/reference/references/index.rst @@ -857,6 +857,9 @@ REFERENCES: .. [BrHu2019] Petter Brändén, June Huh. *Lorentzian polynomials*. Ann. Math. (2) 192, No. 3, 821-891 (2020). :arxiv:`1902.03719`, :doi:`10.4007/annals.2020.192.3.4`. + +.. [Bru2014] Erwan Brugalle and Kristin Shaw. *A bit of tropical geometry*. + Amer. Math. Monthly, 121(7):563-589, 2014. .. [BHNR2004] \S. Brlek, S. Hamel, M. Nivat, C. Reutenauer, On the Palindromic Complexity of Infinite Words, @@ -2612,6 +2615,10 @@ REFERENCES: Wehler K3 Surfaces over finite fields*. New Zealand Journal of Mathematics 45 (2015), 19–31. +.. [Fil2017] Ivana Filipan, *An Invitation to Combinatorial Tropical Geometry*. + Conference: 1st Croatian Combinatorial Days. 2017. + :doi:`10.5592/CO/CCD.2016.05`. + .. [FIV2012] \H. Fournier, A. Ismail, and A. Vigneron. *Computing the Gromov hyperbolicity of a discrete metric space*. 2012. :arxiv:`1210.3323`. diff --git a/src/doc/en/thematic_tutorials/conf.py b/src/doc/en/thematic_tutorials/conf.py index cb6d1662f47..581a8e89fc6 100644 --- a/src/doc/en/thematic_tutorials/conf.py +++ b/src/doc/en/thematic_tutorials/conf.py @@ -15,6 +15,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py index b8eef385e4f..9de7aa68adb 100644 --- a/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py +++ b/src/doc/en/thematic_tutorials/explicit_methods_in_number_theory/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/thematic_tutorials/numerical_sage/conf.py b/src/doc/en/thematic_tutorials/numerical_sage/conf.py index 5772289f6fa..c8e220f8f99 100644 --- a/src/doc/en/thematic_tutorials/numerical_sage/conf.py +++ b/src/doc/en/thematic_tutorials/numerical_sage/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/tutorial/afterword.rst b/src/doc/en/tutorial/afterword.rst index 84dd2891b71..390e67bac07 100644 --- a/src/doc/en/tutorial/afterword.rst +++ b/src/doc/en/tutorial/afterword.rst @@ -107,10 +107,8 @@ behaves differently from Python in several ways. 10 - **Integer division:** The Python expression ``2/3`` does not - behave the way mathematicians might expect. In Python2, if ``m`` and - ``n`` are ints, then ``m/n`` is also an int, namely the quotient of ``m`` - divided by ``n``. Therefore ``2/3=0``. In Python3, ``2/3`` returns the - floating point number ``0.6666...``. In both Python2 and Python3, ``//`` + behave the way mathematicians might expect: ``2/3`` returns the + floating point number ``0.6666...``. Note that ``//`` is the Euclidean division and ``2//3`` returns ``0``. We deal with this in the Sage interpreter, by wrapping integer @@ -125,16 +123,11 @@ behaves differently from Python in several ways. Rational Field sage: 2//3 0 - sage: int(2)/int(3) # not tested, python2 - 0 - **Long integers:** Python has native support for arbitrary precision integers, in addition to C-int's. These are significantly - slower than what GMP provides, and have the property that they - print with an ``L`` at the end to distinguish them from int's (and - this won't change any time soon). Sage implements arbitrary - precision integers using the GMP C-library, and these print without - an ``L``. + slower than what GMP provides. Sage implements arbitrary + precision integers using the GMP C-library. Rather than modifying the Python interpreter (as some people have diff --git a/src/doc/en/tutorial/conf.py b/src/doc/en/tutorial/conf.py index b566ec19677..52be3420ed1 100644 --- a/src/doc/en/tutorial/conf.py +++ b/src/doc/en/tutorial/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/en/tutorial/latex.rst b/src/doc/en/tutorial/latex.rst index a173afd75c5..73ef2df3a31 100644 --- a/src/doc/en/tutorial/latex.rst +++ b/src/doc/en/tutorial/latex.rst @@ -49,7 +49,7 @@ output of the entered commands automatically. You can start this automatic rendering by executing ``%display latex`` (and stop by executing ``%display plain``). -.. ONLY:: html +.. ONLY:: html and feature_jupyter_sphinx Thus, in the Jupyter notebook, you get diff --git a/src/doc/en/website/conf.py b/src/doc/en/website/conf.py index 38f31e5d46f..b238169bb3c 100644 --- a/src/doc/en/website/conf.py +++ b/src/doc/en/website/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/es/a_tour_of_sage/conf.py b/src/doc/es/a_tour_of_sage/conf.py index dee2afa4d66..801f7cadb95 100644 --- a/src/doc/es/a_tour_of_sage/conf.py +++ b/src/doc/es/a_tour_of_sage/conf.py @@ -15,6 +15,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/es/tutorial/conf.py b/src/doc/es/tutorial/conf.py index 43e23fdc568..dcb44232ca0 100644 --- a/src/doc/es/tutorial/conf.py +++ b/src/doc/es/tutorial/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/fr/a_tour_of_sage/conf.py b/src/doc/fr/a_tour_of_sage/conf.py index af1f453f3e4..9cca4b7d1f8 100644 --- a/src/doc/fr/a_tour_of_sage/conf.py +++ b/src/doc/fr/a_tour_of_sage/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release, latex_elements from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/fr/tutorial/conf.py b/src/doc/fr/tutorial/conf.py index af70d3eb4ff..38e0160f3ba 100644 --- a/src/doc/fr/tutorial/conf.py +++ b/src/doc/fr/tutorial/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release, latex_elements from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/hu/a_tour_of_sage/conf.py b/src/doc/hu/a_tour_of_sage/conf.py index b097f56dfe0..2e5215fcf5d 100644 --- a/src/doc/hu/a_tour_of_sage/conf.py +++ b/src/doc/hu/a_tour_of_sage/conf.py @@ -15,6 +15,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/it/a_tour_of_sage/conf.py b/src/doc/it/a_tour_of_sage/conf.py index d06280ece36..48a568cc4d1 100644 --- a/src/doc/it/a_tour_of_sage/conf.py +++ b/src/doc/it/a_tour_of_sage/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release, latex_elements from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/it/faq/conf.py b/src/doc/it/faq/conf.py index e3898184a1f..84a8ac93eab 100644 --- a/src/doc/it/faq/conf.py +++ b/src/doc/it/faq/conf.py @@ -15,6 +15,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/it/faq/faq-contribute.rst b/src/doc/it/faq/faq-contribute.rst index 63c67a8e264..3b6c1612083 100644 --- a/src/doc/it/faq/faq-contribute.rst +++ b/src/doc/it/faq/faq-contribute.rst @@ -158,8 +158,8 @@ Consulta anche la Guida dello Sviluppo Sage, specialmente il capitolo `Convenzioni per scrivere codice sorgente in Sage `_. -Ho inviato al server trac una correzione molte settimane fa. Perché la state ignorando? -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" +Ho inviato al GitHub Sage repo una correzione molte settimane fa. Perché la state ignorando? +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" Non stiamo cercando di ignorare la tua correzione. Le persone che lavorano su Sage lo fanno nel loro tempo libero. diff --git a/src/doc/it/tutorial/conf.py b/src/doc/it/tutorial/conf.py index 15186edb4ba..ea77f3199b0 100644 --- a/src/doc/it/tutorial/conf.py +++ b/src/doc/it/tutorial/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release, latex_elements from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/ja/a_tour_of_sage/conf.py b/src/doc/ja/a_tour_of_sage/conf.py index e8ec7cca39b..eef0eba83b3 100644 --- a/src/doc/ja/a_tour_of_sage/conf.py +++ b/src/doc/ja/a_tour_of_sage/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release, latex_elements from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/ja/tutorial/conf.py b/src/doc/ja/tutorial/conf.py index 9002593de99..eaaa4558a34 100644 --- a/src/doc/ja/tutorial/conf.py +++ b/src/doc/ja/tutorial/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release, latex_elements from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/pt/a_tour_of_sage/conf.py b/src/doc/pt/a_tour_of_sage/conf.py index 267d499ca64..806bc1b77c8 100644 --- a/src/doc/pt/a_tour_of_sage/conf.py +++ b/src/doc/pt/a_tour_of_sage/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/pt/tutorial/conf.py b/src/doc/pt/tutorial/conf.py index a5cabc5b0d1..26368567ee4 100644 --- a/src/doc/pt/tutorial/conf.py +++ b/src/doc/pt/tutorial/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/ru/tutorial/conf.py b/src/doc/ru/tutorial/conf.py index 5d39f7d2600..f2f44113045 100644 --- a/src/doc/ru/tutorial/conf.py +++ b/src/doc/ru/tutorial/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/doc/tr/a_tour_of_sage/conf.py b/src/doc/tr/a_tour_of_sage/conf.py index b7536470bd4..9d2a503d78d 100644 --- a/src/doc/tr/a_tour_of_sage/conf.py +++ b/src/doc/tr/a_tour_of_sage/conf.py @@ -13,6 +13,11 @@ from sage_docbuild.conf import release from sage_docbuild.conf import * # NOQA + +for tag in feature_tags(): + tags.add(tag) + + # Add any paths that contain custom static files (such as style sheets), # relative to this directory to html_static_path. They are copied after the # builtin static files, so a file named "default.css" will overwrite the diff --git a/src/environment-3.10-linux-aarch64.yml b/src/environment-3.10-linux-aarch64.yml index 4e20820eec1..7c6026a6b00 100644 --- a/src/environment-3.10-linux-aarch64.yml +++ b/src/environment-3.10-linux-aarch64.yml @@ -38,7 +38,6 @@ dependencies: - brotli=1.1.0=h31becfc_1 - brotli-bin=1.1.0=h31becfc_1 - brotli-python=1.1.0=py310hbb3657e_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h8af1aa0_1 - bzip2=1.0.8=h31becfc_5 - c-ares=1.28.1=h31becfc_0 @@ -320,6 +319,7 @@ dependencies: - 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 diff --git a/src/environment-3.10-linux.yml b/src/environment-3.10-linux.yml index 73a318f1073..f2667c2307e 100644 --- a/src/environment-3.10-linux.yml +++ b/src/environment-3.10-linux.yml @@ -39,7 +39,6 @@ dependencies: - brotli=1.1.0=hd590300_1 - brotli-bin=1.1.0=hd590300_1 - brotli-python=1.1.0=py310hc6cd4ac_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=ha770c72_1 - bzip2=1.0.8=hd590300_5 - c-ares=1.28.1=hd590300_0 @@ -358,6 +357,7 @@ dependencies: - 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 diff --git a/src/environment-3.10-macos-x86_64.yml b/src/environment-3.10-macos-x86_64.yml index ef12b1c101c..268e619f1ff 100644 --- a/src/environment-3.10-macos-x86_64.yml +++ b/src/environment-3.10-macos-x86_64.yml @@ -32,7 +32,6 @@ dependencies: - brotli=1.1.0=h0dc2134_1 - brotli-bin=1.1.0=h0dc2134_1 - brotli-python=1.1.0=py310h9e9d8ca_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h694c41f_1 - bzip2=1.0.8=h10d778d_5 - c-ares=1.28.1=h10d778d_0 @@ -324,6 +323,7 @@ dependencies: - 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 diff --git a/src/environment-3.10-macos.yml b/src/environment-3.10-macos.yml index 1e7bd5209bc..9110653e86c 100644 --- a/src/environment-3.10-macos.yml +++ b/src/environment-3.10-macos.yml @@ -32,7 +32,6 @@ dependencies: - brotli=1.1.0=hb547adb_1 - brotli-bin=1.1.0=hb547adb_1 - brotli-python=1.1.0=py310h1253130_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=hce30654_1 - bzip2=1.0.8=h93a5062_5 - c-ares=1.28.1=h93a5062_0 @@ -324,6 +323,7 @@ dependencies: - 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 diff --git a/src/environment-3.11-linux-aarch64.yml b/src/environment-3.11-linux-aarch64.yml index e03e0ed8864..87cee9aad2a 100644 --- a/src/environment-3.11-linux-aarch64.yml +++ b/src/environment-3.11-linux-aarch64.yml @@ -38,7 +38,6 @@ dependencies: - brotli=1.1.0=h31becfc_1 - brotli-bin=1.1.0=h31becfc_1 - brotli-python=1.1.0=py311h8715677_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h8af1aa0_1 - bzip2=1.0.8=h31becfc_5 - c-ares=1.28.1=h31becfc_0 @@ -320,6 +319,7 @@ dependencies: - 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 diff --git a/src/environment-3.11-linux.yml b/src/environment-3.11-linux.yml index 32d1541e494..6716e043193 100644 --- a/src/environment-3.11-linux.yml +++ b/src/environment-3.11-linux.yml @@ -39,7 +39,6 @@ dependencies: - brotli=1.1.0=hd590300_1 - brotli-bin=1.1.0=hd590300_1 - brotli-python=1.1.0=py311hb755f60_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=ha770c72_1 - bzip2=1.0.8=hd590300_5 - c-ares=1.28.1=hd590300_0 @@ -358,6 +357,7 @@ dependencies: - 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 diff --git a/src/environment-3.11-macos-x86_64.yml b/src/environment-3.11-macos-x86_64.yml index 6d62ac79ca3..d0fc9f07c5c 100644 --- a/src/environment-3.11-macos-x86_64.yml +++ b/src/environment-3.11-macos-x86_64.yml @@ -32,7 +32,6 @@ dependencies: - brotli=1.1.0=h0dc2134_1 - brotli-bin=1.1.0=h0dc2134_1 - brotli-python=1.1.0=py311hdf8f085_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h694c41f_1 - bzip2=1.0.8=h10d778d_5 - c-ares=1.28.1=h10d778d_0 @@ -324,6 +323,7 @@ dependencies: - 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 diff --git a/src/environment-3.11-macos.yml b/src/environment-3.11-macos.yml index a96a5142606..192cc3a5f33 100644 --- a/src/environment-3.11-macos.yml +++ b/src/environment-3.11-macos.yml @@ -32,7 +32,6 @@ dependencies: - brotli=1.1.0=hb547adb_1 - brotli-bin=1.1.0=hb547adb_1 - brotli-python=1.1.0=py311ha891d26_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=hce30654_1 - bzip2=1.0.8=h93a5062_5 - c-ares=1.28.1=h93a5062_0 @@ -324,6 +323,7 @@ dependencies: - 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 diff --git a/src/environment-3.9-linux-aarch64.yml b/src/environment-3.9-linux-aarch64.yml index cd423b040c4..43382444aae 100644 --- a/src/environment-3.9-linux-aarch64.yml +++ b/src/environment-3.9-linux-aarch64.yml @@ -38,7 +38,6 @@ dependencies: - brotli=1.1.0=h31becfc_1 - brotli-bin=1.1.0=h31becfc_1 - brotli-python=1.1.0=py39h387a81e_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h8af1aa0_1 - bzip2=1.0.8=h31becfc_5 - c-ares=1.28.1=h31becfc_0 @@ -320,6 +319,7 @@ dependencies: - 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 diff --git a/src/environment-3.9-linux.yml b/src/environment-3.9-linux.yml index 36d7a6fab66..c1cae4f27db 100644 --- a/src/environment-3.9-linux.yml +++ b/src/environment-3.9-linux.yml @@ -39,7 +39,6 @@ dependencies: - brotli=1.1.0=hd590300_1 - brotli-bin=1.1.0=hd590300_1 - brotli-python=1.1.0=py39h3d6467e_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=ha770c72_1 - bzip2=1.0.8=hd590300_5 - c-ares=1.28.1=hd590300_0 @@ -358,6 +357,7 @@ dependencies: - 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 diff --git a/src/environment-3.9-macos-x86_64.yml b/src/environment-3.9-macos-x86_64.yml index 566775ddd11..c3026a8fbc0 100644 --- a/src/environment-3.9-macos-x86_64.yml +++ b/src/environment-3.9-macos-x86_64.yml @@ -32,7 +32,6 @@ dependencies: - brotli=1.1.0=h0dc2134_1 - brotli-bin=1.1.0=h0dc2134_1 - brotli-python=1.1.0=py39h840bb9f_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h694c41f_1 - bzip2=1.0.8=h10d778d_5 - c-ares=1.28.1=h10d778d_0 @@ -324,6 +323,7 @@ dependencies: - 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 diff --git a/src/environment-3.9-macos.yml b/src/environment-3.9-macos.yml index 4cf9ff6e7bc..5137c9298af 100644 --- a/src/environment-3.9-macos.yml +++ b/src/environment-3.9-macos.yml @@ -32,7 +32,6 @@ dependencies: - brotli=1.1.0=hb547adb_1 - brotli-bin=1.1.0=hb547adb_1 - brotli-python=1.1.0=py39hb198ff7_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=hce30654_1 - bzip2=1.0.8=h93a5062_5 - c-ares=1.28.1=h93a5062_0 @@ -324,6 +323,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.10-linux-aarch64.yml b/src/environment-dev-3.10-linux-aarch64.yml index e0a7428c353..5cc9a611a2a 100644 --- a/src/environment-dev-3.10-linux-aarch64.yml +++ b/src/environment-dev-3.10-linux-aarch64.yml @@ -42,7 +42,6 @@ dependencies: - brotli=1.1.0=h31becfc_1 - brotli-bin=1.1.0=h31becfc_1 - brotli-python=1.1.0=py310hbb3657e_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h8af1aa0_1 - bzip2=1.0.8=h31becfc_5 - c-ares=1.28.1=h31becfc_0 @@ -367,6 +366,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.10-linux.yml b/src/environment-dev-3.10-linux.yml index 98b9bb546f9..90d8df80567 100644 --- a/src/environment-dev-3.10-linux.yml +++ b/src/environment-dev-3.10-linux.yml @@ -42,7 +42,6 @@ dependencies: - brotli=1.1.0=hd590300_1 - brotli-bin=1.1.0=hd590300_1 - brotli-python=1.1.0=py310hc6cd4ac_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=ha770c72_1 - bzip2=1.0.8=hd590300_5 - c-ares=1.28.1=hd590300_0 @@ -402,6 +401,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.10-macos-x86_64.yml b/src/environment-dev-3.10-macos-x86_64.yml index 2013ecba6a1..6541d3ef7c8 100644 --- a/src/environment-dev-3.10-macos-x86_64.yml +++ b/src/environment-dev-3.10-macos-x86_64.yml @@ -35,7 +35,6 @@ dependencies: - brotli=1.1.0=h0dc2134_1 - brotli-bin=1.1.0=h0dc2134_1 - brotli-python=1.1.0=py310h9e9d8ca_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h694c41f_1 - bzip2=1.0.8=h10d778d_5 - c-ares=1.28.1=h10d778d_0 @@ -365,6 +364,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.10-macos.yml b/src/environment-dev-3.10-macos.yml index 5e68c311f97..014df8bdc08 100644 --- a/src/environment-dev-3.10-macos.yml +++ b/src/environment-dev-3.10-macos.yml @@ -35,7 +35,6 @@ dependencies: - brotli=1.1.0=hb547adb_1 - brotli-bin=1.1.0=hb547adb_1 - brotli-python=1.1.0=py310h1253130_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=hce30654_1 - bzip2=1.0.8=h93a5062_5 - c-ares=1.28.1=h93a5062_0 @@ -365,6 +364,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.11-linux-aarch64.yml b/src/environment-dev-3.11-linux-aarch64.yml index b6877adff0c..9772d14d173 100644 --- a/src/environment-dev-3.11-linux-aarch64.yml +++ b/src/environment-dev-3.11-linux-aarch64.yml @@ -42,7 +42,6 @@ dependencies: - brotli=1.1.0=h31becfc_1 - brotli-bin=1.1.0=h31becfc_1 - brotli-python=1.1.0=py311h8715677_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h8af1aa0_1 - bzip2=1.0.8=h31becfc_5 - c-ares=1.28.1=h31becfc_0 @@ -367,6 +366,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.11-linux.yml b/src/environment-dev-3.11-linux.yml index 61335e6a853..f59609c4b25 100644 --- a/src/environment-dev-3.11-linux.yml +++ b/src/environment-dev-3.11-linux.yml @@ -42,7 +42,6 @@ dependencies: - brotli=1.1.0=hd590300_1 - brotli-bin=1.1.0=hd590300_1 - brotli-python=1.1.0=py311hb755f60_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=ha770c72_1 - bzip2=1.0.8=hd590300_5 - c-ares=1.28.1=hd590300_0 @@ -402,6 +401,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.11-macos-x86_64.yml b/src/environment-dev-3.11-macos-x86_64.yml index ac36b8f0f89..3368f995b8c 100644 --- a/src/environment-dev-3.11-macos-x86_64.yml +++ b/src/environment-dev-3.11-macos-x86_64.yml @@ -35,7 +35,6 @@ dependencies: - brotli=1.1.0=h0dc2134_1 - brotli-bin=1.1.0=h0dc2134_1 - brotli-python=1.1.0=py311hdf8f085_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h694c41f_1 - bzip2=1.0.8=h10d778d_5 - c-ares=1.28.1=h10d778d_0 @@ -365,6 +364,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.11-macos.yml b/src/environment-dev-3.11-macos.yml index 584fcb8acc4..ba84799917e 100644 --- a/src/environment-dev-3.11-macos.yml +++ b/src/environment-dev-3.11-macos.yml @@ -35,7 +35,6 @@ dependencies: - brotli=1.1.0=hb547adb_1 - brotli-bin=1.1.0=hb547adb_1 - brotli-python=1.1.0=py311ha891d26_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=hce30654_1 - bzip2=1.0.8=h93a5062_5 - c-ares=1.28.1=h93a5062_0 @@ -365,6 +364,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.9-linux-aarch64.yml b/src/environment-dev-3.9-linux-aarch64.yml index d975d72ca98..39923130bc5 100644 --- a/src/environment-dev-3.9-linux-aarch64.yml +++ b/src/environment-dev-3.9-linux-aarch64.yml @@ -42,7 +42,6 @@ dependencies: - brotli=1.1.0=h31becfc_1 - brotli-bin=1.1.0=h31becfc_1 - brotli-python=1.1.0=py39h387a81e_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h8af1aa0_1 - bzip2=1.0.8=h31becfc_5 - c-ares=1.28.1=h31becfc_0 @@ -367,6 +366,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.9-linux.yml b/src/environment-dev-3.9-linux.yml index 6aaffa90cab..451a093512e 100644 --- a/src/environment-dev-3.9-linux.yml +++ b/src/environment-dev-3.9-linux.yml @@ -42,7 +42,6 @@ dependencies: - brotli=1.1.0=hd590300_1 - brotli-bin=1.1.0=hd590300_1 - brotli-python=1.1.0=py39h3d6467e_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=ha770c72_1 - bzip2=1.0.8=hd590300_5 - c-ares=1.28.1=hd590300_0 @@ -402,6 +401,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.9-macos-x86_64.yml b/src/environment-dev-3.9-macos-x86_64.yml index d34360440bd..92632f26f85 100644 --- a/src/environment-dev-3.9-macos-x86_64.yml +++ b/src/environment-dev-3.9-macos-x86_64.yml @@ -35,7 +35,6 @@ dependencies: - brotli=1.1.0=h0dc2134_1 - brotli-bin=1.1.0=h0dc2134_1 - brotli-python=1.1.0=py39h840bb9f_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=h694c41f_1 - bzip2=1.0.8=h10d778d_5 - c-ares=1.28.1=h10d778d_0 @@ -365,6 +364,7 @@ dependencies: - 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 diff --git a/src/environment-dev-3.9-macos.yml b/src/environment-dev-3.9-macos.yml index 934855f53d6..bcc3c684e61 100644 --- a/src/environment-dev-3.9-macos.yml +++ b/src/environment-dev-3.9-macos.yml @@ -35,7 +35,6 @@ dependencies: - brotli=1.1.0=hb547adb_1 - brotli-bin=1.1.0=hb547adb_1 - brotli-python=1.1.0=py39hb198ff7_1 - - build=0.7.0=pyhd8ed1ab_0 - bwidget=1.9.14=hce30654_1 - bzip2=1.0.8=h93a5062_5 - c-ares=1.28.1=h93a5062_0 @@ -365,6 +364,7 @@ dependencies: - 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 diff --git a/src/pyproject.toml b/src/pyproject.toml index 8b12b6c77ee..458144ec462 100644 --- a/src/pyproject.toml +++ b/src/pyproject.toml @@ -15,6 +15,7 @@ requires = [ # per https://github.com/scipy/scipy/blob/maintenance/1.13.x/pyproject.toml 'numpy >=1.22.4', 'pkgconfig', + 'jinja2', ] build-backend = "setuptools.build_meta" diff --git a/src/sage/algebras/cluster_algebra.py b/src/sage/algebras/cluster_algebra.py index 43a7bba9816..042b9365ecb 100644 --- a/src/sage/algebras/cluster_algebra.py +++ b/src/sage/algebras/cluster_algebra.py @@ -242,7 +242,7 @@ sage: S.cluster_variable(3) (x2 + 1)/x3 -Walking around by mutating ``S`` updates the informations stored in ``A``:: +Walking around by mutating ``S`` updates the information stored in ``A``:: sage: len(A.g_vectors_so_far()) 10 diff --git a/src/sage/algebras/commutative_dga.py b/src/sage/algebras/commutative_dga.py index 60b80719c53..d71f93a2600 100644 --- a/src/sage/algebras/commutative_dga.py +++ b/src/sage/algebras/commutative_dga.py @@ -2543,7 +2543,7 @@ def minimal_model(self, i=3, max_iterations=3, partial_result=False): or the partial result computed up to that point is returned, deppending on the ``partial_result`` flag. - - ``partial_result`` -- boolean (default: ``False``); wether to return + - ``partial_result`` -- boolean (default: ``False``); whether to return the partial result if the ``max_iterations`` limit is reached OUTPUT: diff --git a/src/sage/algebras/exterior_algebra_groebner.pyx b/src/sage/algebras/exterior_algebra_groebner.pyx index cad3574c8a2..9704bcbbfb0 100644 --- a/src/sage/algebras/exterior_algebra_groebner.pyx +++ b/src/sage/algebras/exterior_algebra_groebner.pyx @@ -373,7 +373,7 @@ cdef class GroebnerStrategy: else: constructed[f0.lsi] = set([f0]) G.append(f0) - # Find the degress of the new pairs + # Find the degrees of the new pairs for j in range(n, len(G)): f1 = G[j] p1 = f1.ls 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 da5e18db630..3ba4bc658cb 100644 --- a/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py +++ b/src/sage/algebras/finite_dimensional_algebras/finite_dimensional_algebra.py @@ -1,7 +1,7 @@ """ Finite-Dimensional Algebras """ -#***************************************************************************** +# *************************************************************************** # Copyright (C) 2011 Johan Bosman # Copyright (C) 2011, 2013 Peter Bruin # Copyright (C) 2011 Michiel Kosters @@ -9,8 +9,8 @@ # 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/ -#***************************************************************************** +# http:s//www.gnu.org/licenses/ +# *************************************************************************** from .finite_dimensional_algebra_element import FiniteDimensionalAlgebraElement from .finite_dimensional_algebra_ideal import FiniteDimensionalAlgebraIdeal @@ -20,15 +20,15 @@ from sage.categories.magmatic_algebras import MagmaticAlgebras from sage.matrix.constructor import matrix from sage.structure.element import Matrix -from sage.rings.ring import Algebra from sage.structure.category_object import normalize_names +from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation from sage.misc.cachefunc import cached_method from functools import reduce -class FiniteDimensionalAlgebra(UniqueRepresentation, Algebra): +class FiniteDimensionalAlgebra(UniqueRepresentation, Parent): r""" Create a finite-dimensional `k`-algebra from a multiplication table. @@ -187,7 +187,7 @@ def __init__(self, k, table, names='e', category=None): self._table = table self._assume_associative = "Associative" in category.axioms() # No further validity checks necessary! - Algebra.__init__(self, base_ring=k, names=names, category=category) + Parent.__init__(self, base=k, names=names, category=category) def _repr_(self): """ @@ -303,10 +303,10 @@ def basis(self): sage: A = FiniteDimensionalAlgebra(GF(3), [Matrix([[1, 0], [0, 1]]), ....: Matrix([[0, 1], [0, 0]])]) sage: A.basis() - Family (e0, e1) + Finite family {0: e0, 1: e1} """ from sage.sets.family import Family - return Family(self.gens()) + return Family({i: self.gen(i) for i in range(self.ngens())}) def __iter__(self): """ diff --git a/src/sage/algebras/fusion_rings/f_matrix.py b/src/sage/algebras/fusion_rings/f_matrix.py index 52e9cfdeb98..b832a520fec 100644 --- a/src/sage/algebras/fusion_rings/f_matrix.py +++ b/src/sage/algebras/fusion_rings/f_matrix.py @@ -189,7 +189,7 @@ class FMatrix(SageObject): sage: f.f_from(s, s, s, s), f.f_to(s, s, s, s) ([i0, p], [i0, p]) - The last two statments show that the possible values of + The last two statements show that the possible values of `X` and `Y` when `A = B = C = D = s` are `i_0` and `p`. The F-matrix is computed by solving the so-called diff --git a/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx b/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx index 2627a6f11b1..44c9e5b3910 100644 --- a/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx +++ b/src/sage/algebras/fusion_rings/fast_parallel_fmats_methods.pyx @@ -455,7 +455,7 @@ cpdef executor(tuple params): Execute a function defined in this module (``sage.algebras.fusion_rings.fast_parallel_fmats_methods``) in a worker process, and supply the factory parameter by constructing a reference - to the ``FMatrix`` object in the worker's memory adress space from + to the ``FMatrix`` object in the worker's memory address space from its ``id``. INPUT: diff --git a/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pyx b/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pyx index ad6e8a1621e..deaa4517406 100644 --- a/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pyx +++ b/src/sage/algebras/fusion_rings/fast_parallel_fusion_ring_braid_repn.pyx @@ -268,7 +268,7 @@ cpdef executor(tuple params): Execute a function registered in this module's ``mappers`` in a worker process, and supply the ``FusionRing`` parameter by constructing a reference to the FMatrix object in the worker's memory - adress space from its ``id``. + address space from its ``id``. .. NOTE:: @@ -310,7 +310,7 @@ cpdef _unflatten_entries(fusion_ring, list entries): Restore cyclotomic coefficient object from its tuple of rational coefficients representation. - Used to circumvent pickling issue introduced by PARI settigs + Used to circumvent pickling issue introduced by PARI settings in :issue:`30537`. EXAMPLES:: diff --git a/src/sage/algebras/fusion_rings/poly_tup_engine.pyx b/src/sage/algebras/fusion_rings/poly_tup_engine.pyx index f263e47d562..6c0b8d2ac27 100644 --- a/src/sage/algebras/fusion_rings/poly_tup_engine.pyx +++ b/src/sage/algebras/fusion_rings/poly_tup_engine.pyx @@ -93,7 +93,7 @@ cpdef tuple _unflatten_coeffs(field, tuple eq_tup): Restore cyclotomic coefficient object from its tuple of rational coefficients representation. - Used to circumvent pickling issue introduced by PARI settigs + Used to circumvent pickling issue introduced by PARI settings in :issue:`30537`. EXAMPLES:: @@ -447,7 +447,7 @@ cpdef dict compute_known_powers(max_degs, dict val_dict, one): - ``max_deg`` -- an ``ETuple`` indicating the maximal degree of each variable - ``val_dict`` -- dictionary of ``(var_idx, poly_tup)`` key-value pairs - - ``poly_tup`` -- tuple of ``(ETuple, coeff)`` pairs reperesenting a + - ``poly_tup`` -- tuple of ``(ETuple, coeff)`` pairs representing a multivariate polynomial EXAMPLES:: diff --git a/src/sage/algebras/fusion_rings/shm_managers.pyx b/src/sage/algebras/fusion_rings/shm_managers.pyx index 94bc24eb4ce..d5acb513219 100644 --- a/src/sage/algebras/fusion_rings/shm_managers.pyx +++ b/src/sage/algebras/fusion_rings/shm_managers.pyx @@ -400,7 +400,7 @@ cdef class FvarsHandler: known squares for initialization, e.g., from a solver checkpoint - ``use_mp`` -- integer indicating the number of child processes used for multiprocessing; if running serially, use 0 - - ``pids_name`` -- the name of a ``ShareableList`` contaning the + - ``pids_name`` -- the name of a ``ShareableList`` containing the process ``pid``'s for every process in the pool (including the parent process) - ``name`` -- the name of a shared memory object diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py index d96b05f43a8..9aa6fa63ff2 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_algebra.py @@ -1322,7 +1322,7 @@ def get_order(self): sage: len(CHA3.get_order()) 24 """ - # The reason we have overriden this is that we have to care about + # The reason we have overridden this is that we have to care about # the dynamical growth of thefinite sub basis used for the # calculation in case of more than 4 strands. @@ -3047,7 +3047,7 @@ def cubic_equation_parameters(self, generic=False): - ``generic`` -- boolean (default: ``False``); if set to ``True`` the coefficients are returned as elements of the generic base ring - OUTPUT: a tripple consisting of the coefficients + OUTPUT: a triple consisting of the coefficients EXAMPLES:: 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 7afbe1432dd..3521e9bd478 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_base_ring.py @@ -103,7 +103,7 @@ def register_ring_hom(ring_hom): try: codomain.register_conversion(ring_hom) except ValueError: - verbose('\nthe map:\n%s\ncannot be registerd as conversion\n' % ring_hom) + verbose('\nthe map:\n%s\ncannot be registered as conversion\n' % ring_hom) return @@ -317,7 +317,7 @@ def _element_constructor_(self, x, mon=None): def _coerce_map_from_(self, R): r""" The rings that canonically coerce to ``self`` ar the ones from - inheritence and the base ring of definition of the cubic Hecke algebra. + inheritance and the base ring of definition of the cubic Hecke algebra. EXAMPLES:: @@ -385,7 +385,7 @@ def hom(self, im_gens, codomain=None, check=True, base_map=None): return super().hom(im_remain, codomain=codomain, check=check, base_map=hom_cycl_gen) else: if base_map is None: - raise ValueError('number of images must be four (inculding a ' + raise ValueError('number of images must be four (including a ' 'third root of unity at first position) or a ' 'base_map (on %s) must be given' % self.base_ring()) return super().hom(im_gens, codomain=codomain, check=check, base_map=base_map) diff --git a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py index 9964fa4e287..59b0767fb48 100644 --- a/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py +++ b/src/sage/algebras/hecke_algebras/cubic_hecke_matrix_rep.py @@ -491,7 +491,7 @@ def __getitem__(self, item): - ``item`` -- an :class:`AbsIrreducibeRep` specifying an absolute irreducible representation of the cubic Hecke algebra; alternatively, it can be specified by list index - (see :meth:`internal_index` repectively :meth:`gap_index`) + (see :meth:`internal_index` respectively :meth:`gap_index`) OUTPUT: @@ -732,7 +732,7 @@ def _element_constructor_(self, x): :class:`~sage.algebras.hecke_algebras.cubic_hecke_algebra.CubicHeckeAlgebra` or an element whose parent is a :class:`MatrixSpace` - EXAMLPES:: + EXAMPlES:: sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA3. = algebras.CubicHecke(3) @@ -786,7 +786,7 @@ def __call__(self, entries=None, coerce=True, copy=None): This method needs to be overloaded here since :class:`MatrixSpace` has an own implementation of it. - EXAMLPES:: + EXAMPLES:: sage: import sage.algebras.hecke_algebras.cubic_hecke_matrix_rep as chmr sage: CHA2. = algebras.CubicHecke(2) diff --git a/src/sage/algebras/lie_algebras/bgg_dual_module.py b/src/sage/algebras/lie_algebras/bgg_dual_module.py index 01517c4e51f..5f0fa10ddfc 100644 --- a/src/sage/algebras/lie_algebras/bgg_dual_module.py +++ b/src/sage/algebras/lie_algebras/bgg_dual_module.py @@ -1153,6 +1153,7 @@ def _acted_upon_(self, scalar, self_on_left=True): _lmul_ = _acted_upon_ _rmul_ = _acted_upon_ + class FiniteDimensionalSimpleModule(SimpleModule): """ A finite dimensional simple module. diff --git a/src/sage/algebras/lie_algebras/bgg_resolution.py b/src/sage/algebras/lie_algebras/bgg_resolution.py index 89ccb3d2079..906f8d43f95 100644 --- a/src/sage/algebras/lie_algebras/bgg_resolution.py +++ b/src/sage/algebras/lie_algebras/bgg_resolution.py @@ -22,6 +22,7 @@ from sage.rings.integer_ring import ZZ from sage.homology.chain_complex import ChainComplex_class + class BGGResolution(UniqueRepresentation, ChainComplex_class): r""" The BGG resolution of a simple module. @@ -81,7 +82,7 @@ def __init__(self, L): self._cartan_type = ct self._simple = L self._W = WeylGroup(ct, prefix='s') - # finish intialization + # finish initialization R = self._simple.base_ring() differentials, mod_order = build_differentials(self._W) differentials = {deg: mat.change_ring(R) for deg, mat in differentials.items()} @@ -212,7 +213,7 @@ def build_differentials(W): vind = dv[0] vpind = dvp[0] for uind in dv[1] & dvp[1]: - # set the entires corresponding to the square + # set the entries corresponding to the square if not mat[j, vind]: if not mat[j, vpind]: mat[j, vpind] = one diff --git a/src/sage/algebras/lie_algebras/center_uea.py b/src/sage/algebras/lie_algebras/center_uea.py index 61f5c6e05d7..c155a797ca5 100644 --- a/src/sage/algebras/lie_algebras/center_uea.py +++ b/src/sage/algebras/lie_algebras/center_uea.py @@ -742,7 +742,7 @@ def retract(self, elt): True """ # This should work except it needs the monomials of the PBW basis to be - # compariable. However, this does not work for, e.g., Lie algebras + # comparable. However, this does not work for, e.g., Lie algebras # in the Chevalley basis as ee are unable to pass a key for the # module morphism. Additionally, the implementation below does more # operations in-place than the module morphism. diff --git a/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py b/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py index 813a5a45293..41dc9cd8159 100644 --- a/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py +++ b/src/sage/algebras/lie_algebras/poincare_birkhoff_witt.py @@ -795,7 +795,7 @@ def transpose(self): r""" Return the transpose map of ``self``. - This is the tranpose map on the Lie algebra extended + This is the transpose map on the Lie algebra extended as an anti-involution of ``self``. EXAMPLES:: diff --git a/src/sage/algebras/quatalg/quaternion_algebra.py b/src/sage/algebras/quatalg/quaternion_algebra.py index 32353a688b6..f85f282c0bb 100644 --- a/src/sage/algebras/quatalg/quaternion_algebra.py +++ b/src/sage/algebras/quatalg/quaternion_algebra.py @@ -861,7 +861,7 @@ def maximal_order(self, take_shortcuts=True, order_basis=None): # Since Voight's algorithm only works for a starting basis having 1 as # its first vector, we derive such a basis from the given order basis - basis = basis_for_quaternion_lattice(order_basis, reverse=True) + basis = basis_for_quaternion_lattice(order_basis) e_new_gens = [] @@ -939,7 +939,7 @@ def maximal_order(self, take_shortcuts=True, order_basis=None): h = (z*b)*e_n[1] - (y*a)*e_n[2] e_n[1:4] = [g, h, g * h] if (1 - a*y**2 - b*z**2 + a*b*w**2).valuation(2) > 2: - e_n = basis_for_quaternion_lattice(list(e) + e_n[1:], reverse=True) + e_n = basis_for_quaternion_lattice(list(e) + e_n[1:]) # e_n now contains elements that locally at p give a bigger order, # but the basis may be messed up at other primes (it might not @@ -953,7 +953,7 @@ def maximal_order(self, take_shortcuts=True, order_basis=None): e_new_gens.extend(e[1:]) - e_new = basis_for_quaternion_lattice(list(basis) + e_new_gens, reverse=True) + e_new = basis_for_quaternion_lattice(list(basis) + e_new_gens) return self.quaternion_order(e_new) def order_with_level(self, level): @@ -1620,8 +1620,8 @@ def __init__(self, A, basis, check=True): raise ValueError("lattice must contain 1") # check if multiplicatively closed - M1 = basis_for_quaternion_lattice(basis, reverse=False) - M2 = basis_for_quaternion_lattice(list(basis) + [x * y for x in basis for y in basis], reverse=False) + M1 = basis_for_quaternion_lattice(basis) + M2 = basis_for_quaternion_lattice(list(basis) + [x * y for x in basis for y in basis]) if M1 != M2: raise ValueError("given lattice must be a ring") @@ -2010,11 +2010,11 @@ def _left_ideal_basis(self, gens): sage: A. = QuaternionAlgebra(-17, -3) sage: A.maximal_order()._left_ideal_basis([i + j, i - j, 2*k, A(3)]) - [1/2 + 1/6*j + 2/3*k, 1/2*i + 1/2*k, 1/3*j + 1/3*k, k] + [1, i, 1/2 + 1/2*j, 1/2 + 1/2*i + 1/6*j + 1/6*k] sage: A.maximal_order()._left_ideal_basis([3*(i + j), 3*(i - j), 6*k, A(3)]) - [3/2 + 1/2*j + 2*k, 3/2*i + 3/2*k, j + k, 3*k] + [3, 3*i, 3/2 + 3/2*j, 3/2 + 3/2*i + 1/2*j + 1/2*k] """ - return basis_for_quaternion_lattice([b * g for b in self.basis() for g in gens], reverse=False) + return basis_for_quaternion_lattice([b * g for b in self.basis() for g in gens]) def _right_order_from_ideal_basis(self, basis): """ @@ -2030,12 +2030,12 @@ def _right_order_from_ideal_basis(self, basis): sage: A. = QuaternionAlgebra(17) sage: O = A.maximal_order() sage: basis = O._left_ideal_basis([1]); basis - [1/2 + 1/6*i + 1/3*k, 1/3*i + 2/3*k, 1/2*j + 1/2*k, k] + [1, 1/2 + 1/2*i, j, 1/3*i + 1/2*j + 1/6*k] sage: O._right_order_from_ideal_basis(basis) Order of Quaternion Algebra (-3, -17) with base ring Rational Field with basis (1/2 + 1/6*i + 1/3*k, 1/3*i + 2/3*k, 1/2*j + 1/2*k, k) sage: basis = O._left_ideal_basis([i*j - j]); basis - [17 + 17/3*i + 4/3*k, 34/3*i + 2/3*k, j + k, 2*k] + [34, 17 + 17*i, 2*j, 17 + 17/3*i + j + 1/3*k] sage: O._right_order_from_ideal_basis(basis) Order of Quaternion Algebra (-3, -17) with base ring Rational Field with basis (1/2 + 1/6*i + 1/3*k, 1/3*i + 2/3*k, 1/2*j + 1/2*k, k) """ @@ -2089,9 +2089,9 @@ def left_ideal(self, gens, check=True, *, is_basis=False): or a single generator:: sage: R.left_ideal([i+j]) - Fractional ideal (1/2 + 1/2*i + 1/2*j + 13/2*k, i + j, 6*j + 6*k, 12*k) + Fractional ideal (12, 6 + 6*i, i + j, 13/2 + 1/2*i + 1/2*j + 1/2*k) sage: R.left_ideal(i+j) - Fractional ideal (1/2 + 1/2*i + 1/2*j + 13/2*k, i + j, 6*j + 6*k, 12*k) + Fractional ideal (12, 6 + 6*i, i + j, 13/2 + 1/2*i + 1/2*j + 1/2*k) sage: R.left_ideal([2, 1+j]) == R*2 + R*(1+j) True """ @@ -2102,7 +2102,7 @@ def left_ideal(self, gens, check=True, *, is_basis=False): else: if gens in self.quaternion_algebra(): gens = [gens] - basis = tuple(basis_for_quaternion_lattice([b * g for b in self.basis() for g in gens], reverse=False)) + basis = tuple(basis_for_quaternion_lattice([b * g for b in self.basis() for g in gens])) check = False return QuaternionFractionalIdeal_rational(self.quaternion_algebra(), basis, left_order=self, check=check) @@ -2132,9 +2132,9 @@ def right_ideal(self, gens, check=True, *, is_basis=False): or a single generator:: sage: R.right_ideal([i+j]) - Fractional ideal (1/2 + 1/2*i + 1/2*j + 11/2*k, i + j, 6*j + 6*k, 12*k) + Fractional ideal (12, 6 + 6*i, i + j, 11/2 + 1/2*i + 1/2*j + 1/2*k) sage: R.right_ideal(i+j) - Fractional ideal (1/2 + 1/2*i + 1/2*j + 11/2*k, i + j, 6*j + 6*k, 12*k) + Fractional ideal (12, 6 + 6*i, i + j, 11/2 + 1/2*i + 1/2*j + 1/2*k) sage: R.right_ideal([2, 1+j]) == 2*R + (1+j)*R True """ @@ -2145,7 +2145,7 @@ def right_ideal(self, gens, check=True, *, is_basis=False): else: if gens in self.quaternion_algebra(): gens = [gens] - basis = tuple(basis_for_quaternion_lattice([g * b for b in self.basis() for g in gens], reverse=False)) + basis = tuple(basis_for_quaternion_lattice([g * b for b in self.basis() for g in gens])) check = False return QuaternionFractionalIdeal_rational(self.quaternion_algebra(), basis, right_order=self, check=check) @@ -2210,7 +2210,7 @@ def __mul__(self, other): sage: Q. = QuaternionAlgebra(-1,-11) sage: O = Q.maximal_order() sage: I = O*j; I - Fractional ideal (-11/2 + 1/2*j, -11/2*i + 1/2*k, -11, -11*i) + Fractional ideal (11, 11*i, 11/2 + 1/2*j, 11/2*i + 1/2*k) """ return self.unit_ideal() * other @@ -2346,11 +2346,13 @@ def isomorphism_to(self, other, *, conjugator=False, B=10): sage: iso = O0.isomorphism_to(O1) sage: iso Ring morphism: - From: Order of Quaternion Algebra (-1, -19) with base ring Rational Field with basis (1, i, 1/2*i + 1/2*j, 1/2 + 1/2*k) - To: Order of Quaternion Algebra (-1, -19) with base ring Rational Field with basis (1, 667*i, 1/2 + 9*i + 1/2*j, 222075/1334*i + 333/667*j + 1/1334*k) + From: Order of Quaternion Algebra (-1, -19) with base ring Rational Field + with basis (1, i, 1/2*i + 1/2*j, 1/2 + 1/2*k) + To: Order of Quaternion Algebra (-1, -19) with base ring Rational Field + with basis (1, 667*i, 1/2 + 9*i + 1/2*j, 222075/1334*i + 333/667*j + 1/1334*k) Defn: i |--> 629/667*i + 36/667*j - 36/667*k - j |--> 684/667*i - 648/667*j - 19/667*k - k |--> -684/667*i - 19/667*j - 648/667*k + j |--> -684/667*i + 648/667*j + 19/667*k + k |--> 684/667*i + 19/667*j + 648/667*k sage: iso(1) 1 sage: iso(i) @@ -2363,7 +2365,7 @@ def isomorphism_to(self, other, *, conjugator=False, B=10): :: sage: gamma = O0.isomorphism_to(O1, conjugator=True); gamma - -36*i - j + k + -36 + j + k sage: gamma in O0 True sage: gamma in O1 @@ -2410,7 +2412,7 @@ def isomorphism_to(self, other, *, conjugator=False, B=10): sage: Oconj = j.inverse() * O * j sage: Oconj = Quat.quaternion_order(Oconj.basis()) sage: O.isomorphism_to(Oconj, conjugator=True) - -j + j Test error cases:: @@ -2571,7 +2573,7 @@ def __init__(self, Q, basis, left_order=None, right_order=None, check=True): sage: R = QuaternionAlgebra(-11,-1).maximal_order() sage: R.right_ideal(R.basis()) - Fractional ideal (1/2 + 1/2*i, i, 1/2*j + 1/2*k, k) + Fractional ideal (1, 1/2 + 1/2*i, j, 1/2*j + 1/2*k) sage: R.right_ideal(tuple(R.basis()), check=False, is_basis=True) Fractional ideal (1/2 + 1/2*i, 1/2*j - 1/2*k, i, -k) @@ -2618,17 +2620,17 @@ def scale(self, alpha, left=False): sage: B = BrandtModule(5,37); I = B.right_ideals()[0] sage: i,j,k = B.quaternion_algebra().gens(); I - Fractional ideal (2 + 2*j + 106*k, i + 2*j + 105*k, 4*j + 64*k, 148*k) + Fractional ideal (4, 148*i, 2 + 106*i + 2*j, 2 + 147*i + k) sage: I.scale(i) - Fractional ideal (2*i + 212*j - 2*k, -2 + 210*j - 2*k, 128*j - 4*k, 296*j) + Fractional ideal (296, 4*i, 2 + 2*i + 2*j, 212 + 2*i + 2*k) sage: I.scale(i, left=True) - Fractional ideal (2*i - 212*j + 2*k, -2 - 210*j + 2*k, -128*j + 4*k, -296*j) + Fractional ideal (296, 4*i, 294 + 2*i + 2*j, 84 + 2*i + 2*k) sage: I.scale(i, left=False) - Fractional ideal (2*i + 212*j - 2*k, -2 + 210*j - 2*k, 128*j - 4*k, 296*j) + Fractional ideal (296, 4*i, 2 + 2*i + 2*j, 212 + 2*i + 2*k) sage: i * I.gens()[0] - 2*i - 212*j + 2*k + 4*i sage: I.gens()[0] * i - 2*i + 212*j - 2*k + 4*i TESTS: @@ -2656,9 +2658,9 @@ def scale(self, alpha, left=False): Q = self.quaternion_algebra() alpha = Q(alpha) if left: - gens = [alpha * b for b in self.basis()] + gens = basis_for_quaternion_lattice([alpha * b for b in self.basis()]) else: - gens = [b * alpha for b in self.basis()] + gens = basis_for_quaternion_lattice([b * alpha for b in self.basis()]) left_order = self.__left_order if alpha in QQ or not left else None right_order = self.__right_order if alpha in QQ or left else None return Q.ideal(gens, check=False, @@ -2673,7 +2675,7 @@ def quaternion_algebra(self): EXAMPLES:: sage: I = BrandtModule(3, 5).right_ideals()[1]; I - Fractional ideal (2 + 6*j + 4*k, 2*i + 4*j + 34*k, 8*j + 32*k, 40*k) + Fractional ideal (8, 40*i, 6 + 28*i + 2*j, 4 + 18*i + 2*k) sage: I.quaternion_algebra() Quaternion Algebra (-1, -3) with base ring Rational Field """ @@ -2781,7 +2783,7 @@ def right_order(self): EXAMPLES:: sage: I = BrandtModule(389).right_ideals()[1]; I - Fractional ideal (2 + 6*j + 2*k, i + 2*j + k, 8*j, 8*k) + Fractional ideal (8, 8*i, 2 + 6*i + 2*j, 6 + 3*i + k) sage: I.right_order() Order of Quaternion Algebra (-2, -389) with base ring Rational Field with basis (1/2 + 1/2*j + 1/2*k, 1/4*i + 1/2*j + 1/4*k, j, k) @@ -2818,7 +2820,7 @@ def __repr__(self): sage: type(I) sage: I.__repr__() - 'Fractional ideal (2 + 6*j + 4*k, 2*i + 4*j + 2*k, 8*j, 8*k)' + 'Fractional ideal (8, 8*i, 6 + 4*i + 2*j, 4 + 2*i + 2*k)' """ return 'Fractional ideal %s' % (self.gens(),) @@ -2956,9 +2958,9 @@ def reduced_basis(self): sage: B = BrandtModule(2,37); I = B.right_ideals()[0] sage: I - Fractional ideal (2 + 2*i + 2*j + 2*k, 4*i + 108*k, 4*j + 44*k, 148*k) + Fractional ideal (4, 148*i, 108*i + 4*j, 2 + 2*i + 2*j + 2*k) sage: I.reduced_basis() - (2 + 2*i + 2*j + 2*k, 4, -2 - 2*i - 14*j + 14*k, -16*i + 12*k) + (4, 2 + 2*i + 2*j + 2*k, 2 - 14*i + 14*j - 2*k, 2 - 2*i - 14*j + 14*k) sage: l = I.reduced_basis() sage: assert all(l[i].reduced_norm() <= l[i+1].reduced_norm() for i in range(len(l) - 1)) @@ -2990,7 +2992,7 @@ def theta_series_vector(self, B): EXAMPLES:: sage: I = BrandtModule(37).right_ideals()[1]; I - Fractional ideal (2 + 6*j + 2*k, i + 2*j + k, 8*j, 8*k) + Fractional ideal (8, 8*i, 2 + 6*i + 2*j, 6 + 3*i + k) sage: I.theta_series_vector(5) (1, 0, 2, 2, 6) sage: I.theta_series_vector(10) @@ -3022,10 +3024,10 @@ def quadratic_form(self): sage: I = BrandtModule(11).right_ideals()[1] sage: Q = I.quadratic_form(); Q Quadratic form in 4 variables over Rational Field with coefficients: - [ 18 22 33 22 ] - [ * 7 22 11 ] - [ * * 22 0 ] - [ * * * 22 ] + [ 2 0 3 2 ] + [ * 2 2 1 ] + [ * * 3 2 ] + [ * * * 2 ] sage: Q.theta_series(10) 1 + 12*q^2 + 12*q^3 + 12*q^4 + 12*q^5 + 24*q^6 + 24*q^7 + 36*q^8 + 36*q^9 + O(q^10) sage: I.theta_series(10) @@ -3055,7 +3057,7 @@ def minimal_element(self): sage: O = Quat.maximal_order(); O Order of Quaternion Algebra (-3, -101) with base ring Rational Field with basis (1/2 + 1/2*i, 1/2*j - 1/2*k, -1/3*i + 1/3*k, -k) sage: (O * 5).minimal_element() - 5/2 + 5/2*i + 5 sage: alpha = 1/2 + 1/6*i + j + 55/3*k sage: I = O*141 + O*alpha; I.norm() 141 @@ -3091,7 +3093,7 @@ def theta_series(self, B, var='q'): EXAMPLES:: sage: I = BrandtModule(11).right_ideals()[1]; I - Fractional ideal (2 + 6*j + 4*k, 2*i + 4*j + 2*k, 8*j, 8*k) + Fractional ideal (8, 8*i, 6 + 4*i + 2*j, 4 + 2*i + 2*k) sage: I.norm() 32 sage: I.theta_series(5) @@ -3126,12 +3128,12 @@ def gram_matrix(self): EXAMPLES:: sage: I = BrandtModule(3,5).right_ideals()[1]; I - Fractional ideal (2 + 6*j + 4*k, 2*i + 4*j + 34*k, 8*j + 32*k, 40*k) + Fractional ideal (8, 40*i, 6 + 28*i + 2*j, 4 + 18*i + 2*k) sage: I.gram_matrix() - [ 640 1920 2112 1920] - [ 1920 14080 13440 16320] - [ 2112 13440 13056 15360] - [ 1920 16320 15360 19200] + [ 256 0 192 128] + [ 0 6400 4480 2880] + [ 192 4480 3328 2112] + [ 128 2880 2112 1408] """ A = self.gens() two = QQ(2) @@ -3187,7 +3189,7 @@ def conjugate(self): EXAMPLES:: sage: I = BrandtModule(3,5).right_ideals()[1]; I - Fractional ideal (2 + 6*j + 4*k, 2*i + 4*j + 34*k, 8*j + 32*k, 40*k) + Fractional ideal (8, 40*i, 6 + 28*i + 2*j, 4 + 18*i + 2*k) sage: I.conjugate() Fractional ideal (2 + 2*j + 28*k, 2*i + 4*j + 34*k, 8*j + 32*k, 40*k) """ @@ -3206,13 +3208,13 @@ def __mul__(self, right): EXAMPLES:: sage: I = BrandtModule(3,5).right_ideals()[1]; I - Fractional ideal (2 + 6*j + 4*k, 2*i + 4*j + 34*k, 8*j + 32*k, 40*k) + Fractional ideal (8, 40*i, 6 + 28*i + 2*j, 4 + 18*i + 2*k) sage: I*I - Fractional ideal (8 + 24*j + 16*k, 8*i + 16*j + 136*k, 32*j + 128*k, 160*k) + Fractional ideal (32, 160*i, 24 + 112*i + 8*j, 16 + 72*i + 8*k) sage: I*I.conjugate() - Fractional ideal (16 + 16*j + 224*k, 8*i + 16*j + 136*k, 32*j + 128*k, 320*k) + Fractional ideal (32, 320*i, 16 + 224*i + 16*j, 16 + 232*i + 8*k) sage: I.multiply_by_conjugate(I) - Fractional ideal (16 + 16*j + 224*k, 8*i + 16*j + 136*k, 32*j + 128*k, 320*k) + Fractional ideal (32, 320*i, 16 + 224*i + 16*j, 16 + 232*i + 8*k) """ if isinstance(right, QuaternionOrder): right = right.unit_ideal() @@ -3222,7 +3224,7 @@ def __mul__(self, right): # if self.__right_order == right.__left_order: # left_order = self.__left_order # right_order = right.__right_order - basis = tuple(basis_for_quaternion_lattice(gens, reverse=False)) + basis = tuple(basis_for_quaternion_lattice(gens)) A = self.quaternion_algebra() return A.ideal(basis, check=False) @@ -3233,9 +3235,9 @@ def __add__(self, other): EXAMPLES:: sage: I = BrandtModule(11,5).right_ideals()[1]; I - Fractional ideal (2 + 2*j + 20*k, 2*i + 4*j + 6*k, 8*j, 40*k) + Fractional ideal (8, 40*i, 2 + 20*i + 2*j, 4 + 14*i + 2*k) sage: J = BrandtModule(11,5).right_ideals()[2]; J - Fractional ideal (2 + 6*j + 20*k, 2*i + 4*j + 26*k, 8*j, 40*k) + Fractional ideal (8, 40*i, 6 + 20*i + 2*j, 4 + 34*i + 2*k) sage: I + J Fractional ideal (2 + 2*j, 2*i + 6*k, 4*j, 20*k) """ @@ -3276,7 +3278,7 @@ def free_module(self): sage: X = BrandtModule(3,5).right_ideals() sage: X[0] - Fractional ideal (2 + 2*j + 8*k, 2*i + 18*k, 4*j + 16*k, 20*k) + Fractional ideal (4, 20*i, 2 + 8*i + 2*j, 18*i + 2*k) sage: X[0].free_module() Free module of degree 4 and rank 4 over Integer Ring Echelon basis matrix: @@ -3356,13 +3358,13 @@ def multiply_by_conjugate(self, J): sage: R = BrandtModule(3,5).right_ideals() sage: R[0].multiply_by_conjugate(R[1]) - Fractional ideal (8 + 8*j + 112*k, 8*i + 16*j + 136*k, 32*j + 128*k, 160*k) + Fractional ideal (32, 160*i, 8 + 112*i + 8*j, 16 + 72*i + 8*k) sage: R[0]*R[1].conjugate() - Fractional ideal (8 + 8*j + 112*k, 8*i + 16*j + 136*k, 32*j + 128*k, 160*k) + Fractional ideal (32, 160*i, 8 + 112*i + 8*j, 16 + 72*i + 8*k) """ Jbar = [b.conjugate() for b in J.basis()] gens = [a * b for a in self.basis() for b in Jbar] - basis = tuple(basis_for_quaternion_lattice(gens, reverse=False)) + basis = tuple(basis_for_quaternion_lattice(gens)) R = self.quaternion_algebra() return R.ideal(basis, check=False) @@ -3392,7 +3394,7 @@ def pushforward(self, J, side=None): sage: I1.left_order() == I2.left_order() True sage: I1.pushforward(I2, side='left') - Fractional ideal (1/2 + 3/2*j + 5*k, 1/10*i + 2*j + 39/10*k, 3*j, 15*k) + Fractional ideal (3, 15*i, 3/2 + 10*i + 1/2*j, 1 + 9/10*i + 1/10*k) TESTS:: @@ -3404,11 +3406,11 @@ def pushforward(self, J, side=None): ... ValueError: self and J have same left and right orders, side of pushforward must be specified sage: O0.unit_ideal().pushforward(O0.unit_ideal(), "left") - Fractional ideal (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k) + Fractional ideal (1, i, 1/2 + 1/2*j, 1/2*i + 1/2*k) sage: I1 = B.ideal([1/2 + 3/2*j + 2*k, 1/2*i + j + 3/2*k, 3*j, 3*k]) sage: I2 = B.ideal([1/2 + 9/2*j, 1/2*i + 9/2*k, 5*j, 5*k]) sage: I1.pushforward(I2) - Fractional ideal (1/2 + 3/2*j + 5*k, 1/10*i + 2*j + 39/10*k, 3*j, 15*k) + Fractional ideal (3, 15*i, 3/2 + 10*i + 1/2*j, 1 + 9/10*i + 1/10*k) sage: I1.pushforward(I2, side='right') Traceback (most recent call last): ... @@ -3648,7 +3650,7 @@ def is_right_equivalent(self, J, B=10, certificate=False): sage: OO = R[0].left_order() sage: S = OO.right_ideal([3*a for a in R[0].basis()]) sage: R[0].is_right_equivalent(S, certificate=True) - (True, -1/3) + (True, 1/3) sage: -1/3*S == R[0] True @@ -3785,39 +3787,39 @@ def cyclic_right_subideals(self, p, alpha=None): sage: B = BrandtModule(2,37); I = B.right_ideals()[0] sage: I.cyclic_right_subideals(3) - [Fractional ideal (2 + 2*i + 10*j + 90*k, 4*i + 4*j + 152*k, 12*j + 132*k, 444*k), - Fractional ideal (2 + 2*i + 2*j + 150*k, 4*i + 8*j + 196*k, 12*j + 132*k, 444*k), - Fractional ideal (2 + 2*i + 6*j + 194*k, 4*i + 8*j + 344*k, 12*j + 132*k, 444*k), - Fractional ideal (2 + 2*i + 6*j + 46*k, 4*i + 4*j + 4*k, 12*j + 132*k, 444*k)] + [Fractional ideal (12, 444*i, 8 + 404*i + 4*j, 2 + 150*i + 2*j + 2*k), + Fractional ideal (12, 444*i, 4 + 256*i + 4*j, 10 + 150*i + 2*j + 2*k), + Fractional ideal (12, 444*i, 8 + 256*i + 4*j, 6 + 298*i + 2*j + 2*k), + Fractional ideal (12, 444*i, 4 + 404*i + 4*j, 6 + 2*i + 2*j + 2*k)] sage: B = BrandtModule(5,389); I = B.right_ideals()[0] sage: C = I.cyclic_right_subideals(3); C - [Fractional ideal (2 + 10*j + 546*k, i + 6*j + 133*k, 12*j + 3456*k, 4668*k), - Fractional ideal (2 + 2*j + 2910*k, i + 6*j + 3245*k, 12*j + 3456*k, 4668*k), - Fractional ideal (2 + i + 2295*k, 3*i + 2*j + 3571*k, 4*j + 2708*k, 4668*k), - Fractional ideal (2 + 2*i + 2*j + 4388*k, 3*i + 2*j + 2015*k, 4*j + 4264*k, 4668*k)] + [Fractional ideal (12, 4668*i, 10 + 3426*i + 2*j, 6 + 379*i + k), + Fractional ideal (12, 4668*i, 2 + 3426*i + 2*j, 6 + 3491*i + k), + Fractional ideal (12, 4 + 1556*i, 6 + 942*i + 6*j, 693*i + 2*j + k), + Fractional ideal (12, 8 + 1556*i, 6 + 942*i + 6*j, 2 + 1007*i + 4*j + k)] sage: [(I.free_module()/J.free_module()).invariants() for J in C] [(3, 3), (3, 3), (3, 3), (3, 3)] sage: I.scale(3).cyclic_right_subideals(3) - [Fractional ideal (6 + 30*j + 1638*k, 3*i + 18*j + 399*k, 36*j + 10368*k, 14004*k), - Fractional ideal (6 + 6*j + 8730*k, 3*i + 18*j + 9735*k, 36*j + 10368*k, 14004*k), - Fractional ideal (6 + 3*i + 6885*k, 9*i + 6*j + 10713*k, 12*j + 8124*k, 14004*k), - Fractional ideal (6 + 6*i + 6*j + 13164*k, 9*i + 6*j + 6045*k, 12*j + 12792*k, 14004*k)] + [Fractional ideal (36, 14004*i, 30 + 10278*i + 6*j, 18 + 1137*i + 3*k), + Fractional ideal (36, 14004*i, 6 + 10278*i + 6*j, 18 + 10473*i + 3*k), + Fractional ideal (36, 12 + 4668*i, 18 + 2826*i + 18*j, 2079*i + 6*j + 3*k), + Fractional ideal (36, 24 + 4668*i, 18 + 2826*i + 18*j, 6 + 3021*i + 12*j + 3*k)] sage: C = I.scale(1/9).cyclic_right_subideals(3); C - [Fractional ideal (2/9 + 10/9*j + 182/3*k, 1/9*i + 2/3*j + 133/9*k, 4/3*j + 384*k, 1556/3*k), - Fractional ideal (2/9 + 2/9*j + 970/3*k, 1/9*i + 2/3*j + 3245/9*k, 4/3*j + 384*k, 1556/3*k), - Fractional ideal (2/9 + 1/9*i + 255*k, 1/3*i + 2/9*j + 3571/9*k, 4/9*j + 2708/9*k, 1556/3*k), - Fractional ideal (2/9 + 2/9*i + 2/9*j + 4388/9*k, 1/3*i + 2/9*j + 2015/9*k, 4/9*j + 4264/9*k, 1556/3*k)] + [Fractional ideal (4/3, 1556/3*i, 10/9 + 1142/3*i + 2/9*j, 2/3 + 379/9*i + 1/9*k), + Fractional ideal (4/3, 1556/3*i, 2/9 + 1142/3*i + 2/9*j, 2/3 + 3491/9*i + 1/9*k), + Fractional ideal (4/3, 4/9 + 1556/9*i, 2/3 + 314/3*i + 2/3*j, 77*i + 2/9*j + 1/9*k), + Fractional ideal (4/3, 8/9 + 1556/9*i, 2/3 + 314/3*i + 2/3*j, 2/9 + 1007/9*i + 4/9*j + 1/9*k)] sage: [(I.scale(1/9).free_module()/J.free_module()).invariants() for J in C] [(3, 3), (3, 3), (3, 3), (3, 3)] sage: Q. = QuaternionAlgebra(-2,-5) sage: I = Q.ideal([Q(1),i,j,k]) sage: I.cyclic_right_subideals(3) - [Fractional ideal (1 + 2*j, i + k, 3*j, 3*k), - Fractional ideal (1 + j, i + 2*k, 3*j, 3*k), - Fractional ideal (1 + 2*i, 3*i, j + 2*k, 3*k), - Fractional ideal (1 + i, 3*i, j + k, 3*k)] + [Fractional ideal (3, 3*i, 2 + j, i + k), + Fractional ideal (3, 3*i, 1 + j, 2*i + k), + Fractional ideal (3, 2 + i, 3*j, 2*j + k), + Fractional ideal (3, 1 + i, 3*j, j + k)] The general algorithm is not yet implemented here:: @@ -3829,17 +3831,18 @@ def cyclic_right_subideals(self, p, alpha=None): """ R = self.right_order() Q = self.quaternion_algebra() + basis = basis_for_quaternion_lattice(self.basis(), reverse=False) f = Q.modp_splitting_map(p) if alpha is not None: alpha = f(alpha) W = GF(p)**4 try: - A = W.span_of_basis([W(f(a).list()) for a in self.basis()]) + A = W.span_of_basis([W(f(a).list()) for a in basis]) scale = 1 - IB = self.basis_matrix() + IB = matrix(map(list, basis)) except (ValueError, ZeroDivisionError): # try rescaling the ideal. - B, d = self.basis_matrix()._clear_denom() + B, d = matrix(map(list, basis))._clear_denom() g = gcd(B.list()) IB = B / g scale = g / d @@ -3851,7 +3854,7 @@ def cyclic_right_subideals(self, p, alpha=None): # However, I haven't implemented that algorithm yet. raise NotImplementedError("general algorithm not implemented (%s)" % msg) - Ai = A.basis_matrix()**(-1) + Ai = ~A.basis_matrix() AiB = Ai.change_ring(QQ) * IB # Do not care about the denominator since we're really working in I/p*I. @@ -3942,7 +3945,7 @@ def primitive_decomposition(self): sage: Jequiv*g == J True sage: Jequiv, g - (Fractional ideal (1/2 + 1/2*i + 7/2*j + 13/2*k, i + 3*k, 5*j + 5*k, 10*k), 7) + (Fractional ideal (10, 5 + 5*i, 3 + j, 13/2 + 7/2*i + 1/2*j + 1/2*k), 7) TESTS: @@ -4004,7 +4007,7 @@ def is_primitive(self) -> bool: ####################################################################### -def basis_for_quaternion_lattice(gens, reverse=None): +def basis_for_quaternion_lattice(gens, reverse=True): r""" Return a basis for the `\ZZ`-lattice in a quaternion algebra spanned by the given gens. @@ -4014,26 +4017,20 @@ def basis_for_quaternion_lattice(gens, reverse=None): - ``gens`` -- list of elements of a single quaternion algebra - ``reverse`` -- when computing the HNF do it on the basis - `(k,j,i,1)` instead of `(1,i,j,k)`; this ensures - that if ``gens`` are the generators for an order, - the first returned basis vector is 1 + `(k,j,i,1)` instead of `(1,i,j,k)`; this ensures that if + ``gens`` are the generators for a fractional ideal (in + particular, an order), the first returned basis vector + equals the norm of the ideal (in case of an order, `1`) EXAMPLES:: sage: from sage.algebras.quatalg.quaternion_algebra import basis_for_quaternion_lattice sage: A. = QuaternionAlgebra(-1,-7) sage: basis_for_quaternion_lattice([i+j, i-j, 2*k, A(1/3)]) - doctest:warning ... DeprecationWarning: ... - [1/3, i + j, 2*j, 2*k] - + [1/3, 2*i, i + j, 2*k] sage: basis_for_quaternion_lattice([A(1),i,j,k]) [1, i, j, k] """ - if reverse is None: - from sage.misc.superseded import deprecation - deprecation(34880, 'The default value for the "reverse" argument to basis_for_quaternion_lattice() will' - ' change from False to True. Pass the argument explicitly to silence this warning.') - reverse = False if not gens: return [] Z, d = quaternion_algebra_cython.integral_matrix_and_denom_from_rational_quaternions(gens, reverse) diff --git a/src/sage/arith/misc.py b/src/sage/arith/misc.py index b7f60bc4251..745d5fcbbe7 100644 --- a/src/sage/arith/misc.py +++ b/src/sage/arith/misc.py @@ -6227,8 +6227,8 @@ def dedekind_sum(p, q, algorithm='default'): return flint_dedekind_sum(p, q) if algorithm == 'pari': - import sage.interfaces.gp - x = sage.interfaces.gp.gp('sumdedekind(%s,%s)' % (p, q)) + from sage.libs.pari import pari + x = pari.sumdedekind(p, q) return Rational(x) raise ValueError('unknown algorithm') @@ -6374,3 +6374,75 @@ 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``, + return a :class:`~sage.structure.factorization.Factorization` object + corresponding to the largest divisor of ``x`` that splits completely + over ``base``. + + The factor base can be specified in the following ways: + + - A sequence of elements. + + - A :class:`~sage.rings.generic.ProductTree` built from such a sequence. + (Caching the tree in the caller will speed things up if this function + is called multiple times with the same factor base.) + + EXAMPLES:: + + sage: from sage.arith.misc import smooth_part + sage: from sage.rings.generic import ProductTree + sage: smooth_part(10^77+1, primes(1000)) + 11^2 * 23 * 463 + sage: tree = ProductTree(primes(1000)) + sage: smooth_part(10^77+1, tree) + 11^2 * 23 * 463 + sage: smooth_part(10^99+1, tree) + 7 * 11^2 * 13 * 19 * 23 + """ + from sage.rings.generic import ProductTree + if isinstance(base, ProductTree): + tree = base + else: + tree = ProductTree(base) + fs = [] + rems = tree.remainders(x) + for j,(p,r) in enumerate(zip(tree, rems)): + if not r: + x //= p + v = 1 + while True: + y,r = divmod(x, p) + if r: + break + x = y + v += 1 + fs.append((p,v)) + 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``, + return the largest divisor of ``x`` that is not divisible by any element + of ``base``. + + ALGORITHM: Divide `x` by the :func:`smooth_part`. + + EXAMPLES:: + + sage: from sage.arith.misc import coprime_part, smooth_part + sage: from sage.rings.generic import ProductTree + sage: coprime_part(10^77+1, primes(10000)) + 2159827213801295896328509719222460043196544298056155507343412527 + sage: tree = ProductTree(primes(10000)) + sage: coprime_part(10^55+1, tree) + 6426667196963538873896485804232411 + sage: coprime_part(10^55+1, tree).factor() + 20163494891 * 318727841165674579776721 + sage: prod(smooth_part(10^55+1, tree)) * coprime_part(10^55+1, tree) + 10000000000000000000000000000000000000000000000000000001 + """ + return x // prod(smooth_part(x, base)) diff --git a/src/sage/categories/category_cy_helper.pyx b/src/sage/categories/category_cy_helper.pyx index 28600da136f..ca29f3f9042 100644 --- a/src/sage/categories/category_cy_helper.pyx +++ b/src/sage/categories/category_cy_helper.pyx @@ -8,15 +8,15 @@ AUTHOR: - Simon King (initial version) """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2014 Simon 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/ +# **************************************************************************** ####################################### # Sorting diff --git a/src/sage/categories/category_singleton.pyx b/src/sage/categories/category_singleton.pyx index ae38bdd2462..c606428486c 100644 --- a/src/sage/categories/category_singleton.pyx +++ b/src/sage/categories/category_singleton.pyx @@ -62,11 +62,11 @@ cdef class Category_contains_method_by_parent_class: TESTS: - The following used to segfault in a preliminary version of the - code:: + The following used to segfault in a preliminary version of the + code:: - sage: None in Rings() - False + sage: None in Rings() + False """ if x is None: return False @@ -76,7 +76,7 @@ cdef class Category_contains_method_by_parent_class: return PyType_IsSubtype(((y._category or y.category()).parent_class), self._parent_class_of_category) except AttributeError: return False - except TypeError: # this is for objects that aren't CategoryObjects + except TypeError: # this is for objects that are not CategoryObjects try: return PyType_IsSubtype((x.category().parent_class), self._parent_class_of_category) except AttributeError: @@ -293,7 +293,8 @@ class Category_singleton(Category): sage: Category_singleton() Traceback (most recent call last): ... - AssertionError: is not a direct subclass of + AssertionError: is not a direct subclass of + Instantiating a subclass of a subclass of :class:`Category_singleton` also triggers an assertion error:: diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index d5bd98633a3..766ec9b64cb 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1908,7 +1908,7 @@ def _base_category_class_and_axiom(cls): sage: CommutativeRings()._base_category_class_and_axiom (, 'Commutative') sage: CommutativeRings()._base_category_class_and_axiom_origin - 'deduced by base_category_class_and_axiom' + 'set by __classget__' ``Sets.Infinite`` is a nested class, so the attribute is set by :meth:`CategoryWithAxiom.__classget__` the first time diff --git a/src/sage/categories/coxeter_groups.py b/src/sage/categories/coxeter_groups.py index 9f71cfdcf90..fe663d6eb97 100644 --- a/src/sage/categories/coxeter_groups.py +++ b/src/sage/categories/coxeter_groups.py @@ -2671,7 +2671,7 @@ def bruhat_le(self, other): reduced word for ``other`` contains a reduced word for ``self`` as subword. See Stembridge, A short derivation of the Möbius function for the Bruhat order. J. Algebraic - Combin. 25 (2007), no. 2, 141--148, Proposition 1.1. + Combinatoric 25 (2007), no. 2, 141--148, Proposition 1.1. Complexity: `O(l * c)`, where `l` is the minimum of the lengths of `u` and of `v`, and `c` is the cost of the low diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 0ed2e0b5994..2df5d054dd0 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -274,7 +274,7 @@ def bhz_poset(self): was defined in [BHZ2005]_. This partial order is not a lattice, as there is no unique - maximal element. It can be succintly defined as follows. + maximal element. It can be succinctly defined as follows. Let `u` and `v` be two elements of the Coxeter group `W`. Let `S(u)` be the support of `u`. Then `u \leq v` if and only diff --git a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py index 270ea045898..6f27e3fa33d 100644 --- a/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py +++ b/src/sage/categories/finite_dimensional_lie_algebras_with_basis.py @@ -2430,7 +2430,7 @@ def faithful_representation(self, algorithm=None): General case - * ``'generic'`` -- generic algortihm (only implemented currently + * ``'generic'`` -- generic algorithm (only implemented currently for positive characteristic) Note that the algorithm for any more generic cases can be used diff --git a/src/sage/categories/map.pxd b/src/sage/categories/map.pxd index 6f3b3bb8a91..8738d4cf042 100644 --- a/src/sage/categories/map.pxd +++ b/src/sage/categories/map.pxd @@ -16,9 +16,9 @@ cdef class Map(Element): cpdef Element _call_(self, x) cpdef Element _call_with_args(self, x, args=*, kwds=*) - cdef public domain # will be either a weakref or a constant map - cdef public codomain # will be a constant map - cdef Parent _codomain # for accessing the codomain directly + cdef public domain # will be either a weakref or a constant map + cdef public codomain # will be a constant map + cdef Parent _codomain # for accessing the codomain directly cdef object _category_for # category in which this is a morphism cdef public _repr_type_str diff --git a/src/sage/categories/map.pyx b/src/sage/categories/map.pyx index 3ee42fc0157..aaa52b56ad1 100644 --- a/src/sage/categories/map.pyx +++ b/src/sage/categories/map.pyx @@ -183,7 +183,7 @@ cdef class Map(Element): cdef Map out = Element.__copy__(self) # Element.__copy__ updates the __dict__, but not the slots. # Let's do this now, but with strong references. - out._parent = self.parent() # self._parent might be None + out._parent = self.parent() # self._parent might be None out._update_slots(self._extra_slots()) return out @@ -462,10 +462,10 @@ cdef class Map(Element): Return a dict with attributes to pickle and copy this map. """ return dict( - _domain=self.domain(), - _codomain=self._codomain, - _is_coercion=self._is_coercion, - _repr_type_str=self._repr_type_str) + _domain=self.domain(), + _codomain=self._codomain, + _is_coercion=self._is_coercion, + _repr_type_str=self._repr_type_str) def _extra_slots_test(self): """ @@ -801,7 +801,7 @@ cdef class Map(Element): """ P = parent(x) cdef Parent D = self.domain() - if P is D: # we certainly want to call _call_/with_args + if P is D: # we certainly want to call _call_/with_args if not args and not kwds: return self._call_(x) return self._call_with_args(x, args, kwds) @@ -1215,7 +1215,7 @@ cdef class Map(Element): def is_surjective(self): """ - Tells whether the map is surjective (not implemented in the base class). + Tell whether the map is surjective (not implemented in the base class). TESTS:: diff --git a/src/sage/categories/primer.py b/src/sage/categories/primer.py index 6afdc8f31d9..dbae2b41049 100644 --- a/src/sage/categories/primer.py +++ b/src/sage/categories/primer.py @@ -58,7 +58,7 @@ - Thousands of different kinds of objects (classes): Integers, polynomials, matrices, groups, number fields, elliptic - curves, permutations, morphisms, languages, ... and a few racoons ... + curves, permutations, morphisms, languages, ... and a few raccoons ... - Tens of thousands methods and functions: @@ -1277,7 +1277,7 @@ class naming and introspection. Sage currently works around the The meaning of each axiom is described in the documentation of the corresponding method, which can be obtained as usual by -instrospection:: +introspection:: sage: C = Groups() sage: C.Finite? # not tested diff --git a/src/sage/categories/pushout.py b/src/sage/categories/pushout.py index 0b5f0a85cdc..e3d2d3f796d 100644 --- a/src/sage/categories/pushout.py +++ b/src/sage/categories/pushout.py @@ -535,7 +535,7 @@ def __ne__(self, other): def __mul__(self, other): """ - Compose construction functors to a composit construction functor, unless one of them is the identity. + Compose construction functors to a composite construction functor, unless one of them is the identity. .. NOTE:: @@ -688,7 +688,7 @@ def __ne__(self, other): def __mul__(self, other): """ - Compose construction functors to a composit construction functor, unless one of them is the identity. + Compose construction functors to a composite construction functor, unless one of them is the identity. .. NOTE:: @@ -1420,10 +1420,10 @@ def __mul__(self, other): if x.count('_') == 1: g, n = x.split('_') if n.isdigit(): - if g.isalnum(): # we can interprete x in any InfinitePolynomialRing - if g in self._gens: # we can interprete x in self, hence, we will not use it as a variable anymore. + if g.isalnum(): # we can interpret x in any InfinitePolynomialRing + if g in self._gens: # we can interpret x in self, hence, we will not use it as a variable anymore. RemainingVars.pop(RemainingVars.index(x)) - IsOverlap = True # some variables of other can be interpreted in self. + IsOverlap = True # some variables of other can be interpreted in self. if OverlappingVars: # Is OverlappingVars in the right order? g0, n0 = OverlappingVars[-1].split('_') diff --git a/src/sage/categories/realizations.py b/src/sage/categories/realizations.py index 762bb277e51..26d5125f9e7 100644 --- a/src/sage/categories/realizations.py +++ b/src/sage/categories/realizations.py @@ -27,7 +27,7 @@ class RealizationsCategory(RegressiveCovariantConstructionCategory): """ An abstract base class for all categories of realizations category. - Relization are implemented as + Realization are implemented as :class:`~sage.categories.covariant_functorial_construction.RegressiveCovariantConstructionCategory`. See there for the documentation of how the various bindings such as ``Sets().Realizations()`` and ``P.Realizations()``, where ``P`` diff --git a/src/sage/categories/sets_cat.py b/src/sage/categories/sets_cat.py index 2d58d1c6514..9d63ac2fa30 100644 --- a/src/sage/categories/sets_cat.py +++ b/src/sage/categories/sets_cat.py @@ -2802,7 +2802,7 @@ def _register_realization(self, realization): sage: R in A.realizations() # indirect doctest True - Note: the test above uses ``QQ[x]`` to not interfer + Note: the test above uses ``QQ[x]`` to not interfere with other tests. """ assert realization.realization_of() is self diff --git a/src/sage/coding/bch_code.py b/src/sage/coding/bch_code.py index aeecdc01318..ebd9d7bc3b4 100644 --- a/src/sage/coding/bch_code.py +++ b/src/sage/coding/bch_code.py @@ -35,6 +35,7 @@ from .grs_code import GeneralizedReedSolomonCode from .decoder import Decoder + class BCHCode(CyclicCode): r""" Representation of a BCH code seen as a cyclic code. diff --git a/src/sage/coding/channel.py b/src/sage/coding/channel.py index 0b584c3c117..e297a6fe68e 100644 --- a/src/sage/coding/channel.py +++ b/src/sage/coding/channel.py @@ -95,6 +95,7 @@ def random_error_vector(n, F, error_positions): vect[i] = F._random_nonzero_element() return vector(F, vect) + def format_interval(t): r""" Return a formatted string representation of ``t``. diff --git a/src/sage/coding/code_bounds.py b/src/sage/coding/code_bounds.py index a4771995a47..99400522265 100644 --- a/src/sage/coding/code_bounds.py +++ b/src/sage/coding/code_bounds.py @@ -360,6 +360,7 @@ def gilbert_lower_bound(n, q, d): ans = q**n/volume_hamming(n,q,d-1) return ans + def plotkin_upper_bound(n,q,d, algorithm=None): r""" Return the Plotkin upper bound. @@ -398,6 +399,7 @@ def plotkin_upper_bound(n,q,d, algorithm=None): fact = int(fact) + 1 return int(d/( d - t * fact)) * q**(n - fact) + def griesmer_upper_bound(n,q,d,algorithm=None): r""" Return the Griesmer upper bound. diff --git a/src/sage/coding/code_constructions.py b/src/sage/coding/code_constructions.py index 5767872b3e2..be1c087c280 100644 --- a/src/sage/coding/code_constructions.py +++ b/src/sage/coding/code_constructions.py @@ -178,6 +178,7 @@ def _is_a_splitting(S1, S2, n, return_automorphism=False): else: return False + def _lift2smallest_field(a): """ INPUT: @@ -327,6 +328,7 @@ def walsh_matrix(m0): ##################### main constructions ##################### + def DuadicCodeEvenPair(F,S1,S2): r""" Construct the "even pair" of duadic codes associated to the @@ -376,6 +378,7 @@ def DuadicCodeEvenPair(F,S1,S2): C2 = CyclicCode(length=n, generator_pol=gg2) return C1,C2 + def DuadicCodeOddPair(F,S1,S2): """ Construct the "odd pair" of duadic codes associated to the @@ -431,6 +434,7 @@ def DuadicCodeOddPair(F,S1,S2): C2 = CyclicCode(length=n, generator_pol=gg2) return C1,C2 + def ExtendedQuadraticResidueCode(n,F): r""" The extended quadratic residue code (or XQR code) is obtained from @@ -471,6 +475,7 @@ def ExtendedQuadraticResidueCode(n,F): C = QuadraticResidueCodeOddPair(n,F)[0] return C.extended_code() + def from_parity_check_matrix(H): r""" Return the linear code that has ``H`` as a parity check matrix. @@ -494,6 +499,7 @@ def from_parity_check_matrix(H): Cd = LinearCode(H) return Cd.dual_code() + def QuadraticResidueCode(n,F): r""" A quadratic residue code (or QR code) is a cyclic code whose @@ -537,6 +543,7 @@ def QuadraticResidueCode(n,F): """ return QuadraticResidueCodeOddPair(n,F)[0] + def QuadraticResidueCodeEvenPair(n,F): r""" Quadratic residue codes of a given odd prime length and base ring @@ -688,6 +695,7 @@ def random_linear_code(F, length, dimension): if G.rank() == dimension: return LinearCode(G) + def ToricCode(P,F): r""" Let `P` denote a list of lattice points in diff --git a/src/sage/coding/decoder.py b/src/sage/coding/decoder.py index d5b112b821d..05089583389 100644 --- a/src/sage/coding/decoder.py +++ b/src/sage/coding/decoder.py @@ -23,6 +23,7 @@ from sage.misc.abstract_method import abstract_method from sage.structure.sage_object import SageObject + class Decoder(SageObject): r""" Abstract top-class for :class:`Decoder` objects. diff --git a/src/sage/coding/encoder.py b/src/sage/coding/encoder.py index 6ad764935c7..459d6c82ebc 100644 --- a/src/sage/coding/encoder.py +++ b/src/sage/coding/encoder.py @@ -23,6 +23,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.sage_object import SageObject + class Encoder(SageObject): r""" Abstract top-class for :class:`Encoder` objects. @@ -380,6 +381,7 @@ def generator_matrix(self): [1 1 0 1 0 0 1] """ + class EncodingError(Exception): r""" Special exception class to indicate an error during encoding or unencoding. diff --git a/src/sage/coding/extended_code.py b/src/sage/coding/extended_code.py index 45557b1277e..46335b19bdc 100644 --- a/src/sage/coding/extended_code.py +++ b/src/sage/coding/extended_code.py @@ -31,6 +31,7 @@ from sage.modules.free_module_element import vector from copy import copy + class ExtendedCode(AbstractLinearCode): r""" Representation of an extended code. diff --git a/src/sage/coding/golay_code.py b/src/sage/coding/golay_code.py index 3d52dade619..233c754df97 100644 --- a/src/sage/coding/golay_code.py +++ b/src/sage/coding/golay_code.py @@ -32,6 +32,7 @@ from .linear_code import (AbstractLinearCode, LinearCodeGeneratorMatrixEncoder) + class GolayCode(AbstractLinearCode): r""" Representation of a Golay Code. diff --git a/src/sage/coding/goppa_code.py b/src/sage/coding/goppa_code.py index f61be9e7afb..aede3782597 100644 --- a/src/sage/coding/goppa_code.py +++ b/src/sage/coding/goppa_code.py @@ -35,6 +35,7 @@ from sage.modules.free_module_element import vector from sage.coding.all import codes + def _columnize(element): """ Convert a finite field element to a column vector over the prime field. diff --git a/src/sage/coding/guruswami_sudan/gs_decoder.py b/src/sage/coding/guruswami_sudan/gs_decoder.py index 6a91949234f..54a624375bd 100644 --- a/src/sage/coding/guruswami_sudan/gs_decoder.py +++ b/src/sage/coding/guruswami_sudan/gs_decoder.py @@ -36,6 +36,7 @@ from sage.functions.other import floor from sage.misc.functional import sqrt + def n_k_params(C, n_k): r""" Internal helper function for the :class:`GRSGuruswamiSudanDecoder` class for @@ -85,6 +86,7 @@ def n_k_params(C, n_k): elif n_k is not None: return n_k + def roth_ruckenstein_root_finder(p, maxd=None, precision=None): """ Wrapper for Roth-Ruckenstein algorithm to compute the roots of a polynomial @@ -104,6 +106,7 @@ def roth_ruckenstein_root_finder(p, maxd=None, precision=None): p = p.polynomial(gens[1]) return p.roots(multiplicities=False, degree_bound=maxd, algorithm='Roth-Ruckenstein') + def alekhnovich_root_finder(p, maxd=None, precision=None): """ Wrapper for Alekhnovich's algorithm to compute the roots of a polynomial @@ -123,6 +126,7 @@ def alekhnovich_root_finder(p, maxd=None, precision=None): p = p.polynomial(gens[1]) return p.roots(multiplicities=False, degree_bound=maxd, algorithm='Alekhnovich') + class GRSGuruswamiSudanDecoder(Decoder): r""" The Guruswami-Sudan list-decoding algorithm for decoding Generalized diff --git a/src/sage/coding/guruswami_sudan/interpolation.py b/src/sage/coding/guruswami_sudan/interpolation.py index c7855af3381..b1334307e79 100644 --- a/src/sage/coding/guruswami_sudan/interpolation.py +++ b/src/sage/coding/guruswami_sudan/interpolation.py @@ -25,6 +25,8 @@ from sage.misc.misc_c import prod ####################### Linear algebra system solving ############################### + + def _flatten_once(lstlst): r""" Flattens a list of list into a list, but only flattening one layer and @@ -52,6 +54,7 @@ def _flatten_once(lstlst): # Linear algebraic Interpolation algorithm, helper functions #************************************************************* + def _monomial_list(maxdeg, l, wy): r""" Return a list of all nonnegative integer pairs `(i,j)` such that ``i + wy @@ -156,6 +159,7 @@ def _interpolation_max_weighted_deg(n, tau, s): """ return (n-tau) * s + def _interpolation_matrix_problem(points, tau, parameters, wy): r""" Return the linear system of equations which ``Q`` should be a solution to. @@ -287,6 +291,7 @@ def gs_interpolation_linalg(points, tau, parameters, wy): ####################### Lee-O'Sullivan's method ############################### + def lee_osullivan_module(points, parameters, wy): r""" Return the analytically straight-forward basis for the `\GF{q}[x]` module diff --git a/src/sage/coding/information_set_decoder.py b/src/sage/coding/information_set_decoder.py index 00f4816c37a..c059b185816 100644 --- a/src/sage/coding/information_set_decoder.py +++ b/src/sage/coding/information_set_decoder.py @@ -68,6 +68,7 @@ def _format_decoding_interval(decoding_interval): return "exactly {0}".format(decoding_interval[0]) return "between {0} and {1}".format(decoding_interval[0], decoding_interval[1]) + class InformationSetAlgorithm(SageObject): r""" Abstract class for algorithms for diff --git a/src/sage/coding/linear_rank_metric.py b/src/sage/coding/linear_rank_metric.py index ff5f0c897b3..97a37e96c9b 100644 --- a/src/sage/coding/linear_rank_metric.py +++ b/src/sage/coding/linear_rank_metric.py @@ -176,6 +176,7 @@ def to_matrix_representation(v, sub_field=None, basis=None): extension, to_big_field, from_big_field = base_field.vector_space(sub_field, basis, map=True) return matrix(sub_field, m, n, lambda i, j: from_big_field(v[j])[i]) + def from_matrix_representation(w, base_field=None, basis=None): r""" Return a vector representation of a matrix ``w`` over ``base_field`` in terms @@ -255,6 +256,7 @@ def rank_weight(c, sub_field=None, basis=None): c = to_matrix_representation(c, sub_field, basis) return c.rank() + def rank_distance(a, b, sub_field=None, basis=None): r""" Return the rank of ``a`` - ``b`` as a matrix over ``sub_field``. diff --git a/src/sage/coding/punctured_code.py b/src/sage/coding/punctured_code.py index c56dccf3df3..c8be67993f8 100644 --- a/src/sage/coding/punctured_code.py +++ b/src/sage/coding/punctured_code.py @@ -27,6 +27,7 @@ from sage.rings.finite_rings.finite_field_constructor import GF from copy import copy + def _puncture(v, points): r""" Return v punctured as the positions listed in ``points``. @@ -58,6 +59,7 @@ def _puncture(v, points): new_v = [v[i] for i in range(len(v)) if i not in points] return S(new_v) + def _insert_punctured_positions(l, punctured_points, value=None): r""" Return ``l`` with ``value`` inserted in the corresponding diff --git a/src/sage/coding/self_dual_codes.py b/src/sage/coding/self_dual_codes.py index 9270aa5f240..10565d9e1a0 100644 --- a/src/sage/coding/self_dual_codes.py +++ b/src/sage/coding/self_dual_codes.py @@ -141,6 +141,7 @@ def _matA(n): A.append(I+O) return A + def _matId(n): r""" For internal use; returns a list of identity matrices over GF(2) @@ -177,6 +178,7 @@ def _MS2(n): n2 = n.quo_rem(2)[0] return MatrixSpace(_F, n2, n2) + def _I2(n): r""" Internal function. @@ -196,6 +198,7 @@ def _I2(n): """ return _MS2(n).identity_matrix() + @cached_function def _And7(): """ @@ -253,6 +256,7 @@ def _H8(): ############## main functions ############## + def self_dual_binary_codes(n): r""" Return the dictionary of inequivalent binary self dual codes of length `n`. diff --git a/src/sage/combinat/SJT.py b/src/sage/combinat/SJT.py index 03883eeb401..893f7735183 100644 --- a/src/sage/combinat/SJT.py +++ b/src/sage/combinat/SJT.py @@ -26,6 +26,7 @@ # **************************************************************************** from sage.combinat.combinat import CombinatorialElement + class SJT(CombinatorialElement): r""" A representation of a list permuted using the Steinhaus-Johnson-Trotter diff --git a/src/sage/combinat/combinat.py b/src/sage/combinat/combinat.py index 19677532d98..3d36078a755 100644 --- a/src/sage/combinat/combinat.py +++ b/src/sage/combinat/combinat.py @@ -1571,6 +1571,7 @@ def __init__(self, parent, *args, **kwds): ##################################################### # combinatorial sets/lists + def tuples(S, k, algorithm='itertools'): r""" Return a list of all `k`-tuples of elements of a given set ``S``. diff --git a/src/sage/combinat/designs/bibd.py b/src/sage/combinat/designs/bibd.py index 1ccd1a02ada..da6dd6c09dd 100644 --- a/src/sage/combinat/designs/bibd.py +++ b/src/sage/combinat/designs/bibd.py @@ -362,6 +362,7 @@ def balanced_incomplete_block_design(v, k, lambd=1, existence=False, use_LJCR=Fa else: raise NotImplementedError("I don't know how to build a ({},{},{})-BIBD!".format(v, k, lambd)) + def BruckRyserChowla_check(v, k, lambd): r""" Check whether the parameters passed satisfy the Bruck-Ryser-Chowla theorem. @@ -433,6 +434,7 @@ def BruckRyserChowla_check(v, k, lambd): return flag + def steiner_triple_system(n): r""" Return a Steiner Triple System. @@ -746,6 +748,7 @@ def BIBD_from_difference_family(G, D, lambd=None, check=True): # (v,4,1)-BIBD # ################ + def v_4_1_BIBD(v, check=True): r""" Return a `(v,4,1)`-BIBD. @@ -890,6 +893,7 @@ def BIBD_from_PBD(PBD, v, k, check=True, base_cases=None): return bibd + def _relabel_bibd(B,n,p=None): r""" Relabel the BIBD on `n` points and blocks of size k such that @@ -1016,6 +1020,7 @@ def PBD_4_5_8_9_12(v, check=True): return PBD + def _PBD_4_5_8_9_12_closure(B): r""" Makes sure all blocks of `B` have size in `\{4,5,8,9,12\}`. @@ -1175,6 +1180,7 @@ def v_5_1_BIBD(v, check=True): return bibd + def _get_r_s_t_u(v): r""" Implement the table from [ClaytonSmith]_. @@ -1247,6 +1253,7 @@ def PBD_from_TD(k,t,u): TD.append(list(range(k*t,k*t+u))) return TD + def BIBD_5q_5_for_q_prime_power(q): r""" Return a `(5q,5,1)`-BIBD with `q\equiv 1\pmod 4` a prime power. @@ -1394,6 +1401,7 @@ def BIBD_from_arc_in_desarguesian_projective_plane(n,k,existence=False): from sage.combinat.designs.block_design import DesarguesianProjectivePlaneDesign return DesarguesianProjectivePlaneDesign(q).trace(C)._blocks + class PairwiseBalancedDesign(GroupDivisibleDesign): r""" Pairwise Balanced Design (PBD). diff --git a/src/sage/combinat/designs/block_design.py b/src/sage/combinat/designs/block_design.py index e5faaa11602..bdf37227019 100644 --- a/src/sage/combinat/designs/block_design.py +++ b/src/sage/combinat/designs/block_design.py @@ -71,6 +71,7 @@ ### utility functions ------------------------------------------------------- + def tdesign_params(t, v, k, L): """ Return the design's parameters: `(t, v, b, r , k, L)`. Note that `t` must be @@ -91,6 +92,7 @@ def tdesign_params(t, v, k, L): r = integer_floor(L * x/y) return (t, v, b, r, k, L) + def are_hyperplanes_in_projective_geometry_parameters(v, k, lmbda, return_parameters=False): r""" Return ``True`` if the parameters ``(v,k,lmbda)`` are the one of hyperplanes in @@ -167,6 +169,7 @@ def are_hyperplanes_in_projective_geometry_parameters(v, k, lmbda, return_parame return (True, (q,d)) if return_parameters else True + def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, check=True): r""" Return a projective geometry design. @@ -392,6 +395,7 @@ def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True): return B + def q3_minus_one_matrix(K): r""" Return a companion matrix in `GL(3, K)` whose multiplicative order is `q^3 - 1`. @@ -438,6 +442,7 @@ def q3_minus_one_matrix(K): if m.multiplicative_order() == q**3 - 1: return m + def normalize_hughes_plane_point(p, q): r""" Return the normalized form of point ``p`` as a 3-tuple. @@ -481,6 +486,7 @@ def normalize_hughes_plane_point(p, q): else: return ((p[0] * k)**q,(p[1]*k)**q,(p[2]*k)**q) + def HughesPlane(q2, check=True): r""" Return the Hughes projective plane of order ``q2``. @@ -620,6 +626,7 @@ def HughesPlane(q2, check=True): from .bibd import BalancedIncompleteBlockDesign return BalancedIncompleteBlockDesign(q2**2+q2+1, blcks, check=check) + def projective_plane_to_OA(pplane, pt=None, check=True): r""" Return the orthogonal array built from the projective plane ``pplane``. @@ -775,6 +782,7 @@ def projective_plane(n, check=True, existence=False): else: return DesarguesianProjectivePlaneDesign(n, point_coordinates=False, check=check) + def AffineGeometryDesign(n, d, F, point_coordinates=True, check=True): r""" Return an affine geometry design. diff --git a/src/sage/combinat/designs/database.py b/src/sage/combinat/designs/database.py index ba4972ec5c9..7c797481773 100644 --- a/src/sage/combinat/designs/database.py +++ b/src/sage/combinat/designs/database.py @@ -68,6 +68,7 @@ # Cyclic shift of a list cyclic_shift = lambda l,i : l[-i:]+l[:-i] + def _MOLS_from_string(s,k): r""" Return MOLS from a string. @@ -91,6 +92,7 @@ def _MOLS_from_string(s,k): matrices[i % k].append(l) return [Matrix(_) for _ in matrices] + def MOLS_10_2(): r""" Return a pair of MOLS of order 10. @@ -134,6 +136,7 @@ def MOLS_10_2(): [5,6,7,1,2,3,4,0,9,8], [7,1,2,3,4,5,6,9,8,0]])] + def MOLS_12_5(): r""" Return 5 MOLS of order 12. @@ -165,6 +168,7 @@ def MOLS_12_5(): return _MOLS_from_string(M,5) + def MOLS_14_4(): r""" Return four MOLS of order 14. @@ -210,6 +214,7 @@ def MOLS_14_4(): return _MOLS_from_string(M,4) + def MOLS_15_4(): r""" Return 4 MOLS of order 15. @@ -249,6 +254,7 @@ def MOLS_15_4(): return _MOLS_from_string(M,4) + def MOLS_18_3(): r""" Return 3 MOLS of order 18. @@ -310,6 +316,7 @@ def MOLS_18_3(): LIST_OF_MOLS_CONSTRUCTIONS = ", ".join(":func:`{} MOLS of order {} `".format(k,n,n,k) for n,(k,_) in MOLS_constructions.items()) + def OA_7_18(): r""" Return an OA(7,18). @@ -364,6 +371,7 @@ def OA_7_18(): M = [M[i] for i in range(len(M)) if i % 18 < 9] # only develop w.r.t the last two coordinates return M + def OA_9_40(): r""" Return an OA(9,40). @@ -404,6 +412,7 @@ def OA_9_40(): return OA_n_times_2_pow_c_from_matrix(9,3,FiniteField(5),A,Y,check=False) + def OA_7_66(): r""" Return an OA(7,66). @@ -444,6 +453,7 @@ def OA_7_66(): PBD = [[rel[x] for x in B] for B in PBD] return OA_from_PBD(7,66,PBD,check=False) + def OA_7_68(): r""" Return an OA(7,68). @@ -484,6 +494,7 @@ def OA_7_68(): PBD = [[rel[x] for x in B] for B in PBD] return OA_from_PBD(7,68,PBD,check=False) + def OA_8_69(): r""" Return an OA(8,69). @@ -556,6 +567,7 @@ def OA_8_69(): OA = [[relabel[x] for x in B] for B in OA] return OA + def OA_7_74(): r""" Return an OA(7,74). @@ -596,6 +608,7 @@ def OA_7_74(): PBD = [[rel[x] for x in B] for B in PBD] return OA_from_PBD(7,74,PBD,check=False) + def OA_8_76(): r""" Return an OA(8,76). @@ -663,6 +676,7 @@ def OA_8_76(): OA = [[relabel[x] for x in B] for B in OA] return OA + def OA_11_80(): r""" Return an OA(11,80). @@ -705,6 +719,7 @@ def OA_11_80(): return OA_n_times_2_pow_c_from_matrix(11,4,FiniteField(5),A,Y,check=False) + def OA_15_112(): r""" Return an OA(15,112). @@ -751,6 +766,7 @@ def OA_15_112(): return OA_n_times_2_pow_c_from_matrix(15,4,FiniteField(7),list(zip(*A)),Y,check=False) + def OA_9_120(): r""" Return an OA(9,120). @@ -797,6 +813,7 @@ def OA_9_120(): return OA + def OA_9_135(): r""" Return an OA(9,135). @@ -882,6 +899,7 @@ def OA_9_135(): # And call Wilson's construction return wilson_construction(truncated_OA, 9, 16, 8, (1,)*7, check=False) + def OA_11_160(): r""" Return an OA(11,160). @@ -925,6 +943,7 @@ def OA_11_160(): return OA_n_times_2_pow_c_from_matrix(11,5,FiniteField(5),list(zip(*A)),Y,check=False) + def OA_16_176(): r""" Return an OA(16,176). @@ -979,6 +998,7 @@ def OA_16_176(): Y = [None, 0, 1, 2, 8, 6, 9, 4, 10, 3, 5, 11, 13, 14, 12] return OA_n_times_2_pow_c_from_matrix(16,4,FiniteField(11),list(zip(*A)),Y,check=False) + def OA_11_185(): r""" Return an OA(11,185). @@ -1042,6 +1062,7 @@ def OA_11_185(): OA.extend([[special_set[x] for x in B] for B in orthogonal_array(11,17)]) return OA + def OA_10_205(): r""" Return an `OA(10,205)`. @@ -1123,6 +1144,7 @@ def OA_10_205(): return OA + def OA_16_208(): r""" Return an OA(16,208). @@ -1182,6 +1204,7 @@ def OA_16_208(): return OA_n_times_2_pow_c_from_matrix(16,4,FiniteField(13),list(zip(*A)),Y,check=False) + def OA_15_224(): r""" Return an OA(15,224). @@ -1229,6 +1252,7 @@ def OA_15_224(): return OA_n_times_2_pow_c_from_matrix(15,5,FiniteField(7),list(zip(*A)),Y,check=False) + def OA_11_254(): r""" Return an OA(11,254). @@ -1268,6 +1292,7 @@ def OA_11_254(): return OA_from_PBD(11,254,BIBD,check=False) + def OA_20_352(): r""" Return an OA(20,352). @@ -1327,6 +1352,7 @@ def OA_20_352(): return OA_n_times_2_pow_c_from_matrix(20,5,FiniteField(11),list(zip(*A)),Y,check=False) + def OA_20_416(): r""" Return an OA(20,416). @@ -1387,6 +1413,7 @@ def OA_20_416(): return OA_n_times_2_pow_c_from_matrix(20,5,FiniteField(13),list(zip(*A)),Y,check=False) + def OA_20_544(): r""" Return an OA(20,544). @@ -1456,6 +1483,7 @@ def OA_20_544(): return OA_n_times_2_pow_c_from_matrix(20,5,FiniteField(17),list(zip(*A)),Y,check=False) + def OA_17_560(): r""" Return an OA(17,560). @@ -1515,6 +1543,7 @@ def OA_17_560(): return wilson_construction(OA,k,n,m,[p**beta]*3,check=False) + def OA_11_640(): r""" Return an OA(11,640). @@ -1557,6 +1586,7 @@ def OA_11_640(): return OA_n_times_2_pow_c_from_matrix(11,7,FiniteField(5),list(zip(*A)),Y,check=False) + def OA_10_796(): r""" Return an OA(10,796). @@ -1628,6 +1658,7 @@ def OA_10_796(): return OA + def OA_10_469(): r""" Return an OA(10,469). @@ -1702,6 +1733,7 @@ def OA_10_469(): return OA + def OA_520_plus_x(x): r""" Return an `OA(10+x,520+x)`. @@ -1775,6 +1807,7 @@ def OA_520_plus_x(x): OA.append([relabel[new_point]]*k) return OA + def OA_10_520(): r""" Return an OA(10,520). @@ -1797,6 +1830,7 @@ def OA_10_520(): """ return OA_520_plus_x(0) + def OA_12_522(): r""" Return an OA(12,522). @@ -1819,6 +1853,7 @@ def OA_12_522(): """ return OA_520_plus_x(2) + def OA_14_524(): r""" Return an OA(14,524). @@ -1841,6 +1876,7 @@ def OA_14_524(): """ return OA_520_plus_x(4) + def OA_15_896(): r""" Return an OA(15,896). @@ -1888,6 +1924,7 @@ def OA_15_896(): return OA_n_times_2_pow_c_from_matrix(15,7,FiniteField(7),list(zip(*A)),Y,check=False) + def OA_9_1078(): r""" Return an OA(9,1078). @@ -1918,6 +1955,7 @@ def OA_9_1078(): """ return wilson_construction(None,9,11,89,[[(11,9)]]) + def OA_25_1262(): r""" Return an OA(25,1262). @@ -1955,6 +1993,7 @@ def OA_25_1262(): return OA_from_PBD(25,1262,PBD,check=False) + def OA_9_1612(): r""" Return an OA(9,1612). @@ -1985,6 +2024,7 @@ def OA_9_1612(): """ return wilson_construction(None,9,17,89,[[(11,9)]]) + def OA_10_1620(): r""" Return an OA(10,1620). @@ -2061,6 +2101,7 @@ def OA_10_1620(): LIST_OF_OA_CONSTRUCTIONS = ", ".join(":func:`OA({},{}) `".format(k,n,k,n) for n,(k,_) in OA_constructions.items()) + def QDM_19_6_1_1_1(): r""" Return a `(19,6;1,1;1)`-quasi-difference matrix. @@ -2143,6 +2184,7 @@ def QDM_21_5_1_1_1(): return G, Mb + def QDM_21_6_1_1_5(): r""" Return a `(21,6;1,1;5)`-quasi-difference matrix. @@ -2183,6 +2225,7 @@ def QDM_21_6_1_1_5(): return G, Mb + def QDM_25_6_1_1_5(): r""" Return a `(25,6;1,1;5)`-quasi-difference matrix. @@ -2228,6 +2271,7 @@ def QDM_25_6_1_1_5(): return G, Mb + def QDM_33_6_1_1_1(): r""" Return a `(33,6;1,1;1)`-quasi-difference matrix. @@ -2271,6 +2315,7 @@ def QDM_33_6_1_1_1(): return G, Mb + def QDM_37_6_1_1_1(): r""" Return a `(37,6;1,1;1)`-quasi-difference matrix. @@ -2309,6 +2354,7 @@ def QDM_37_6_1_1_1(): return G, Mb + def QDM_35_7_1_1_7(): r""" Return a `(35,7;1,1;7)`-quasi-difference matrix. @@ -2346,6 +2392,7 @@ def QDM_35_7_1_1_7(): return G, Mb + def QDM_45_7_1_1_9(): r""" Return a `(45,7;1,1;9)`-quasi-difference matrix. @@ -2383,6 +2430,7 @@ def QDM_45_7_1_1_9(): return G, Mb + def QDM_54_7_1_1_8(): r""" Return a `(54,7;1,1;8)`-quasi-difference matrix. @@ -2420,6 +2468,7 @@ def QDM_54_7_1_1_8(): return G, Mb + def QDM_57_9_1_1_8(): r""" Return a `(57,9;1,1;8)`-quasi-difference matrix. @@ -3174,6 +3223,7 @@ def DM_12_6_1(): return G,M + def DM_21_6_1(): r""" Return a `(21,6,1)`-difference matrix. @@ -3209,6 +3259,7 @@ def DM_21_6_1(): return AdditiveCyclic(21), Mb + def DM_24_8_1(): r""" Return a `(24,8,1)`-difference matrix. @@ -3256,6 +3307,7 @@ def DM_24_8_1(): return G, Mb + def DM_28_6_1(): r""" Return a `(28,6,1)`-difference matrix. @@ -3299,6 +3351,7 @@ def DM_28_6_1(): return G, Mb + def DM_33_6_1(): r""" Return a `(33,6,1)`-difference matrix. @@ -3341,6 +3394,7 @@ def DM_33_6_1(): return G, Mb + def DM_35_6_1(): r""" Return a `(35,6,1)`-difference matrix. @@ -3373,6 +3427,7 @@ def DM_35_6_1(): return G, list(zip(*M)) + def DM_36_9_1(): r""" Return a `(36,9,1)`-difference matrix. @@ -3426,6 +3481,7 @@ def DM_36_9_1(): return G, Mb + def DM_39_6_1(): r""" Return a `(39,6,1)`-difference matrix. @@ -3470,6 +3526,7 @@ def DM_39_6_1(): return G,Mb + def DM_44_6_1(): r""" Return a `(44,6,1)`-difference matrix. @@ -3529,6 +3586,7 @@ def DM_44_6_1(): return G2211, Mb + def DM_45_7_1(): r""" Return a `(45,7,1)`-difference matrix. @@ -3585,6 +3643,7 @@ def DM_45_7_1(): return G533, Mb + def DM_48_9_1(): r""" Return a `(48,9,1)`-difference matrix. @@ -3634,6 +3693,7 @@ def DM_48_9_1(): return F3F16, Mb + def DM_51_6_1(): r""" Return a `(51,6,1)`-difference matrix. @@ -3748,6 +3808,7 @@ def t2(i,R): return G, Mb + def DM_55_7_1(): r""" Return a `(55,7,1)`-difference matrix. @@ -3787,6 +3848,7 @@ def DM_55_7_1(): return G, Mb + def DM_56_8_1(): r""" Return a `(56,8,1)`-difference matrix. @@ -3834,6 +3896,7 @@ def DM_56_8_1(): return G, Mb + def DM_57_8_1(): r""" Return a `(57,8,1)`-difference matrix. @@ -3862,6 +3925,7 @@ def DM_57_8_1(): G = AdditiveCyclic(57) return G, M + def DM_60_6_1(): r""" Return a `(60,6,1)`-difference matrix. @@ -3913,6 +3977,7 @@ def DM_60_6_1(): return G, M60b + def DM_75_8_1(): r""" Return a `(75,8,1)`-difference matrix. @@ -3961,6 +4026,7 @@ def DM_75_8_1(): return G, Mb + def DM_273_17_1(): r""" Return a `(273,17,1)`-difference matrix. @@ -3989,6 +4055,7 @@ def DM_273_17_1(): G = AdditiveCyclic(273) return G, M + def DM_993_32_1(): r""" Return a `(993,32,1)`-difference matrix. @@ -4131,6 +4198,7 @@ def RBIBD_120_8_1(): equiv = [[M.nonzero_positions_in_row(x) for x in S] for S in equiv] return [B for S in equiv for B in S] + def BIBD_45_9_8(from_code=False): r""" Return a `(45,9,1)`-BIBD. @@ -4304,6 +4372,7 @@ def BIBD_106_6_1(): return [[((x+i) % 53+y*53) for x,y in B] for i in range(53) for B in bibd] + def BIBD_111_6_1(): r""" Return a (111,6,1)-BIBD. @@ -4362,6 +4431,7 @@ def BIBD_126_6_1(): return [[x+y*5+z*25 for x,y,z in B] for B in bibd] + def BIBD_136_6_1(): r""" Return a (136,6,1)-BIBD. @@ -4669,6 +4739,7 @@ def BIBD_79_13_2(): libgap.unset_global("p4Act") return [[int(t)-1 for t in y] for y in blocks] + def BIBD_56_11_2(): r""" Return a symmetric `(56,11,2)`-BIBD. diff --git a/src/sage/combinat/designs/difference_family.py b/src/sage/combinat/designs/difference_family.py index bb8bb30d5bc..789f5d9a281 100644 --- a/src/sage/combinat/designs/difference_family.py +++ b/src/sage/combinat/designs/difference_family.py @@ -85,6 +85,7 @@ def group_law(G): else: raise ValueError("%s does not seem to be a group" % G) + def block_stabilizer(G, B): r""" Compute the left stabilizer of the block ``B`` under the action of ``G``. @@ -328,6 +329,7 @@ def is_difference_family(G, D, v=None, k=None, l=None, verbose=False): print("It is a ({},{},{})-difference family".format(v, k, l)) return True + def singer_difference_set(q,d): r""" Return a difference set associated to the set of hyperplanes in a projective @@ -411,6 +413,7 @@ def singer_difference_set(q,d): return Zmod((q**(d+1)-1)//(q-1)), [powers] + def df_q_6_1(K, existence=False, check=True): r""" Return a `(q,6,1)`-difference family over the finite field `K`. @@ -470,6 +473,7 @@ def df_q_6_1(K, existence=False, check=True): return D + def radical_difference_set(K, k, l=1, existence=False, check=True): r""" Return a difference set made of a cyclotomic coset in the finite field @@ -635,6 +639,7 @@ def radical_difference_set(K, k, l=1, existence=False, check=True): return D + def one_cyclic_tiling(A,n): r""" Given a subset ``A`` of the cyclic additive group `G = Z / nZ` return @@ -698,6 +703,7 @@ def one_cyclic_tiling(A,n): for c in M: return [i-1 for i in c] + def one_radical_difference_family(K, k): r""" Search for a radical difference family on ``K`` using dancing links @@ -815,6 +821,7 @@ def one_radical_difference_family(K, k): d.insert(K.zero(),0) return D + def radical_difference_family(K, k, l=1, existence=False, check=True): r""" Return a ``(v,k,l)``-radical difference family. @@ -925,6 +932,7 @@ def radical_difference_family(K, k, l=1, existence=False, check=True): return D + def twin_prime_powers_difference_set(p, check=True): r""" Return a difference set on `GF(p) \times GF(p+2)`. @@ -980,6 +988,7 @@ def twin_prime_powers_difference_set(p, check=True): return G, [d] + def are_mcfarland_1973_parameters(v, k, lmbda, return_parameters=False): r""" Test whether ``(v,k,lmbda)`` is a triple that can be obtained from the @@ -1052,6 +1061,7 @@ def are_mcfarland_1973_parameters(v, k, lmbda, return_parameters=False): return (True, (q, a1//a2)) if return_parameters else True + def mcfarland_1973_construction(q, s): r""" Return a difference set. @@ -1115,6 +1125,7 @@ def mcfarland_1973_construction(q, s): return G,[D] + def are_hadamard_difference_set_parameters(v, k, lmbda): r""" Check whether ``(v,k,lmbda)`` is of the form ``(4N^2, 2N^2 - N, N^2 - N)``. @@ -1135,6 +1146,7 @@ def are_hadamard_difference_set_parameters(v, k, lmbda): N2 = N*N return v == 4*N2 and k == 2*N2 - N and lmbda == N2 - N + @cached_function def hadamard_difference_set_product_parameters(N): r""" @@ -1178,6 +1190,7 @@ def hadamard_difference_set_product_parameters(N): return None + def hadamard_difference_set_product(G1, D1, G2, D2): r""" Make a product of two Hadamard difference sets. @@ -1217,6 +1230,7 @@ def hadamard_difference_set_product(G1, D1, G2, D2): return G, [[s for s in G if s not in D]] + def turyn_1965_3x3xK(k=4): r""" Return a difference set in either `C_3 \times C_3 \times C_4` or `C_3 \times @@ -1296,6 +1310,7 @@ def _is_periodic_sequence(seq, period): return False return True + def _create_m_sequence(q, n, check=True): r""" Create an m-sequence over GF(q) with period `q^n - 1`. @@ -1358,6 +1373,7 @@ def _create_m_sequence(q, n, check=True): assert _is_periodic_sequence(seq, period) return seq[:period] + def _get_submodule_of_order(G, order): r""" Construct a submodule of the given order from group ``G``. @@ -1387,6 +1403,7 @@ def _get_submodule_of_order(G, order): return H return None + def relative_difference_set_from_m_sequence(q, N, check=True, return_group=False): r""" Construct `R((q^N-1)/(q-1), q-1, q^{N-1}, q^{N-2})` where ``q`` is a prime power and `N\ge 2`. @@ -1462,6 +1479,7 @@ def relative_difference_set_from_m_sequence(q, N, check=True, return_group=False return G, set1 return set1 + def relative_difference_set_from_homomorphism(q, N, d, check=True, return_group=False): r""" Construct `R((q^N-1)/(q-1), n, q^{N-1}, q^{N-2}d)` where `nd = q-1`. diff --git a/src/sage/combinat/designs/difference_matrices.py b/src/sage/combinat/designs/difference_matrices.py index 5cebb84e439..11fe16bb8d5 100644 --- a/src/sage/combinat/designs/difference_matrices.py +++ b/src/sage/combinat/designs/difference_matrices.py @@ -19,6 +19,7 @@ from .designs_pyx import is_difference_matrix from .database import DM as DM_constructions + @cached_function def find_product_decomposition(g, k, lmbda=1): r""" @@ -71,6 +72,7 @@ def find_product_decomposition(g, k, lmbda=1): return False + def difference_matrix_product(k, M1, G1, lmbda1, M2, G2, lmbda2, check=True): r""" Return the product of the ``(G1, k, lmbda1)`` and ``(G2, k, lmbda2)`` @@ -121,6 +123,7 @@ def difference_matrix_product(k, M1, G1, lmbda1, M2, G2, lmbda2, check=True): return G,M + def difference_matrix(g,k,lmbda=1,existence=False,check=True): r""" Return a `(g,k,\lambda)`-difference matrix. diff --git a/src/sage/combinat/designs/ext_rep.py b/src/sage/combinat/designs/ext_rep.py index 9d04b4f5c66..5297ad3357a 100644 --- a/src/sage/combinat/designs/ext_rep.py +++ b/src/sage/combinat/designs/ext_rep.py @@ -466,6 +466,7 @@ """ + def dump_to_tmpfile(s): """ Utility function to dump a string to a temporary file. @@ -483,6 +484,7 @@ def dump_to_tmpfile(s): f.close() return file_loc + def check_dtrs_protocols(input_name, input_pv): """ Check that the XML data is in a valid format. We can currently @@ -506,6 +508,7 @@ def check_dtrs_protocols(input_name, input_pv): msg = ('''Incompatible dtrs_protocols: program: %s %s: %s''' % (program_pv, input_name, input_pv)) raise RuntimeError(msg) + def open_extrep_file(fname): """ Try to guess the compression type from extension @@ -534,6 +537,7 @@ def open_extrep_file(fname): f = open(fname, 'rb') return f + def open_extrep_url(url): """ Try to guess the compression type from extension @@ -569,6 +573,7 @@ def open_extrep_url(url): pattern_decimal = re.compile(r'-?\d+\.\d+$') pattern_rational = re.compile(r'-?\d+/\d+$') + def _encode_attribute(string): """ Convert numbers in attributes into binary format. @@ -600,6 +605,7 @@ def _encode_attribute(string): else: return string + class XTree: ''' A lazy class to wrap a rooted tree representing an XML document. @@ -773,6 +779,7 @@ def __len__(self): return len(self.xt_children) + class XTreeProcessor: ''' An incremental event-driven parser for ext-rep documents. @@ -1030,6 +1037,7 @@ def designs_from_XML(fname): return proc.list_of_designs + def designs_from_XML_url(url): """ Return a list of designs contained in an XML file named by a URL. diff --git a/src/sage/combinat/designs/orthogonal_arrays.py b/src/sage/combinat/designs/orthogonal_arrays.py index ae471d37065..ae1d48388bb 100644 --- a/src/sage/combinat/designs/orthogonal_arrays.py +++ b/src/sage/combinat/designs/orthogonal_arrays.py @@ -2054,6 +2054,7 @@ def OA_from_wider_OA(OA,k): return OA return [L[:k] for L in OA] + class OAMainFunctions: r""" Functions related to orthogonal arrays. diff --git a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py index 5d71fbb12c8..edad950fc88 100644 --- a/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py +++ b/src/sage/combinat/designs/orthogonal_arrays_build_recursive.py @@ -96,6 +96,7 @@ def construction_3_3(k,n,m,i,explain_construction=False): assert is_orthogonal_array(OA,k,n*m+i) return OA + def construction_3_4(k,n,m,r,s,explain_construction=False): r""" Return a `OA(k,nm+rs)`. @@ -178,6 +179,7 @@ def construction_3_4(k,n,m,r,s,explain_construction=False): OA = wilson_construction(OA,k,n,m,[1]*r+[s],check=False) return OA + def construction_3_5(k,n,m,r,s,t,explain_construction=False): r""" Return an `OA(k,nm+r+s+t)`. @@ -272,6 +274,7 @@ def construction_3_5(k,n,m,r,s,t,explain_construction=False): OA = wilson_construction(OA,k,q,m,[r,s,t], check=False) return OA + def construction_3_6(k,n,m,i,explain_construction=False): r""" Return a `OA(k,nm+i)`. @@ -328,6 +331,7 @@ def construction_3_6(k,n,m,i,explain_construction=False): assert is_orthogonal_array(OA,k,n*m+i) return OA + def OA_and_oval(q, *, solver=None, integrality_tolerance=1e-3): r""" Return a `OA(q+1,q)` whose blocks contains `\leq 2` zeroes in the last `q` @@ -752,6 +756,7 @@ def thwart_lemma_3_5(k,n,m,a,b,c,d=0,complement=False,explain_construction=False return wilson_construction(OA,k,n,m,sizes, check=False) + def thwart_lemma_4_1(k,n,m,explain_construction=False): r""" Return an `OA(k,nm+4(n-2))`. @@ -880,6 +885,7 @@ def thwart_lemma_4_1(k,n,m,explain_construction=False): return wilson_construction(OA,k,n,m,[n-2,]*4,check=False) + def three_factor_product(k,n1,n2,n3,check=False,explain_construction=False): r""" Return an `OA(k+1,n_1n_2n_3)`. @@ -1145,6 +1151,7 @@ def product_with_parallel_classes(OA1,k,g1,g2,g1_parall,parall,check=True): return OA + def _reorder_matrix(matrix): r""" Return a matrix which is obtained from ``matrix`` by permutation of each row @@ -1195,6 +1202,7 @@ def _reorder_matrix(matrix): return list(zip(*matrix)) + def brouwer_separable_design(k,t,q,x,check=False,verbose=False,explain_construction=False): r""" Return a `OA(k,t(q^2+q+1)+x)` using Brouwer's result on separable designs. diff --git a/src/sage/combinat/designs/steiner_quadruple_systems.py b/src/sage/combinat/designs/steiner_quadruple_systems.py index cf1834e88db..9576ae5f5aa 100644 --- a/src/sage/combinat/designs/steiner_quadruple_systems.py +++ b/src/sage/combinat/designs/steiner_quadruple_systems.py @@ -64,6 +64,8 @@ from sage.combinat.designs.incidence_structures import IncidenceStructure # Construction 1 + + def two_n(B): r""" Return a Steiner Quadruple System on `2n` points. @@ -100,6 +102,8 @@ def two_n(B): return IncidenceStructure(2*n,Y,check=False,copy=False) # Construction 2 + + def three_n_minus_two(B): """ Return a Steiner Quadruple System on `3n-2` points. @@ -155,6 +159,8 @@ def three_n_minus_two(B): return IncidenceStructure(3*n-2,Y,check=False,copy=False) # Construction 3 + + def three_n_minus_eight(B): r""" Return a Steiner Quadruple System on `3n-8` points. @@ -214,6 +220,8 @@ def three_n_minus_eight(B): return IncidenceStructure(3*n-8,Y,check=False,copy=False) # Construction 4 + + def three_n_minus_four(B): r""" Return a Steiner Quadruple System on `3n-4` points. @@ -278,6 +286,8 @@ def three_n_minus_four(B): return IncidenceStructure(3*n-4,Y,check=False,copy=False) # Construction 5 + + def four_n_minus_six(B): """ Return a Steiner Quadruple System on `4n-6` points. @@ -349,6 +359,8 @@ def four_n_minus_six(B): return IncidenceStructure(4*n-6,Y,check=False,copy=False) # Construction 6 + + def twelve_n_minus_ten(B): """ Return a Steiner Quadruple System on `12n-6` points. @@ -446,6 +458,7 @@ def twelve_n_minus_ten(B): Y.append([r(x,a), r(y,aa), r(z,aaa), r(t,aaaa)]) return IncidenceStructure(12*n-10,Y,check=False,copy=False) + def relabel_system(B): r""" Relabel the set so that `\{n-4, n-3, n-2, n-1\}` is in `B`. @@ -482,6 +495,7 @@ def get_label(x): B = [[get_label(_) for _ in s] for s in B] return IncidenceStructure(n,B) + def P(alpha, m): r""" Return the collection of pairs `P_{\alpha}(m)`. @@ -525,6 +539,7 @@ def P(alpha, m): pairs += [(y,m+y)] return pairs + def _missing_pair(n,l): r""" Return the smallest `(x,x+1)` that is not contained in `l`. @@ -559,6 +574,7 @@ def barP(eps, m): """ return barP_system(m)[eps] + @cached_function def barP_system(m): r""" @@ -671,6 +687,7 @@ def barP_system(m): return pairs + @cached_function def steiner_quadruple_system(n, check=False): r""" @@ -738,6 +755,7 @@ def steiner_quadruple_system(n, check=False): return sqs + def _SQS14(): r""" Return a Steiner Quadruple System on 14 points. @@ -771,6 +789,7 @@ def _SQS14(): [6, 8, 10, 12], [6, 9, 11, 12], [7, 8, 10, 13], [7, 8, 11, 12], [7, 9, 10, 12], [8, 9, 10, 11]] + def _SQS38(): r""" Return a Steiner Quadruple System on 14 points. diff --git a/src/sage/combinat/sf/dual.py b/src/sage/combinat/sf/dual.py index ce0f9f6bd1c..ff039ebd863 100644 --- a/src/sage/combinat/sf/dual.py +++ b/src/sage/combinat/sf/dual.py @@ -913,6 +913,8 @@ def expand(self, n, alphabet='x'): from sage.combinat.sf.sfa import SymmetricFunctionsFunctor + + class DualBasisFunctor(SymmetricFunctionsFunctor): """ A constructor for algebras of symmetric functions constructed by diff --git a/src/sage/combinat/sf/orthotriang.py b/src/sage/combinat/sf/orthotriang.py index 685674f0a3a..9a4378a859f 100644 --- a/src/sage/combinat/sf/orthotriang.py +++ b/src/sage/combinat/sf/orthotriang.py @@ -49,6 +49,7 @@ class SymmetricFunctionAlgebra_orthotriang(sfa.SymmetricFunctionAlgebra_generic) class Element(sfa.SymmetricFunctionAlgebra_generic.Element): pass + @staticmethod def __classcall__(cls, Sym, base, scalar, prefix, basis_name, leading_coeff=None): """ @@ -282,6 +283,8 @@ def product(self, left, right): from sage.combinat.sf.sfa import SymmetricFunctionsFunctor + + class OrthotriangBasisFunctor(SymmetricFunctionsFunctor): """ A constructor for algebras of symmetric functions constructed by diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index 9e45bdb2270..47d5e0042c1 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -6469,6 +6469,7 @@ def exponential_specialization(self, t=None, q=1): from sage.categories.commutative_rings import CommutativeRings from sage.categories.functor import Functor + class SymmetricFunctionsFunctor(ConstructionFunctor): """ A constructor for algebras of symmetric functions. diff --git a/src/sage/combinat/specht_module.py b/src/sage/combinat/specht_module.py index 49f3ac01e40..0114a8f191b 100644 --- a/src/sage/combinat/specht_module.py +++ b/src/sage/combinat/specht_module.py @@ -37,6 +37,7 @@ from sage.modules.free_module_element import vector from sage.categories.modules_with_basis import ModulesWithBasis + class SymmetricGroupRepresentation(Representation_abstract): """ Mixin class for symmetric group (algebra) representations. diff --git a/src/sage/combinat/symmetric_group_representations.py b/src/sage/combinat/symmetric_group_representations.py index dbaebfe3f01..f64e68fecad 100644 --- a/src/sage/combinat/symmetric_group_representations.py +++ b/src/sage/combinat/symmetric_group_representations.py @@ -1024,6 +1024,8 @@ def partition_to_vector_of_contents(partition, reverse=False): from sage.rings.quotient_ring import QuotientRing_generic from sage.combinat.specht_module import SymmetricGroupRepresentation as SymmetricGroupRepresentation_mixin + + class GarsiaProcesiModule(UniqueRepresentation, QuotientRing_generic, SymmetricGroupRepresentation_mixin): r""" A Garsia-Procesi module. diff --git a/src/sage/combinat/tamari_lattices.py b/src/sage/combinat/tamari_lattices.py index e38fcfbc7ed..89a940182d7 100644 --- a/src/sage/combinat/tamari_lattices.py +++ b/src/sage/combinat/tamari_lattices.py @@ -49,6 +49,7 @@ from __future__ import annotations from sage.combinat.posets.lattices import LatticePoset, MeetSemilattice + def paths_in_triangle(i, j, a, b) -> list[tuple[int, ...]]: r""" Return all Dyck paths from `(0,0)` to `(i,j)` in the `(a \times diff --git a/src/sage/cpython/_py2_random.py b/src/sage/cpython/_py2_random.py index a86f66c5ba0..e5f160b11cc 100644 --- a/src/sage/cpython/_py2_random.py +++ b/src/sage/cpython/_py2_random.py @@ -45,6 +45,7 @@ import _random + class Random(_random.Random): """Random number generator base class used by bound module functions. diff --git a/src/sage/crypto/block_cipher/miniaes.py b/src/sage/crypto/block_cipher/miniaes.py index babb4fec8b0..0a421c17e5e 100644 --- a/src/sage/crypto/block_cipher/miniaes.py +++ b/src/sage/crypto/block_cipher/miniaes.py @@ -35,6 +35,7 @@ from sage.rings.integer import Integer from sage.structure.sage_object import SageObject + class MiniAES(SageObject): r""" This class implements the Mini Advanced Encryption Standard (Mini-AES) diff --git a/src/sage/crypto/block_cipher/sdes.py b/src/sage/crypto/block_cipher/sdes.py index a474530199b..9b29d25ac15 100644 --- a/src/sage/crypto/block_cipher/sdes.py +++ b/src/sage/crypto/block_cipher/sdes.py @@ -31,6 +31,7 @@ from sage.monoids.string_monoid import BinaryStrings from sage.structure.sage_object import SageObject + class SimplifiedDES(SageObject): r""" This class implements the Simplified Data Encryption Standard (S-DES) diff --git a/src/sage/crypto/cipher.py b/src/sage/crypto/cipher.py index 09f9fe902cb..98a00db47dc 100644 --- a/src/sage/crypto/cipher.py +++ b/src/sage/crypto/cipher.py @@ -16,6 +16,7 @@ from sage.structure.element import Element + class Cipher(Element): """ Cipher class @@ -52,6 +53,7 @@ def domain(self): def codomain(self): return self.parent().cipher_codomain() + class SymmetricKeyCipher(Cipher): """ Symmetric key cipher class @@ -62,6 +64,7 @@ def __init__(self, parent, key): """ Cipher.__init__(self, parent, key) + class PublicKeyCipher(Cipher): """ Public key cipher class diff --git a/src/sage/crypto/classical.py b/src/sage/crypto/classical.py index 3e2e618ea29..82811ab56a8 100644 --- a/src/sage/crypto/classical.py +++ b/src/sage/crypto/classical.py @@ -2969,6 +2969,7 @@ def random_key(self): from sage.misc.prandom import randint return Integer(randint(0, self.alphabet_size() - 1)) + class SubstitutionCryptosystem(SymmetricKeyCryptosystem): """ Create a substitution cryptosystem. @@ -3193,6 +3194,7 @@ def enciphering(self, K, M): e = self(K) return e(M) + class TranspositionCryptosystem(SymmetricKeyCryptosystem): """ Create a transposition cryptosystem of block length ``n``. diff --git a/src/sage/crypto/classical_cipher.py b/src/sage/crypto/classical_cipher.py index b03aedff480..cb2a03ede29 100644 --- a/src/sage/crypto/classical_cipher.py +++ b/src/sage/crypto/classical_cipher.py @@ -232,6 +232,7 @@ def inverse(self): raise ValueError("Argument\n\n%s\n\nmust be an invertible cipher." % self) return E(B) + class ShiftCipher(SymmetricKeyCipher): r""" Shift cipher class. This is the class that does the actual work of @@ -374,6 +375,7 @@ def _repr_(self): # as the alphabet used for the plaintext and ciphertext spaces. return "Shift cipher on %s" % self.parent().cipher_domain() + class SubstitutionCipher(SymmetricKeyCipher): """ Substitution cipher class @@ -447,6 +449,7 @@ def inverse(self): K = E.inverse_key(self.key()) return E(K) + class TranspositionCipher(SymmetricKeyCipher): """ Transition cipher class @@ -517,6 +520,7 @@ def inverse(self): K = E.inverse_key(self.key()) return E(K) + class VigenereCipher(SymmetricKeyCipher): """ Vigenere cipher class diff --git a/src/sage/crypto/key_exchange/diffie_hellman.py b/src/sage/crypto/key_exchange/diffie_hellman.py index bdd25affe3b..47b6bd392a8 100644 --- a/src/sage/crypto/key_exchange/diffie_hellman.py +++ b/src/sage/crypto/key_exchange/diffie_hellman.py @@ -33,6 +33,7 @@ from typing import Union + class DiffieHellman(KeyExchangeScheme): @experimental(37305) diff --git a/src/sage/crypto/key_exchange/key_exchange_scheme.py b/src/sage/crypto/key_exchange/key_exchange_scheme.py index ff250357eb1..8ddf0c89de6 100644 --- a/src/sage/crypto/key_exchange/key_exchange_scheme.py +++ b/src/sage/crypto/key_exchange/key_exchange_scheme.py @@ -23,6 +23,7 @@ from sage.misc.superseded import experimental from sage.structure.sage_object import SageObject + class KeyExchangeScheme(SageObject): """ Abstract base class for key exchange schemes. diff --git a/src/sage/crypto/lattice.py b/src/sage/crypto/lattice.py index 355bfd1c3ba..430ab98f3ae 100644 --- a/src/sage/crypto/lattice.py +++ b/src/sage/crypto/lattice.py @@ -24,6 +24,7 @@ from sage.rings.polynomial.polynomial_ring import PolynomialRing_general + def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, quotient=None, dual=False, ntl=False, lattice=False): r""" diff --git a/src/sage/crypto/lwe.py b/src/sage/crypto/lwe.py index 4eee100c205..7403260c514 100644 --- a/src/sage/crypto/lwe.py +++ b/src/sage/crypto/lwe.py @@ -399,6 +399,7 @@ def __init__(self, n, secret_dist='uniform', m=None): D = DiscreteGaussianDistributionIntegerSampler(s/sqrt(2*pi.n()), q) LWE.__init__(self, n=n, q=q, D=D, secret_dist=secret_dist, m=m) + class LindnerPeikert(LWE): """ LWE oracle with parameters as in [LP2011]_. @@ -512,6 +513,7 @@ def __init__(self, n, instance='key', m=None): else: raise TypeError("Parameter instance=%s not understood." % (instance)) + class RingLWE(SageObject): """ Ring Learning with Errors oracle. @@ -607,6 +609,7 @@ def __call__(self): a = self.R_q.random_element() return vector(a), vector(a * (self.__s) + self.D()) + class RingLindnerPeikert(RingLWE): """ Ring-LWE oracle with parameters as in [LP2011]_. @@ -650,6 +653,7 @@ def __init__(self, N, delta=0.01, m=None): D = DiscreteGaussianDistributionPolynomialSampler(ZZ['x'], n, stddev) RingLWE.__init__(self, N=N, q=q, D=D, poly=None, secret_dist='noise', m=m) + class RingLWEConverter(SageObject): """ Wrapper callable to convert Ring-LWE oracles into LWE oracles by @@ -712,6 +716,7 @@ def _repr_(self): """ return "RingLWEConverter(%s)" % str(self.ringlwe) + def samples(m, n, lwe, seed=None, balanced=False, **kwds): """ Return ``m`` LWE samples. diff --git a/src/sage/crypto/mq/sr.py b/src/sage/crypto/mq/sr.py index 8c372a22e92..2ea8ee58c32 100644 --- a/src/sage/crypto/mq/sr.py +++ b/src/sage/crypto/mq/sr.py @@ -2448,6 +2448,7 @@ def field_polynomials(self, name, i, l=None): _vars = self.vars(name, i, l, e) return [_vars[e*j+k]**2 - _vars[e*j+(k+1) % e] for j in range(l) for k in range(e)] + class SR_gf2(SR_generic): def __init__(self, n=1, r=1, c=1, e=4, star=False, **kwargs): r""" @@ -3162,6 +3163,7 @@ def field_polynomials(self, name, i, l=None): _vars = self.vars(name, i, l, e) return [_vars[e*j+k]**2 - _vars[e*j+k] for j in range(l) for k in range(e)] + class SR_gf2_2(SR_gf2): """ This is an example how to customize the SR constructor. @@ -3246,6 +3248,7 @@ def inversion_polynomials_single_sbox(self, x=None, w=None, biaffine_only=None, F = S.polynomials(w, x, degree=e-2, groebner=groebner) return F + class AllowZeroInversionsContext: """ Temporarily allow zero inversion. @@ -3294,6 +3297,7 @@ def __exit__(self, typ, value, tb): """ self.sr._allow_zero_inversions = self.allow_zero_inversions + def test_consistency(max_n=2, **kwargs): r""" Test all combinations of ``r``, ``c``, ``e`` and ``n`` in ``(1, diff --git a/src/sage/crypto/public_key/blum_goldwasser.py b/src/sage/crypto/public_key/blum_goldwasser.py index c4338ae46af..cf09d4038c8 100644 --- a/src/sage/crypto/public_key/blum_goldwasser.py +++ b/src/sage/crypto/public_key/blum_goldwasser.py @@ -44,6 +44,7 @@ floor = Function_floor() IntegerModRing = IntegerModFactory("IntegerModRing") + class BlumGoldwasser(PublicKeyCryptosystem): r""" The Blum-Goldwasser probabilistic public-key encryption scheme. diff --git a/src/sage/crypto/stream.py b/src/sage/crypto/stream.py index 4a9ef986b6e..a9e94d63b24 100644 --- a/src/sage/crypto/stream.py +++ b/src/sage/crypto/stream.py @@ -25,6 +25,7 @@ IntegerModRing = IntegerModFactory("IntegerModRing") + class LFSRCryptosystem(SymmetricKeyCryptosystem): """ Linear feedback shift register cryptosystem class @@ -101,6 +102,7 @@ def encoding(self,M): except Exception: raise TypeError("Argument M = %s does not encode in the cipher domain" % M) + class ShrinkingGeneratorCryptosystem(SymmetricKeyCryptosystem): """ Shrinking generator cryptosystem class @@ -165,6 +167,7 @@ def encoding(self,M): except Exception: raise TypeError("Argument M = %s does not encode in the cipher domain" % M) + def blum_blum_shub(length, seed=None, p=None, q=None, lbound=None, ubound=None, ntries=100): r""" diff --git a/src/sage/crypto/stream_cipher.py b/src/sage/crypto/stream_cipher.py index ef1b44e6f2b..4b6d36ad925 100644 --- a/src/sage/crypto/stream_cipher.py +++ b/src/sage/crypto/stream_cipher.py @@ -14,6 +14,7 @@ from .cipher import SymmetricKeyCipher from sage.monoids.string_monoid_element import StringMonoidElement + class LFSRCipher(SymmetricKeyCipher): def __init__(self, parent, poly, IS): """ @@ -143,6 +144,7 @@ def initial_state(self): """ return self.key()[1] + class ShrinkingGeneratorCipher(SymmetricKeyCipher): def __init__(self, parent, e1, e2): """ diff --git a/src/sage/crypto/util.py b/src/sage/crypto/util.py index 199d09c2758..66ffb78ef2b 100644 --- a/src/sage/crypto/util.py +++ b/src/sage/crypto/util.py @@ -93,6 +93,7 @@ def ascii_integer(B): return sum([L[7], L[6]*2, L[5]*4, L[4]*8, L[3]*16, L[2]*32, L[1]*64, L[0]*128]) + def ascii_to_bin(A): r""" Return the binary representation of the ASCII string ``A``. @@ -159,6 +160,7 @@ def ascii_to_bin(A): bin = BinaryStrings() return bin.encoding("".join(list(A))) + def bin_to_ascii(B): r""" Return the ASCII representation of the binary string ``B``. @@ -347,6 +349,7 @@ def has_blum_prime(lbound, ubound): return True return False + def is_blum_prime(n): r""" Determine whether or not ``n`` is a Blum prime. @@ -384,6 +387,7 @@ def is_blum_prime(n): else: return False + def least_significant_bits(n, k): r""" Return the ``k`` least significant bits of ``n``. @@ -438,6 +442,7 @@ def least_significant_bits(n, k): """ return [int(_) for _ in list(n.binary()[-k:])] + def random_blum_prime(lbound, ubound, ntries=100): r""" A random Blum prime within the specified bounds. diff --git a/src/sage/databases/conway.py b/src/sage/databases/conway.py index 38458806b76..e782676fde9 100644 --- a/src/sage/databases/conway.py +++ b/src/sage/databases/conway.py @@ -15,6 +15,7 @@ # **************************************************************************** from collections.abc import Mapping + class DictInMapping(Mapping): def __init__(self, dict): """ diff --git a/src/sage/databases/cubic_hecke_db.py b/src/sage/databases/cubic_hecke_db.py index 2f94439e6f0..ef8d1f7f1c5 100644 --- a/src/sage/databases/cubic_hecke_db.py +++ b/src/sage/databases/cubic_hecke_db.py @@ -1285,6 +1285,7 @@ def read_basis(num_strands=3): -1], [2, -1, 2], [1, 2, -1, 2], [-1, 2, -1, 2]] return data[num_strands] + def read_irr(variables, num_strands=3): r""" Return precomputed data of Ivan Marin. @@ -1328,6 +1329,7 @@ def read_irr(variables, num_strands=3): 1/b, (1, 1): 1/b, (1, 2): a/b + b/c, (2, 2): 1/c}]]) return data[num_strands] + def read_regl(variables, num_strands=3): r""" Return precomputed data of Ivan Marin. @@ -1401,6 +1403,7 @@ def read_regl(variables, num_strands=3): (22, 6): 1/w, (22, 13): u/w, (22, 22): v/w, (23, 13): 1}]]) return data[num_strands] + def read_regr(variables, num_strands=3): r""" Return precomputed data of Ivan Marin. diff --git a/src/sage/databases/db_class_polynomials.py b/src/sage/databases/db_class_polynomials.py index dd436fe5db7..57acde7c05a 100644 --- a/src/sage/databases/db_class_polynomials.py +++ b/src/sage/databases/db_class_polynomials.py @@ -106,6 +106,7 @@ def __repr__(self): # None of the following are implemented yet. ###################################################### + class AtkinClassPolynomialDatabase(ClassPolynomialDatabase): """ The database of Atkin class polynomials. diff --git a/src/sage/databases/findstat.py b/src/sage/databases/findstat.py index 85c06bf06cd..4811fc0f2b7 100644 --- a/src/sage/databases/findstat.py +++ b/src/sage/databases/findstat.py @@ -307,6 +307,8 @@ def mapping(sigma): FINDSTAT_FORM_FOOTER = '' ###################################################################### + + class FindStat(UniqueRepresentation, SageObject): r""" The Combinatorial Statistic Finder. @@ -438,6 +440,7 @@ def _get_json(url, **kwargs): return result raise ConnectionError(response.text) + def _post_json(url, data, **kwargs): """ Return the json response or raise an error. @@ -1793,6 +1796,8 @@ def statistic(x): ###################################################################### # statistics ###################################################################### + + class FindStatCombinatorialStatistic(SageObject): """ A class providing methods to retrieve the first terms of a statistic. @@ -2393,6 +2398,8 @@ def info(self): _all_statistics = {} + + class FindStatStatistics(UniqueRepresentation, Parent): r""" The class of FindStat statistics. @@ -2740,6 +2747,7 @@ def __len__(self): """ return len(self._result) + class FindStatCompoundStatistic(Element, FindStatCombinatorialStatistic): def __init__(self, id, domain=None, check=True): """ @@ -3036,6 +3044,8 @@ def info(self): ###################################################################### # maps ###################################################################### + + class FindStatCombinatorialMap(SageObject): """ A class serving as common ancestor of :class:`FindStatStatistic` @@ -3043,6 +3053,7 @@ class FindStatCombinatorialMap(SageObject): """ pass + class FindStatMap(Element, FindStatFunction, FindStatCombinatorialMap, @@ -3305,6 +3316,8 @@ def info(self): _all_maps = {} + + class FindStatMaps(UniqueRepresentation, Parent): r""" The class of FindStat maps. @@ -3623,6 +3636,7 @@ def __len__(self): """ return len(self._result) + class FindStatCompoundMap(Element, FindStatCombinatorialMap): def __init__(self, id, domain=None, codomain=None, check=True): """ @@ -3914,6 +3928,8 @@ def _finite_irreducible_cartan_types_by_rank(n): return cartan_types # helper for generation of PlanePartitions + + def _plane_partitions_by_size_aux(n, outer=None): """ Iterate over the plane partitions with `n` boxes, as lists. @@ -3941,6 +3957,7 @@ def _plane_partitions_by_size_aux(n, outer=None): pp = [la] + pp yield pp + def _plane_partitions_by_size(n): """ Iterate over the plane partitions with `n` boxes. @@ -3970,6 +3987,8 @@ def _plane_partitions_by_size(n): yield PlanePartition(pp) # helper for generation of Lattices + + def _finite_lattices(n): """ Iterate over the lattices with `n` elements. diff --git a/src/sage/databases/knotinfo_db.py b/src/sage/databases/knotinfo_db.py index 779ee127467..8ffc5d5f32a 100644 --- a/src/sage/databases/knotinfo_db.py +++ b/src/sage/databases/knotinfo_db.py @@ -44,6 +44,7 @@ columns_white_list = ['knot_atlas_anon', 'knotilus_page_anon'] columns_black_list = ['homfly_polynomial_old'] + class KnotInfoColumnTypes(Enum): r""" Enum class to specify if a column from the table of knots and links provided diff --git a/src/sage/databases/odlyzko.py b/src/sage/databases/odlyzko.py index 510edb4a8f6..1e19fda8619 100644 --- a/src/sage/databases/odlyzko.py +++ b/src/sage/databases/odlyzko.py @@ -31,6 +31,7 @@ from sage.misc.persist import load from sage.env import SAGE_SHARE + def zeta_zeros(): r""" List of the imaginary parts of the first 2,001,052 zeros of the diff --git a/src/sage/databases/sql_db.py b/src/sage/databases/sql_db.py index edef584b6d4..64aa74f6b2d 100644 --- a/src/sage/databases/sql_db.py +++ b/src/sage/databases/sql_db.py @@ -98,6 +98,7 @@ 'UNIQUE','UPDATE','USING','VACUUM','VALUES','VIEW','VIRTUAL','WHEN', 'WHERE'] + def regexp(expr, item): """ Function to define regular expressions in pysqlite. @@ -179,6 +180,7 @@ def verify_column(col_dict): d['sql'] = col_dict['sql'] return d + def verify_operator(operator): """ Check that ``operator`` is one of the allowed strings. @@ -274,6 +276,8 @@ def construct_skeleton(database): p = 0 + + def _create_print_table(cur, col_titles, **kwds): r""" Create a nice printable table from the cursor given with the given @@ -397,6 +401,7 @@ def row_str(row, html): ret += '\n'.join([row_str(row, False) for row in cur]) return ret + class SQLQuery(SageObject): def __init__(self, database, *args, **kwds): """ diff --git a/src/sage/doctest/forker.py b/src/sage/doctest/forker.py index 823a0d14a41..de1c8531814 100644 --- a/src/sage/doctest/forker.py +++ b/src/sage/doctest/forker.py @@ -150,14 +150,15 @@ def init_sage(controller=None): sage: from sympy.printing.pretty.pretty import PrettyPrinter sage: s = sympify('+x^'.join(str(i) for i in range(30))) sage: print(PrettyPrinter(settings={'wrap_line': True}).doprint(s)) - 29 28 27 26 25 24 23 22 21 20 19 18 17 - x + x + x + x + x + x + x + x + x + x + x + x + x + + 29 28 27 26 25 24 23 22 21 20 19 18 17 ↪ + x + x + x + x + x + x + x + x + x + x + x + x + x + ↪ - 16 15 14 13 12 11 10 9 8 7 6 5 4 3 - x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + ↪ 16 15 14 13 12 11 10 9 8 7 6 5 4 3 ↪ + ↪ x + x + x + x + x + x + x + x + x + x + x + x + x + x + ↪ - 2 - + x + ↪ 2 + ↪ x + x + The displayhook sorts dictionary keys to simplify doctesting of dictionary output:: diff --git a/src/sage/features/sphinx.py b/src/sage/features/sphinx.py index ec7c8be17b6..672b826f59d 100644 --- a/src/sage/features/sphinx.py +++ b/src/sage/features/sphinx.py @@ -39,5 +39,33 @@ def __init__(self): PythonModule.__init__(self, 'sphinx', spkg='sphinx', type='standard') +class JupyterSphinx(PythonModule): + r""" + A :class:`sage.features.Feature` describing the presence of + :ref:`jupyter_sphinx `. + + It is provided by a standard package in the Sage distribution, + but it can be disabled by ``configure --disable-doc`` and + ``configure --disable-notebook``. + + EXAMPLES:: + + sage: from sage.features.sphinx import JupyterSphinx + sage: JupyterSphinx().is_present() # optional - jupyter_sphinx + FeatureTestResult('jupyter_sphinx', True) + """ + def __init__(self): + r""" + TESTS:: + + sage: from sage.features.sphinx import JupyterSphinx + sage: isinstance(JupyterSphinx(), JupyterSphinx) + True + """ + PythonModule.__init__(self, 'jupyter_sphinx', + spkg='jupyter_sphinx', type='standard') + + def all_features(): - return [Sphinx()] + return [Sphinx(), + JupyterSphinx()] diff --git a/src/sage/features/threejs.py b/src/sage/features/threejs.py index 56ad807babf..8698b84e0e5 100644 --- a/src/sage/features/threejs.py +++ b/src/sage/features/threejs.py @@ -1,5 +1,5 @@ # sage_setup: distribution = sagemath-environment -import os +from pathlib import Path from . import StaticFile @@ -26,16 +26,17 @@ def __init__(self): """ from sage.env import SAGE_SHARE, THREEJS_DIR + share_dir = Path(SAGE_SHARE) threejs_search_path = THREEJS_DIR or ( - os.path.join(SAGE_SHARE, "jupyter", "nbextensions", "threejs-sage"), - os.path.join(SAGE_SHARE, "sagemath", "threejs-sage"), - os.path.join(SAGE_SHARE, "sage", "threejs"), - os.path.join(SAGE_SHARE, "threejs-sage") + (share_dir / "jupyter" / "nbextensions" / "threejs-sage"), + (share_dir / "sagemath" / "threejs-sage"), + (share_dir / "sage" / "threejs"), + (share_dir / "threejs-sage") ) try: version = self.required_version() - filename = os.path.join(version, "three.min.js") + filename = Path(version) / "three.min.js" except FileNotFoundError: filename = 'unknown' @@ -64,7 +65,7 @@ def required_version(self): """ from sage.env import SAGE_EXTCODE - filename = os.path.join(SAGE_EXTCODE, 'threejs', 'threejs-version.txt') + filename = Path(SAGE_EXTCODE) / 'threejs' / 'threejs-version.txt' with open(filename) as f: return f.read().strip() diff --git a/src/sage/functions/hypergeometric.py b/src/sage/functions/hypergeometric.py index ade7836b310..eb5c6665c0d 100644 --- a/src/sage/functions/hypergeometric.py +++ b/src/sage/functions/hypergeometric.py @@ -124,7 +124,7 @@ sage: maxima(hypergeometric([1, 1, 1], [3, 3, 3], x)) # needs sage.symbolic hypergeometric([1,1,1],[3,3,3],_SAGE_VAR_x) sage: hypergeometric((5, 4), (4, 4), 3)._sympy_() # needs sympy sage.symbolic - hyper((5, 4), (4, 4), 3) + hyper((5,), (4,), 3) sage: hypergeometric((5, 4), (4, 4), 3)._mathematica_init_() # needs sage.symbolic 'HypergeometricPFQ[{5,4},{4,4},3]' diff --git a/src/sage/graphs/connectivity.pyx b/src/sage/graphs/connectivity.pyx index 2d299e254fe..b390e0c9877 100644 --- a/src/sage/graphs/connectivity.pyx +++ b/src/sage/graphs/connectivity.pyx @@ -2634,22 +2634,51 @@ def spqr_tree_to_graph(T): sage: H.is_isomorphic(G) True - TESTS:: + TESTS: + + Check that the method is working for the empty SPQR tree:: sage: H = spqr_tree_to_graph(Graph()) sage: H.is_isomorphic(Graph()) True + + Check that :issue:`38527` is fixed:: + + sage: from sage.graphs.connectivity import spqr_tree, spqr_tree_to_graph + sage: G = Graph('LlCG{O@?GBoMw?') + sage: T1 = spqr_tree(G, algorithm="Hopcroft_Tarjan") + sage: T2 = spqr_tree(G, algorithm="cleave") + sage: T1.is_isomorphic(T2) + True + sage: G1 = spqr_tree_to_graph(T1) + sage: G2 = spqr_tree_to_graph(T2) + sage: G.is_isomorphic(G1) + True + sage: G.is_isomorphic(G2) + True """ from sage.graphs.graph import Graph from collections import Counter count_G = Counter() count_P = Counter() + vertex_to_int = dict() for t, g in T: + for u in g: + if u not in vertex_to_int: + vertex_to_int[u] = len(vertex_to_int) if t in ['P', 'Q']: - count_P.update(g.edge_iterator()) + for u, v, label in g.edge_iterator(): + if vertex_to_int[u] < vertex_to_int[v]: + count_P[u, v, label] += 1 + else: + count_P[v, u, label] += 1 else: - count_G.update(g.edge_iterator()) + for u, v, label in g.edge_iterator(): + if vertex_to_int[u] < vertex_to_int[v]: + count_G[u, v, label] += 1 + else: + count_G[v, u, label] += 1 G = Graph(multiedges=True) for e, num in count_G.items(): diff --git a/src/sage/graphs/digraph.py b/src/sage/graphs/digraph.py index 2454834bd51..4010c698732 100644 --- a/src/sage/graphs/digraph.py +++ b/src/sage/graphs/digraph.py @@ -873,7 +873,7 @@ def dig6_string(self): r""" Return the ``dig6`` representation of the digraph as an ASCII string. - This is only valid for single (no multiple edges) digraphs on at most + This is only valid for simple (no multiple edges) digraphs on at most `2^{18} - 1 = 262143` vertices. .. NOTE:: @@ -893,6 +893,9 @@ def dig6_string(self): sage: D = DiGraph({0: [1, 2], 1: [2], 2: [3], 3: [0]}) sage: D.dig6_string() 'CW`_' + sage: L = DiGraph({0: [1, 2], 1: [2], 2: [3], 3: [3]}) + sage: L.dig6_string() + 'CW`C' TESTS:: diff --git a/src/sage/graphs/generic_graph.py b/src/sage/graphs/generic_graph.py index 614186f04e4..3a476e0a209 100644 --- a/src/sage/graphs/generic_graph.py +++ b/src/sage/graphs/generic_graph.py @@ -831,8 +831,11 @@ def __str__(self): def _bit_vector(self): """ - Return a string representing the edges of the (simple) graph for - ``graph6`` and ``dig6`` strings. + Return a string representing the edges of the graph for ``graph6`` + and ``dig6`` strings. + + The graph must be simple; loops are allowed only if the graph is + directed, and multiple edges are never allowed. EXAMPLES:: @@ -862,7 +865,7 @@ def _bit_vector(self): sage: P.canonical_label(algorithm='sage')._bit_vector() '001100001111000000011010100110100011' """ - self._scream_if_not_simple() + self._scream_if_not_simple(allow_loops=self._directed) n = self.order() if self._directed: total_length = n * n diff --git a/src/sage/graphs/graph_input.py b/src/sage/graphs/graph_input.py index 432cce4ec99..678fdbcf32e 100644 --- a/src/sage/graphs/graph_input.py +++ b/src/sage/graphs/graph_input.py @@ -144,6 +144,13 @@ def from_dig6(G, dig6_string): sage: from_dig6(g, digraphs.Circuit(10).dig6_string()) sage: g.is_isomorphic(digraphs.Circuit(10)) True + + The string may represent a directed graph with loops:: + + sage: L = DiGraph(loops=True) + sage: from_dig6(L, 'CW`C') + sage: L.edges(labels=False, sort=True) + [(0, 1), (0, 2), (1, 2), (2, 3), (3, 3)] """ from .generic_graph_pyx import length_and_string_from_graph6, binary_string_from_dig6 if isinstance(dig6_string, bytes): diff --git a/src/sage/graphs/graph_plot_js.py b/src/sage/graphs/graph_plot_js.py index 2c439a56dec..648e3842d58 100644 --- a/src/sage/graphs/graph_plot_js.py +++ b/src/sage/graphs/graph_plot_js.py @@ -73,9 +73,9 @@ Functions --------- """ +from pathlib import Path from sage.misc.temporary_file import tmp_filename from sage.misc.lazy_import import lazy_import -import os lazy_import("sage.plot.colors", "rainbow") # **************************************************************************** @@ -317,13 +317,12 @@ def gen_html_code(G, "edge_thickness": int(edge_thickness)}) from sage.env import SAGE_EXTCODE, SAGE_SHARE - js_code_file = open(SAGE_EXTCODE + "/graphs/graph_plot_js.html", 'r') - js_code = js_code_file.read().replace("// GRAPH_DATA_HEREEEEEEEEEEE", string) - js_code_file.close() + with open(Path(SAGE_EXTCODE) / "graphs" / "graph_plot_js.html", 'r') as f: + js_code = f.read().replace("// GRAPH_DATA_HEREEEEEEEEEEE", string) # Add d3.js script depending on whether d3js package is installed. - d3js_filepath = os.path.join(SAGE_SHARE, 'd3js', 'd3.min.js') - if os.path.exists(d3js_filepath): + d3js_filepath = Path(SAGE_SHARE) / 'd3js' / 'd3.min.js' + if d3js_filepath.exists(): with open(d3js_filepath, 'r') as d3js_code_file: d3js_script = '' else: diff --git a/src/sage/groups/generic.py b/src/sage/groups/generic.py index c3831eb2bc5..69acc7c654d 100644 --- a/src/sage/groups/generic.py +++ b/src/sage/groups/generic.py @@ -1257,6 +1257,17 @@ def order_from_multiple(P, m, plist=None, factorization=None, check=True, sage: K. = GF(3^60) sage: order_from_multiple(a, 3^60 - 1, operation='*', check=False) 42391158275216203514294433200 + + TESTS: + + Check that :issue:`38489` is fixed:: + + sage: from sage.groups.generic import order_from_multiple + sage: plist = [43, 257, 547, 881] + sage: m = prod(plist[:-1]) + sage: elt = Zmod(m)(plist[-1]) + sage: order_from_multiple(elt, m, plist=plist) + 6044897 """ Z = integer_ring.ZZ @@ -1325,6 +1336,8 @@ def _order_from_multiple_helper(Q, L, S): if abs(sum_left + v - (S / 2)) > abs(sum_left - (S / 2)): break sum_left += v + if not 0 < k < l: + k = l // 2 L1 = L[:k] L2 = L[k:] # recursive calls diff --git a/src/sage/groups/perm_gps/permgroup_named.py b/src/sage/groups/perm_gps/permgroup_named.py index 5c153b93d4c..1a55db32508 100644 --- a/src/sage/groups/perm_gps/permgroup_named.py +++ b/src/sage/groups/perm_gps/permgroup_named.py @@ -2794,8 +2794,8 @@ def ramification_module_decomposition_hurwitz_curve(self): F = self.base_ring() q = F.order() - libgap.Read(str(Path(SAGE_EXTCODE) / 'gap' / 'joyner' / - 'hurwitz_crv_rr_sp.gap')) + libgap.Read(Path(SAGE_EXTCODE) / 'gap' / 'joyner' / + 'hurwitz_crv_rr_sp.gap') mults = libgap.eval(f"ram_module_hurwitz({q})") return mults.sage() @@ -2838,8 +2838,8 @@ def ramification_module_decomposition_modular_curve(self): raise ValueError("degree must be 2") F = self.base_ring() q = F.order() - libgap.Read(str(Path(SAGE_EXTCODE) / 'gap' / 'joyner' / - 'modular_crv_rr_sp.gap')) + libgap.Read(Path(SAGE_EXTCODE) / 'gap' / 'joyner' / + 'modular_crv_rr_sp.gap') mults = libgap.eval(f"ram_module_X({q})") return mults.sage() diff --git a/src/sage/homology/homology_vector_space_with_basis.py b/src/sage/homology/homology_vector_space_with_basis.py index bb576a56462..9aadaa9060c 100644 --- a/src/sage/homology/homology_vector_space_with_basis.py +++ b/src/sage/homology/homology_vector_space_with_basis.py @@ -633,7 +633,7 @@ def _acted_upon_(self, a, self_on_left): = \langle f, \phi_L (a \otimes x) \rangle, for `f \in H_m`, `a \in A^n`, and `x \in - H^{m-n}`. Somewhat more succintly, we define the action `f + H^{m-n}`. Somewhat more succinctly, we define the action `f \cdot a` by .. MATH:: diff --git a/src/sage/libs/ecl.pyx b/src/sage/libs/ecl.pyx index 07650bd3810..aaede566da6 100644 --- a/src/sage/libs/ecl.pyx +++ b/src/sage/libs/ecl.pyx @@ -26,7 +26,7 @@ from sage.rings.integer cimport Integer from sage.rings.rational cimport Rational from cpython.object cimport Py_EQ, Py_NE -# it would be preferrable to let bint_symbolp wrap an efficient macro +# it would be preferable to let bint_symbolp wrap an efficient macro # but the macro provided in object.h doesn't seem to work cdef bint bint_symbolp(cl_object obj) noexcept: return not(cl_symbolp(obj) == ECL_NIL) diff --git a/src/sage/libs/eclib/mwrank.pyx b/src/sage/libs/eclib/mwrank.pyx index cdac5a145cb..6765ac296ed 100644 --- a/src/sage/libs/eclib/mwrank.pyx +++ b/src/sage/libs/eclib/mwrank.pyx @@ -830,7 +830,7 @@ cdef class _mw: and the computed bound. - ``sat_low_bd`` -- integer (default: 2); only do saturation at - prime not less than this. For exampe, if the points have + prime not less than this. For example, if the points have been found via 2-descent they should already be 2-saturated, and ``sat_low_bd=3`` is appropriate. diff --git a/src/sage/libs/flint/nmod_poly_linkage.pxi b/src/sage/libs/flint/nmod_poly_linkage.pxi index db9e5d61204..b2450ed190b 100644 --- a/src/sage/libs/flint/nmod_poly_linkage.pxi +++ b/src/sage/libs/flint/nmod_poly_linkage.pxi @@ -617,8 +617,26 @@ cdef inline int celement_xgcd(nmod_poly_t res, nmod_poly_t s, nmod_poly_t t, nmo True sage: (G//d)*d == G True + + TESTS: + + Ensure that :issue:`38537` is fixed:: + + sage: k = Zmod(2**16) + sage: R. = k[] + sage: u = x + 10161 + sage: v = x + 10681 + sage: u.xgcd(v) + Traceback (most recent call last): + ... + ValueError: non-invertible elements encountered during XGCD """ - nmod_poly_xgcd(res, s, t, a, b) + try: + sig_on() + nmod_poly_xgcd(res, s, t, a, b) + sig_off() + except RuntimeError: + raise ValueError("non-invertible elements encountered during XGCD") cdef factor_helper(Polynomial_zmod_flint poly, bint squarefree=False): diff --git a/src/sage/libs/flint/qsieve.pxd b/src/sage/libs/flint/qsieve.pxd index 7bd1bf5b862..9f40fb53daa 100644 --- a/src/sage/libs/flint/qsieve.pxd +++ b/src/sage/libs/flint/qsieve.pxd @@ -24,7 +24,7 @@ cdef extern from "flint_wrap.h": void qsieve_init_poly_next(qs_t qs_inf, slong i) noexcept void qsieve_compute_C(fmpz_t C, qs_t qs_inf, qs_poly_t poly) noexcept void qsieve_do_sieving(qs_t qs_inf, unsigned char * sieve, qs_poly_t poly) noexcept - void qsieve_do_sieving2(qs_t qs_inf, unsigned char * seive, qs_poly_t poly) noexcept + void qsieve_do_sieving2(qs_t qs_inf, unsigned char * sieve, qs_poly_t poly) noexcept slong qsieve_evaluate_candidate(qs_t qs_inf, ulong i, unsigned char * sieve, qs_poly_t poly) noexcept slong qsieve_evaluate_sieve(qs_t qs_inf, unsigned char * sieve, qs_poly_t poly) noexcept slong qsieve_collect_relations(qs_t qs_inf, unsigned char * sieve) noexcept diff --git a/src/sage/libs/gap/util.pyx b/src/sage/libs/gap/util.pyx index e585431cda9..29fa347ff30 100644 --- a/src/sage/libs/gap/util.pyx +++ b/src/sage/libs/gap/util.pyx @@ -368,7 +368,7 @@ cdef Obj gap_eval(str gap_string) except? NULL: # here if the error handler was set; but in case it wasn't # let's still check the result... nresults = GAP_LenList(result) - if nresults > 1: # to mimick the old libGAP + if nresults > 1: # to mimic the old libGAP # TODO: Get rid of this restriction eventually? raise GAPError("can only evaluate a single statement") diff --git a/src/sage/libs/giac/__init__.py b/src/sage/libs/giac/__init__.py index 208fc9af930..ab62e2a21db 100644 --- a/src/sage/libs/giac/__init__.py +++ b/src/sage/libs/giac/__init__.py @@ -35,7 +35,7 @@ # Remarks for doctests: # 1) The first time that the c++ library giac is loaded a message appears. -# This message is version and arch dependant. +# This message is version and arch dependent. # 2) When proba_epsilon is too bad (>1e-6?) setting it to a better value # will give an additional message like the following one: # Restoring proba epsilon to 1e-6 from 1e-12 @@ -146,7 +146,7 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, for giac. If ``None``, the global ``giacpy_sage.giacsettings.threads`` is considered. - - ``prot`` -- boolean (default: ``False``); if ``True`` print detailled informations + - ``prot`` -- boolean (default: ``False``); if ``True`` print detailed information - ``elim_variables`` -- (default: ``None``) a list of variables to eliminate from the ideal @@ -208,7 +208,7 @@ def groebner_basis(gens, proba_epsilon=None, threads=None, prot=False, ... Time: CPU 168.98 s, Wall: 94.13 s - You can get detailled information by setting ``prot=True`` + You can get detailed information by setting ``prot=True`` :: diff --git a/src/sage/libs/giac/giac.pxd b/src/sage/libs/giac/giac.pxd index 1d9da88d8d4..d069c04a8a1 100644 --- a/src/sage/libs/giac/giac.pxd +++ b/src/sage/libs/giac/giac.pxd @@ -193,7 +193,7 @@ cdef extern from "misc.h": int giacgencmp( gen & , gen & , context *) except + int giacgenrichcmp( gen & , gen & , int, context *) except + #NB: we use the following multiplication otherwise some giac errors make python quit: - #l=giac([1,2]); l.tranpose()*l + #l=giac([1,2]); l.transpose()*l gen GIAC_giacmul "giacmul"( gen & , gen & , context *) except + gen GIAC_giacdiv "giacdiv"( gen & , gen & , context *) except + gen GIAC_giacmod "giacmod"( gen & , gen & , context *) except + diff --git a/src/sage/libs/giac/giac.pyx b/src/sage/libs/giac/giac.pyx index 3042220118c..ca835f85b90 100644 --- a/src/sage/libs/giac/giac.pyx +++ b/src/sage/libs/giac/giac.pyx @@ -216,7 +216,7 @@ def _giac(s): sage: (x+2*y).cos().texpand() cos(x)*(2*cos(y)^2-1)-sin(x)*2*cos(y)*sin(y) - Coercion, Pygen and internal giac variables: The most usefull objects will + Coercion, Pygen and internal giac variables: The most useful objects will be the Python object of type Pygen.:: sage: x,y,z = libgiac('x,y,z') @@ -296,7 +296,7 @@ def _giac(s): sage: A [[44,2],[3,4]] - Sparse Matrices are avaible via the table function: + Sparse Matrices are available via the table function: :: @@ -517,7 +517,7 @@ def _giac(s): ``q2a``, ``isom``, ``mkisom`` - - *Finite Fieds* + - *Finite Fields* * ``%``, ``% 0``, ``mod``, ``GF``, ``powmod`` @@ -1287,7 +1287,7 @@ cdef class Pygen(GiacMethods_base): # def htmlhelp(self, str lang='en'): # """ - # Open the giac html detailled help about ``self`` in an external browser + # Open the giac html detailed help about ``self`` in an external browser # There are currently 3 supported languages: 'en', 'fr', 'el' @@ -1920,7 +1920,7 @@ class GiacFunction(Pygen): # a class to evaluate args before call """ A Subclass of Pygen to create functions with evaluating all the args - before call so that they are substitued by their value. + before call so that they are substituted by their value. EXAMPLES:: @@ -1986,8 +1986,9 @@ for i in mostkeywords+moremethods: GiacMethods[i].__doc__ = eval("Pygen."+i+".__doc__") # To avoid conflicts we export only these few ones. Most giac keywords will be -# avaible through: libgiac.keywordname -__all__=['Pygen','giacsettings','libgiac','loadgiacgen','GiacFunction','GiacMethods','GiacMethods_base'] +# available through: libgiac.keywordname +__all__ = ['Pygen', 'giacsettings', 'libgiac', 'loadgiacgen', 'GiacFunction', + 'GiacMethods', 'GiacMethods_base'] def loadgiacgen(str filename): diff --git a/src/sage/libs/lcalc/lcalc_Lfunction.pyx b/src/sage/libs/lcalc/lcalc_Lfunction.pyx index c528b136f93..061a388e618 100644 --- a/src/sage/libs/lcalc/lcalc_Lfunction.pyx +++ b/src/sage/libs/lcalc/lcalc_Lfunction.pyx @@ -398,7 +398,7 @@ cdef class Lfunction: result.clear() return returnvalue - # Needs to be overriden + # Needs to be overridden cdef void _init_fun(self, char *NAME, int what_type, dirichlet_coeff, long long Period, double q, c_Complex w, int A, double *g, c_Complex *l, int n_poles, c_Complex *p, c_Complex *r) noexcept: raise NotImplementedError diff --git a/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi b/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi index f019a1832be..69cde5e4074 100644 --- a/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi +++ b/src/sage/libs/linkages/padics/fmpz_poly_unram.pxi @@ -260,7 +260,7 @@ cdef inline bint cisunit(celement a, PowComputer_ prime_pow) except -1: cdef inline int cshift(celement out, celement rem, celement a, long n, long prec, PowComputer_ prime_pow, bint reduce_afterward) except -1: """ - Mulitplies by a power of the uniformizer. + Multiplies by a power of the uniformizer. INPUT: @@ -291,7 +291,7 @@ cdef inline int cshift(celement out, celement rem, celement a, long n, long prec cdef inline int cshift_notrunc(celement out, celement a, long n, long prec, PowComputer_ prime_pow, bint reduce_afterward) except -1: """ - Mulitplies by a power of the uniformizer, assuming that the + Multiplies by a power of the uniformizer, assuming that the valuation of a is at least -n. INPUT: diff --git a/src/sage/libs/m4ri.pxd b/src/sage/libs/m4ri.pxd index a9c6c792c05..7fbdd35b856 100644 --- a/src/sage/libs/m4ri.pxd +++ b/src/sage/libs/m4ri.pxd @@ -19,7 +19,7 @@ cdef extern from "m4ri/m4ri.h": cdef int m4ri_radix ############## - # Maintainance + # Maintenance ############## # builds all gray codes up to a certain size diff --git a/src/sage/libs/singular/polynomial.pyx b/src/sage/libs/singular/polynomial.pyx index e9ce19c6553..6f7f576cb02 100644 --- a/src/sage/libs/singular/polynomial.pyx +++ b/src/sage/libs/singular/polynomial.pyx @@ -467,7 +467,7 @@ cdef object singular_polynomial_latex(poly *p, ring *r, object base, object late sage: latex(10*x^2 + 1/2*y) 10 x^{2} + \frac{1}{2} y - Demonstrate that coefficients over non-atomic representated rings are + Demonstrate that coefficients over non-atomic represented rings are properly parenthesized (:issue:`11186`):: sage: x = var('x') diff --git a/src/sage/libs/symmetrica/symmetrica.pxi b/src/sage/libs/symmetrica/symmetrica.pxi index 0a147d6c743..def9544e2c6 100644 --- a/src/sage/libs/symmetrica/symmetrica.pxi +++ b/src/sage/libs/symmetrica/symmetrica.pxi @@ -941,7 +941,7 @@ cdef void* _op_elmsym(object d, OP res) noexcept: #Elementary symmetric function pointer = s_s_n(pointer) -cdef object _py_homsym(OP a): #Homogenous symmetric functions +cdef object _py_homsym(OP a): # Homogeneous symmetric functions late_import() z_elt = _py_schur_general(a) if len(z_elt) == 0: @@ -954,7 +954,7 @@ cdef object _py_homsym(OP a): #Homogenous symmetric functions z._monomial_coefficients = z_elt return z -cdef void* _op_homsym(object d, OP res) noexcept: #Homogenous symmetric functions +cdef void* _op_homsym(object d, OP res) noexcept: # Homogeneous symmetric functions cdef OP pointer = res _op_schur_general(d, res) while pointer != NULL: diff --git a/src/sage/manifolds/differentiable/diff_form.py b/src/sage/manifolds/differentiable/diff_form.py index ae924713ffd..fb58189796e 100644 --- a/src/sage/manifolds/differentiable/diff_form.py +++ b/src/sage/manifolds/differentiable/diff_form.py @@ -770,7 +770,7 @@ def hodge_dual( nondegenerate_tensor = self._vmodule._ambient_domain.metric() p = self.tensor_type()[1] - # For performance reasons, we raise the indicies of the volume form + # For performance reasons, we raise the indices of the volume form # and not of the differential form; in the symplectic case this is wrong by # a factor of (-1)^p, which will be corrected below eps = nondegenerate_tensor.volume_form(p) @@ -787,7 +787,7 @@ def hodge_dual( result = result * nondegenerate_tensor._indic_signat from sage.manifolds.differentiable.symplectic_form import SymplecticForm if isinstance(nondegenerate_tensor, SymplecticForm): - # correction because we lifted the indicies of the volume (see above) + # correction because we lifted the indices of the volume (see above) result = result * (-1)**p result.set_name( diff --git a/src/sage/manifolds/differentiable/vector_bundle.py b/src/sage/manifolds/differentiable/vector_bundle.py index 4a2c5372419..f65bba7a79d 100644 --- a/src/sage/manifolds/differentiable/vector_bundle.py +++ b/src/sage/manifolds/differentiable/vector_bundle.py @@ -1642,7 +1642,7 @@ def orientation(self): EXAMPLES: - In the trivial case, i.e. if the destination map is the identitiy + In the trivial case, i.e. if the destination map is the identity and the tangent bundle is covered by one frame, the orientation is easily obtained:: diff --git a/src/sage/matrix/args.pyx b/src/sage/matrix/args.pyx index 6d74468e179..332eaf82df8 100644 --- a/src/sage/matrix/args.pyx +++ b/src/sage/matrix/args.pyx @@ -857,7 +857,7 @@ cdef class MatrixArgs: cdef list L if self.typ == MA_ENTRIES_SEQ_FLAT and not convert: - # Try to re-use existing list + # Try to reuse existing list if type(self.entries) is not list: L = list(self.entries) else: diff --git a/src/sage/matrix/matrix2.pyx b/src/sage/matrix/matrix2.pyx index 84ee5d0a760..f5f0eac7ea8 100644 --- a/src/sage/matrix/matrix2.pyx +++ b/src/sage/matrix/matrix2.pyx @@ -898,7 +898,7 @@ cdef class Matrix(Matrix1): # first coerce both elements to parent over same base ring P = K if L is K else coercion_model.common_parent(K, L) if P not in _Fields and P.is_integral_domain() and extend: - # the non-integral-domain case is handled separatedly below + # the non-integral-domain case is handled separately below P = P.fraction_field() if L is not P: B = B.change_ring(P) @@ -16843,7 +16843,7 @@ cdef class Matrix(Matrix1): nonzero = j break if (nonzero != -1): - # swap column wih nonzero entry just outside block + # swap column with nonzero entry just outside block if nonzero != c+1: Z.swap_columns(c+1, nonzero) Z.swap_rows(c+1, nonzero) diff --git a/src/sage/matrix/matrix_cyclo_dense.pyx b/src/sage/matrix/matrix_cyclo_dense.pyx index ab5542dda7b..f32d738df0d 100644 --- a/src/sage/matrix/matrix_cyclo_dense.pyx +++ b/src/sage/matrix/matrix_cyclo_dense.pyx @@ -985,7 +985,7 @@ cdef class Matrix_cyclo_dense(Matrix_dense): INPUT: - - ``col`` -- integer indicating the column; must be coercable to + - ``col`` -- integer indicating the column; must be coercible to ``int``, and this must lie between 0 (inclusive) and ``self._ncols`` (exclusive), since no bounds-checking is performed - ``nump1`` -- integer; numerator bound plus one diff --git a/src/sage/matrix/matrix_double_dense.pyx b/src/sage/matrix/matrix_double_dense.pyx index 255523b0273..fa3f391194a 100644 --- a/src/sage/matrix/matrix_double_dense.pyx +++ b/src/sage/matrix/matrix_double_dense.pyx @@ -1286,7 +1286,7 @@ cdef class Matrix_double_dense(Matrix_numpy_dense): from sage.rings.real_double import RDF from sage.rings.complex_double import CDF if isinstance(other, str): - # for backward compatibilty, allow algorithm to be passed as first + # for backward compatibility, allow algorithm to be passed as first # positional argument and tol as second positional argument from sage.misc.superseded import deprecation deprecation(29243, '"algorithm" and "tol" should be used as ' diff --git a/src/sage/matrix/matrix_gf2e_dense.pyx b/src/sage/matrix/matrix_gf2e_dense.pyx index b8660ad08dc..945e92cdfd6 100644 --- a/src/sage/matrix/matrix_gf2e_dense.pyx +++ b/src/sage/matrix/matrix_gf2e_dense.pyx @@ -443,7 +443,7 @@ cdef class Matrix_gf2e_dense(matrix_dense.Matrix_dense): finite field is small, there is a very high chance that ``e * B[j]`` is computed more than once for any ``e`` in the finite field. Instead, we compute all possible - multiples of ``B[j]`` and re-use this data in the inner loop. + multiples of ``B[j]`` and reuse this data in the inner loop. This is what is called a "Newton-John" table in M4RIE. INPUT: diff --git a/src/sage/matrix/matrix_polynomial_dense.pyx b/src/sage/matrix/matrix_polynomial_dense.pyx index 6d01a42a126..5b3c56ae573 100644 --- a/src/sage/matrix/matrix_polynomial_dense.pyx +++ b/src/sage/matrix/matrix_polynomial_dense.pyx @@ -2845,7 +2845,7 @@ cdef class Matrix_polynomial_dense(Matrix_generic_dense): with the required degree property In the latter case (rank-deficient or strictly fewer rows than columns, - with no solution to `A = XB`), there might stil be a quotient and + with no solution to `A = XB`), there might still be a quotient and remainder, in which case this method will find it via normal form computation:: diff --git a/src/sage/matrix/strassen.pyx b/src/sage/matrix/strassen.pyx index 56c4bf183ad..eb42f8640b6 100644 --- a/src/sage/matrix/strassen.pyx +++ b/src/sage/matrix/strassen.pyx @@ -809,7 +809,7 @@ def test(n, m, R, c=2): ## TODO -- the doctests below are currently not ## tested/enabled/working -- enable them when linear algebra -## restructing gets going. +## restructuring gets going. ## sage: dim1 = 64; dim2 = 83; dim3 = 101 ## sage: R = MatrixSpace(QQ, dim1, dim2) diff --git a/src/sage/matroids/basis_exchange_matroid.pxd b/src/sage/matroids/basis_exchange_matroid.pxd index dc4b4aeb114..fdcfd82172f 100644 --- a/src/sage/matroids/basis_exchange_matroid.pxd +++ b/src/sage/matroids/basis_exchange_matroid.pxd @@ -46,19 +46,19 @@ cdef class BasisExchangeMatroid(Matroid): cpdef _move_current_basis(self, X, Y) cpdef frozenset _max_independent(self, frozenset F) - cpdef int _rank(self, frozenset F) + cpdef int _rank(self, frozenset F) except? -1 cpdef frozenset _circuit(self, frozenset F) cpdef frozenset _fundamental_circuit(self, frozenset B, e) cpdef frozenset _closure(self, frozenset F) cpdef frozenset _max_coindependent(self, frozenset F) - cpdef int _corank(self, frozenset F) + cpdef int _corank(self, frozenset F) noexcept cpdef frozenset _cocircuit(self, frozenset F) cpdef frozenset _fundamental_cocircuit(self, frozenset B, e) cpdef frozenset _coclosure(self, frozenset F) cpdef frozenset _augment(self, frozenset X, frozenset Y) - cpdef bint _is_independent(self, frozenset F) + cpdef bint _is_independent(self, frozenset F) noexcept cpdef list whitney_numbers2(self) cdef _whitney_numbers2_rec(self, object f_vec, bitset_t* flats, bitset_t* todo, long elt, long rnk) @@ -90,6 +90,6 @@ cdef class BasisExchangeMatroid(Matroid): cpdef _is_isomorphism(self, other, morphism) cdef bint __is_isomorphism(self, BasisExchangeMatroid other, morphism) noexcept - cpdef bint is_valid(self) + cpdef bint is_valid(self) noexcept cdef bint nxksrd(bitset_s *b, long n, long k, bint succ) noexcept diff --git a/src/sage/matroids/basis_exchange_matroid.pyx b/src/sage/matroids/basis_exchange_matroid.pyx index a3c4c897d16..8d0dbf1c834 100644 --- a/src/sage/matroids/basis_exchange_matroid.pyx +++ b/src/sage/matroids/basis_exchange_matroid.pyx @@ -652,7 +652,7 @@ cdef class BasisExchangeMatroid(Matroid): self.__max_independent(self._output, self._input) return self.__unpack(self._output) - cpdef int _rank(self, frozenset F): + cpdef int _rank(self, frozenset F) except? -1: """ Compute the rank of a subset of the groundset. @@ -796,7 +796,7 @@ cdef class BasisExchangeMatroid(Matroid): self.__max_coindependent(self._output, self._input) return self.__unpack(self._output) - cpdef int _corank(self, frozenset F): + cpdef int _corank(self, frozenset F) noexcept: """ Return the corank of a set. @@ -940,7 +940,7 @@ cdef class BasisExchangeMatroid(Matroid): self.__augment(self._output, self._input, self._input2) return self.__unpack(self._output) - cpdef bint _is_independent(self, frozenset F): + cpdef bint _is_independent(self, frozenset F) noexcept: """ Test if input is independent. @@ -2231,7 +2231,7 @@ cdef class BasisExchangeMatroid(Matroid): return self._characteristic_setsystem()._isomorphism(other._characteristic_setsystem(), PS, PO) is not None - cpdef bint is_valid(self): + cpdef bint is_valid(self) noexcept: r""" Test if the data obey the matroid axioms. diff --git a/src/sage/matroids/basis_matroid.pxd b/src/sage/matroids/basis_matroid.pxd index 5789ad98937..fd240b01a38 100644 --- a/src/sage/matroids/basis_matroid.pxd +++ b/src/sage/matroids/basis_matroid.pxd @@ -15,7 +15,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): cdef reset_current_basis(self) - cpdef bint _is_basis(self, frozenset X) + cpdef bint _is_basis(self, frozenset X) noexcept cpdef bases_count(self) cpdef SetSystem bases(self) diff --git a/src/sage/matroids/basis_matroid.pyx b/src/sage/matroids/basis_matroid.pyx index f9710eaac7c..b74a76af956 100644 --- a/src/sage/matroids/basis_matroid.pyx +++ b/src/sage/matroids/basis_matroid.pyx @@ -298,7 +298,7 @@ cdef class BasisMatroid(BasisExchangeMatroid): # a function that is very efficient for this class - cpdef bint _is_basis(self, frozenset X): + cpdef bint _is_basis(self, frozenset X) noexcept: """ Test if input is a basis. diff --git a/src/sage/matroids/circuit_closures_matroid.pxd b/src/sage/matroids/circuit_closures_matroid.pxd index 878443d86f3..b724a49faf4 100644 --- a/src/sage/matroids/circuit_closures_matroid.pxd +++ b/src/sage/matroids/circuit_closures_matroid.pxd @@ -5,9 +5,9 @@ cdef class CircuitClosuresMatroid(Matroid): cdef dict _circuit_closures # _CC cdef int _matroid_rank # _R cpdef frozenset groundset(self) - cpdef int _rank(self, frozenset X) + cpdef int _rank(self, frozenset X) except? -1 cpdef full_rank(self) - cpdef bint _is_independent(self, frozenset F) + cpdef bint _is_independent(self, frozenset F) noexcept cpdef frozenset _max_independent(self, frozenset F) cpdef frozenset _circuit(self, frozenset F) cpdef dict circuit_closures(self) diff --git a/src/sage/matroids/circuit_closures_matroid.pyx b/src/sage/matroids/circuit_closures_matroid.pyx index 7dd29ee8143..a4251298ebc 100644 --- a/src/sage/matroids/circuit_closures_matroid.pyx +++ b/src/sage/matroids/circuit_closures_matroid.pyx @@ -179,7 +179,7 @@ cdef class CircuitClosuresMatroid(Matroid): """ return frozenset(self._groundset) - cpdef int _rank(self, frozenset X): + cpdef int _rank(self, frozenset X) except? -1: """ Return the rank of a set ``X``. @@ -221,7 +221,7 @@ cdef class CircuitClosuresMatroid(Matroid): """ return self._matroid_rank - cpdef bint _is_independent(self, frozenset F): + cpdef bint _is_independent(self, frozenset F) noexcept: """ Test if input is independent. diff --git a/src/sage/matroids/circuits_matroid.pxd b/src/sage/matroids/circuits_matroid.pxd index f7b938a4d6f..a3bffafce6d 100644 --- a/src/sage/matroids/circuits_matroid.pxd +++ b/src/sage/matroids/circuits_matroid.pxd @@ -9,9 +9,9 @@ cdef class CircuitsMatroid(Matroid): cdef list _sorted_C_lens cdef bint _nsc_defined cpdef frozenset groundset(self) - cpdef int _rank(self, frozenset X) + cpdef int _rank(self, frozenset X) except? -1 cpdef full_rank(self) - cpdef bint _is_independent(self, frozenset X) + cpdef bint _is_independent(self, frozenset X) noexcept cpdef frozenset _max_independent(self, frozenset X) cpdef frozenset _circuit(self, frozenset X) cpdef frozenset _closure(self, frozenset X) @@ -27,11 +27,11 @@ cdef class CircuitsMatroid(Matroid): # properties cpdef girth(self) - cpdef bint is_paving(self) + cpdef bint is_paving(self) noexcept # isomorphism and relabeling cpdef _is_isomorphic(self, other, certificate=*) cpdef relabel(self, mapping) # verification - cpdef bint is_valid(self) + cpdef bint is_valid(self) noexcept diff --git a/src/sage/matroids/circuits_matroid.pyx b/src/sage/matroids/circuits_matroid.pyx index ae3be51d36f..3b3693b52f6 100644 --- a/src/sage/matroids/circuits_matroid.pyx +++ b/src/sage/matroids/circuits_matroid.pyx @@ -100,7 +100,7 @@ cdef class CircuitsMatroid(Matroid): """ return self._groundset - cpdef int _rank(self, frozenset X): + cpdef int _rank(self, frozenset X) except? -1: """ Return the rank of a set ``X``. @@ -140,7 +140,7 @@ cdef class CircuitsMatroid(Matroid): """ return self._matroid_rank - cpdef bint _is_independent(self, frozenset X): + cpdef bint _is_independent(self, frozenset X) noexcept: """ Test if input is independent. @@ -850,7 +850,7 @@ cdef class CircuitsMatroid(Matroid): from sage.rings.infinity import infinity return min(self._k_C, default=infinity) - cpdef bint is_paving(self): + cpdef bint is_paving(self) noexcept: """ Return if ``self`` is paving. @@ -869,7 +869,7 @@ cdef class CircuitsMatroid(Matroid): # verification - cpdef bint is_valid(self): + cpdef bint is_valid(self) noexcept: r""" Test if ``self`` obeys the matroid axioms. diff --git a/src/sage/matroids/flats_matroid.pxd b/src/sage/matroids/flats_matroid.pxd index 956e30f859d..23fd4ceb1ec 100644 --- a/src/sage/matroids/flats_matroid.pxd +++ b/src/sage/matroids/flats_matroid.pxd @@ -8,9 +8,9 @@ cdef class FlatsMatroid(Matroid): cdef object _L # lattice of flats cpdef frozenset groundset(self) - cpdef int _rank(self, frozenset X) + cpdef int _rank(self, frozenset X) except? -1 cpdef frozenset _closure(self, frozenset X) - cpdef bint _is_closed(self, frozenset X) + cpdef bint _is_closed(self, frozenset X) noexcept cpdef full_rank(self) @@ -24,4 +24,4 @@ cdef class FlatsMatroid(Matroid): cpdef relabel(self, mapping) # verification - cpdef bint is_valid(self) + cpdef bint is_valid(self) noexcept diff --git a/src/sage/matroids/flats_matroid.pyx b/src/sage/matroids/flats_matroid.pyx index 9c6a3c76aeb..6842839e03f 100644 --- a/src/sage/matroids/flats_matroid.pyx +++ b/src/sage/matroids/flats_matroid.pyx @@ -114,7 +114,7 @@ cdef class FlatsMatroid(Matroid): """ return self._groundset - cpdef int _rank(self, frozenset X): + cpdef int _rank(self, frozenset X) except? -1: """ Return the rank of a set ``X``. @@ -191,7 +191,7 @@ cdef class FlatsMatroid(Matroid): if f >= X: return f - cpdef bint _is_closed(self, frozenset X): + cpdef bint _is_closed(self, frozenset X) noexcept: """ Test if input is a closed set. @@ -539,7 +539,7 @@ cdef class FlatsMatroid(Matroid): # verification - cpdef bint is_valid(self): + cpdef bint is_valid(self) noexcept: r""" Test if ``self`` obeys the matroid axioms. @@ -579,7 +579,7 @@ cdef class FlatsMatroid(Matroid): True sage: Matroid(flats=['', 'a', 'b', 'ab']).is_valid() True - sage: M = Matroid(flats=['', # missing an extention of flat ['5'] by '6' + sage: M = Matroid(flats=['', # missing an extension of flat ['5'] by '6' ....: '0','1','2','3','4','5','6','7','8','9','a','b','c', ....: '45','46','47','4c','57','5c','67','6c','7c', ....: '048','149','24a','34b','059','15a','25b','358', @@ -619,7 +619,7 @@ cdef class FlatsMatroid(Matroid): False sage: Matroid(flats={0: [[]], 1: [[0, 1], [2]], 2: [[0], [1], [0, 1, 2]]}).is_valid() False - sage: M = Matroid(flats={0: [''], # missing an extention of flat ['5'] by '6' + sage: M = Matroid(flats={0: [''], # missing an extension of flat ['5'] by '6' ....: 1: ['0','1','2','3','4','5','6','7','8','9','a','b','c'], ....: 2: ['45','46','47','4c','57','5c','67','6c','7c', ....: '048','149','24a','34b','059','15a','25b','358', diff --git a/src/sage/matroids/graphic_matroid.pxd b/src/sage/matroids/graphic_matroid.pxd index 8ec8dd9e8b0..3684ab19f0d 100644 --- a/src/sage/matroids/graphic_matroid.pxd +++ b/src/sage/matroids/graphic_matroid.pxd @@ -7,23 +7,23 @@ cdef class GraphicMatroid(Matroid): cdef dict _vertex_map cdef dict _groundset_edge_map cpdef frozenset groundset(self) - cpdef int _rank(self, frozenset X) + cpdef int _rank(self, frozenset X) except? -1 cpdef _vertex_stars(self) cpdef _minor(self, contractions, deletions) cpdef _has_minor(self, N, bint certificate=*) - cpdef int _corank(self, frozenset X) - cpdef bint _is_circuit(self, frozenset X) + cpdef int _corank(self, frozenset X) noexcept + cpdef bint _is_circuit(self, frozenset X) noexcept cpdef frozenset _closure(self, frozenset X) cpdef frozenset _max_independent(self, frozenset X) cpdef frozenset _max_coindependent(self, frozenset X) cpdef frozenset _circuit(self, frozenset X) cpdef frozenset _coclosure(self, frozenset X) - cpdef bint _is_closed(self, frozenset X) + cpdef bint _is_closed(self, frozenset X) noexcept cpdef _is_isomorphic(self, other, certificate=*) cpdef _isomorphism(self, other) - cpdef bint is_valid(self) - cpdef bint is_graphic(self) - cpdef bint is_regular(self) + cpdef bint is_valid(self) noexcept + cpdef bint is_graphic(self) noexcept + cpdef bint is_regular(self) noexcept cpdef graph(self) cpdef vertex_map(self) cpdef list groundset_to_edges(self, X) diff --git a/src/sage/matroids/graphic_matroid.pyx b/src/sage/matroids/graphic_matroid.pyx index a01cef13fe3..5e740e78637 100644 --- a/src/sage/matroids/graphic_matroid.pyx +++ b/src/sage/matroids/graphic_matroid.pyx @@ -238,7 +238,7 @@ cdef class GraphicMatroid(Matroid): """ return self._groundset - cpdef int _rank(self, frozenset X): + cpdef int _rank(self, frozenset X) except? -1: """ Return the rank of a set ``X``. @@ -625,7 +625,7 @@ cdef class GraphicMatroid(Matroid): N = N.regular_matroid() return M._has_minor(N, certificate=certificate) - cpdef int _corank(self, frozenset X): + cpdef int _corank(self, frozenset X) noexcept: """ Return the corank of the set `X` in the matroid. @@ -653,7 +653,7 @@ cdef class GraphicMatroid(Matroid): DS_vertices.union(u, v) return len(X) - (DS_vertices.number_of_subsets() - Integer(1)) - cpdef bint _is_circuit(self, frozenset X): + cpdef bint _is_circuit(self, frozenset X) noexcept: """ Test if input is a circuit. @@ -918,7 +918,7 @@ cdef class GraphicMatroid(Matroid): g.add_edge(e) return frozenset(XX) - cpdef bint _is_closed(self, frozenset X): + cpdef bint _is_closed(self, frozenset X) noexcept: """ Test if input is a closed set. @@ -1093,7 +1093,7 @@ cdef class GraphicMatroid(Matroid): """ return self.is_isomorphic(other, certificate=True)[1] - cpdef bint is_valid(self): + cpdef bint is_valid(self) noexcept: """ Test if the data obey the matroid axioms. @@ -1110,7 +1110,7 @@ cdef class GraphicMatroid(Matroid): """ return True - cpdef bint is_graphic(self): + cpdef bint is_graphic(self) noexcept: r""" Return if ``self`` is graphic. @@ -1124,7 +1124,7 @@ cdef class GraphicMatroid(Matroid): """ return True - cpdef bint is_regular(self): + cpdef bint is_regular(self) noexcept: r""" Return if ``self`` is regular. diff --git a/src/sage/matroids/linear_matroid.pxd b/src/sage/matroids/linear_matroid.pxd index 085a68be0f6..b0890a76148 100644 --- a/src/sage/matroids/linear_matroid.pxd +++ b/src/sage/matroids/linear_matroid.pxd @@ -62,7 +62,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): cpdef _is_3connected_shifting(self, certificate=*) cpdef _is_4connected_shifting(self, certificate=*) - cpdef bint is_valid(self) + cpdef bint is_valid(self) noexcept cdef class BinaryMatroid(LinearMatroid): cdef tuple _b_invariant, _b_partition @@ -91,8 +91,8 @@ cdef class BinaryMatroid(LinearMatroid): cpdef _fast_isom_test(self, other) cpdef relabel(self, mapping) - cpdef bint is_graphic(self) - cpdef bint is_valid(self) + cpdef bint is_graphic(self) noexcept + cpdef bint is_valid(self) noexcept cdef class TernaryMatroid(LinearMatroid): @@ -122,7 +122,7 @@ cdef class TernaryMatroid(LinearMatroid): cpdef _fast_isom_test(self, other) cpdef relabel(self, mapping) - cpdef bint is_valid(self) + cpdef bint is_valid(self) noexcept cdef class QuaternaryMatroid(LinearMatroid): cdef object _x_zero, _x_one @@ -149,7 +149,7 @@ cdef class QuaternaryMatroid(LinearMatroid): cpdef _fast_isom_test(self, other) cpdef relabel(self, mapping) - cpdef bint is_valid(self) + cpdef bint is_valid(self) noexcept cdef class RegularMatroid(LinearMatroid): cdef _bases_count, _r_invariant @@ -172,6 +172,6 @@ cdef class RegularMatroid(LinearMatroid): cpdef has_line_minor(self, k, hyperlines=*, certificate=*) cpdef _linear_extension_chains(self, F, fundamentals=*) - cpdef bint is_regular(self) - cpdef bint is_graphic(self) - cpdef bint is_valid(self) + cpdef bint is_regular(self) noexcept + cpdef bint is_graphic(self) noexcept + cpdef bint is_valid(self) noexcept diff --git a/src/sage/matroids/linear_matroid.pyx b/src/sage/matroids/linear_matroid.pyx index 0310b8c2cd3..6848604f0c8 100644 --- a/src/sage/matroids/linear_matroid.pyx +++ b/src/sage/matroids/linear_matroid.pyx @@ -2614,7 +2614,7 @@ cdef class LinearMatroid(BasisExchangeMatroid): cochains = self.linear_coextension_cochains(F, cosimple=cosimple, fundamentals=fundamentals) return self._linear_coextensions(element, cochains) - cpdef bint is_valid(self): + cpdef bint is_valid(self) noexcept: r""" Test if the data represent an actual matroid. @@ -3793,7 +3793,7 @@ cdef class BinaryMatroid(LinearMatroid): keep_initial_representation=False) # graphicness test - cpdef bint is_graphic(self): + cpdef bint is_graphic(self) noexcept: """ Test if the binary matroid is graphic. @@ -3862,7 +3862,7 @@ cdef class BinaryMatroid(LinearMatroid): # 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 - cpdef bint is_valid(self): + cpdef bint is_valid(self) noexcept: r""" Test if the data obey the matroid axioms. @@ -4724,7 +4724,7 @@ cdef class TernaryMatroid(LinearMatroid): basis=bas, keep_initial_representation=False) - cpdef bint is_valid(self): + cpdef bint is_valid(self) noexcept: r""" Test if the data obey the matroid axioms. @@ -5488,7 +5488,7 @@ cdef class QuaternaryMatroid(LinearMatroid): basis=bas, keep_initial_representation=False) - cpdef bint is_valid(self): + cpdef bint is_valid(self) noexcept: r""" Test if the data obey the matroid axioms. @@ -6239,7 +6239,7 @@ cdef class RegularMatroid(LinearMatroid): fundamentals = set([1]) return LinearMatroid._linear_extension_chains(self, F, fundamentals) - cpdef bint is_graphic(self): + cpdef bint is_graphic(self) noexcept: """ Test if the regular matroid is graphic. @@ -6270,7 +6270,7 @@ cdef class RegularMatroid(LinearMatroid): """ return BinaryMatroid(reduced_matrix=self._reduced_representation()).is_graphic() - cpdef bint is_valid(self): + cpdef bint is_valid(self) noexcept: r""" Test if the data obey the matroid axioms. @@ -6299,7 +6299,7 @@ cdef class RegularMatroid(LinearMatroid): # representation - cpdef bint is_regular(self): + cpdef bint is_regular(self) noexcept: r""" Return if ``self`` is regular. diff --git a/src/sage/matroids/matroid.pxd b/src/sage/matroids/matroid.pxd index ca197f605b9..6218cb804f4 100644 --- a/src/sage/matroids/matroid.pxd +++ b/src/sage/matroids/matroid.pxd @@ -9,28 +9,28 @@ cdef class Matroid(SageObject): # virtual methods cpdef frozenset groundset(self) - cpdef int _rank(self, frozenset X) + cpdef int _rank(self, frozenset X) except? -1 # internal methods, assuming verified input cpdef frozenset _max_independent(self, frozenset X) cpdef frozenset _circuit(self, frozenset X) cpdef frozenset _fundamental_circuit(self, frozenset B, e) cpdef frozenset _closure(self, frozenset X) - cpdef int _corank(self, frozenset X) + cpdef int _corank(self, frozenset X) noexcept cpdef frozenset _max_coindependent(self, frozenset X) cpdef frozenset _cocircuit(self, frozenset X) cpdef frozenset _fundamental_cocircuit(self, frozenset B, e) cpdef frozenset _coclosure(self, frozenset X) cpdef frozenset _augment(self, frozenset X, frozenset Y) - cpdef bint _is_independent(self, frozenset X) - cpdef bint _is_basis(self, frozenset X) - cpdef bint _is_circuit(self, frozenset X) - cpdef bint _is_closed(self, frozenset X) - cpdef bint _is_coindependent(self, frozenset X) - cpdef bint _is_cobasis(self, frozenset X) - cpdef bint _is_cocircuit(self, frozenset X) - cpdef bint _is_coclosed(self, frozenset X) + cpdef bint _is_independent(self, frozenset X) noexcept + cpdef bint _is_basis(self, frozenset X) noexcept + cpdef bint _is_circuit(self, frozenset X) noexcept + cpdef bint _is_closed(self, frozenset X) noexcept + cpdef bint _is_coindependent(self, frozenset X) noexcept + cpdef bint _is_cobasis(self, frozenset X) noexcept + cpdef bint _is_cocircuit(self, frozenset X) noexcept + cpdef bint _is_coclosed(self, frozenset X) noexcept cpdef _minor(self, contractions, deletions) cpdef _has_minor(self, N, bint certificate=*) @@ -105,7 +105,7 @@ cdef class Matroid(SageObject): cpdef is_coclosed(self, X) # verification - cpdef bint is_valid(self) + cpdef bint is_valid(self) noexcept # enumeration cpdef SetSystem circuits(self, k=*) @@ -184,8 +184,8 @@ cdef class Matroid(SageObject): cpdef _is_3connected_CE(self, certificate=*) cpdef _is_3connected_BC(self, certificate=*) cpdef _is_3connected_BC_recursion(self, basis, fund_cocircuits) - cpdef bint is_paving(self) - cpdef bint is_sparse_paving(self) + cpdef bint is_paving(self) noexcept + cpdef bint is_sparse_paving(self) noexcept cpdef girth(self) # representability @@ -195,8 +195,8 @@ cdef class Matroid(SageObject): cpdef _local_ternary_matroid(self, basis=*) cpdef ternary_matroid(self, randomized_tests=*, verify=*) cpdef is_ternary(self, randomized_tests=*) - cpdef bint is_regular(self) - cpdef bint is_graphic(self) + cpdef bint is_regular(self) noexcept + cpdef bint is_graphic(self) noexcept # matroid k-closed cpdef is_k_closed(self, int k) diff --git a/src/sage/matroids/matroid.pyx b/src/sage/matroids/matroid.pyx index bfcf7d361a2..9fb3ef581b9 100644 --- a/src/sage/matroids/matroid.pyx +++ b/src/sage/matroids/matroid.pyx @@ -492,7 +492,7 @@ cdef class Matroid(SageObject): """ raise NotImplementedError("subclasses need to implement this") - cpdef int _rank(self, frozenset X): + cpdef int _rank(self, frozenset X) except? -1: r""" Return the rank of a set ``X``. @@ -513,8 +513,9 @@ cdef class Matroid(SageObject): sage: M = sage.matroids.matroid.Matroid() sage: M._rank(frozenset([0, 1, 2])) - NotImplementedError: subclasses need to implement this + Traceback (most recent call last): ... + NotImplementedError: subclasses need to implement this """ raise NotImplementedError("subclasses need to implement this") @@ -732,7 +733,7 @@ cdef class Matroid(SageObject): XX.pop() return frozenset(XX) - cpdef int _corank(self, frozenset X): + cpdef int _corank(self, frozenset X) noexcept: """ Return the corank of a set. @@ -904,7 +905,7 @@ cdef class Matroid(SageObject): # override the following methods for even better efficiency - cpdef bint _is_independent(self, frozenset X): + cpdef bint _is_independent(self, frozenset X) noexcept: """ Test if input is independent. @@ -925,7 +926,7 @@ cdef class Matroid(SageObject): """ return len(X) == self._rank(X) - cpdef bint _is_basis(self, frozenset X): + cpdef bint _is_basis(self, frozenset X) noexcept: """ Test if input is a basis. @@ -958,7 +959,7 @@ cdef class Matroid(SageObject): """ return self._is_independent(X) - cpdef bint _is_circuit(self, frozenset X): + cpdef bint _is_circuit(self, frozenset X) noexcept: """ Test if input is a circuit. @@ -990,7 +991,7 @@ cdef class Matroid(SageObject): Z.add(x) return True - cpdef bint _is_closed(self, frozenset X): + cpdef bint _is_closed(self, frozenset X) noexcept: """ Test if input is a closed set. @@ -1019,7 +1020,7 @@ cdef class Matroid(SageObject): XX.discard(y) return True - cpdef bint _is_coindependent(self, frozenset X): + cpdef bint _is_coindependent(self, frozenset X) noexcept: """ Test if input is coindependent. @@ -1040,7 +1041,7 @@ cdef class Matroid(SageObject): """ return self._corank(X) == len(X) - cpdef bint _is_cobasis(self, frozenset X): + cpdef bint _is_cobasis(self, frozenset X) noexcept: """ Test if input is a cobasis. @@ -1068,7 +1069,7 @@ cdef class Matroid(SageObject): """ return self._is_basis(self.groundset().difference(X)) - cpdef bint _is_cocircuit(self, frozenset X): + cpdef bint _is_cocircuit(self, frozenset X) noexcept: """ Test if input is a cocircuit. @@ -1100,7 +1101,7 @@ cdef class Matroid(SageObject): Z.add(x) return True - cpdef bint _is_coclosed(self, frozenset X): + cpdef bint _is_coclosed(self, frozenset X) noexcept: """ Test if input is a coclosed set. @@ -2305,7 +2306,7 @@ cdef class Matroid(SageObject): # verification - cpdef bint is_valid(self): + cpdef bint is_valid(self) noexcept: r""" Test if the data obey the matroid axioms. @@ -6187,7 +6188,7 @@ cdef class Matroid(SageObject): return False return True - cpdef bint is_paving(self): + cpdef bint is_paving(self) noexcept: """ Return if ``self`` is paving. @@ -6210,7 +6211,7 @@ cdef class Matroid(SageObject): return False return True - cpdef bint is_sparse_paving(self): + cpdef bint is_sparse_paving(self) noexcept: """ Return if ``self`` is sparse-paving. @@ -6577,7 +6578,7 @@ cdef class Matroid(SageObject): """ return self.ternary_matroid(randomized_tests=randomized_tests, verify=True) is not None - cpdef bint is_graphic(self): + cpdef bint is_graphic(self) noexcept: r""" Return if ``self`` is graphic. @@ -6611,7 +6612,7 @@ cdef class Matroid(SageObject): return False return True - cpdef bint is_regular(self): + cpdef bint is_regular(self) noexcept: r""" Return if ``self`` is regular. diff --git a/src/sage/matroids/union_matroid.pxd b/src/sage/matroids/union_matroid.pxd index 518ca54bba9..72d13abc91c 100644 --- a/src/sage/matroids/union_matroid.pxd +++ b/src/sage/matroids/union_matroid.pxd @@ -5,16 +5,16 @@ cdef class MatroidUnion(Matroid): cdef list matroids cdef frozenset _groundset cpdef frozenset groundset(self) - cpdef int _rank(self, frozenset X) + cpdef int _rank(self, frozenset X) except? -1 cdef class MatroidSum(Matroid): cdef list summands cdef frozenset _groundset cpdef frozenset groundset(self) - cpdef int _rank(self, frozenset X) + cpdef int _rank(self, frozenset X) except? -1 cdef class PartitionMatroid(Matroid): cdef dict p cdef frozenset _groundset cpdef frozenset groundset(self) - cpdef int _rank(self, frozenset X) + cpdef int _rank(self, frozenset X) except? -1 diff --git a/src/sage/matroids/union_matroid.pyx b/src/sage/matroids/union_matroid.pyx index ef40d0fc1b2..e371d5fb313 100644 --- a/src/sage/matroids/union_matroid.pyx +++ b/src/sage/matroids/union_matroid.pyx @@ -66,7 +66,7 @@ cdef class MatroidUnion(Matroid): """ return self._groundset - cpdef int _rank(self, frozenset X): + cpdef int _rank(self, frozenset X) except? -1: r""" Return the rank of a set ``X``. @@ -195,7 +195,7 @@ cdef class MatroidSum(Matroid): """ return self._groundset - cpdef int _rank(self, frozenset X): + cpdef int _rank(self, frozenset X) except? -1: r""" Return the rank of a set ``X``. @@ -290,7 +290,7 @@ cdef class PartitionMatroid(Matroid): """ return self._groundset - cpdef int _rank(self, frozenset X): + cpdef int _rank(self, frozenset X) except? -1: r""" Return the rank of a set ``X``. diff --git a/src/sage/misc/cachefunc.pyx b/src/sage/misc/cachefunc.pyx index c7590c6e9ad..7545f1b0dc9 100644 --- a/src/sage/misc/cachefunc.pyx +++ b/src/sage/misc/cachefunc.pyx @@ -1751,7 +1751,7 @@ cdef class CachedMethodCaller(CachedFunction): """ # initialize CachedFunction. Since the cached method is actually bound # to an instance, it now makes sense to initialise the ArgumentFixer - # and re-use it for all bound cached method callers of the unbound + # and reuse it for all bound cached method callers of the unbound # cached method. if cachedmethod._cachedfunc._argument_fixer is None: cachedmethod._cachedfunc.argfix_init() diff --git a/src/sage/misc/dev_tools.py b/src/sage/misc/dev_tools.py index 3f90fde6031..b11b2078129 100644 --- a/src/sage/misc/dev_tools.py +++ b/src/sage/misc/dev_tools.py @@ -310,7 +310,7 @@ def find_object_modules(obj): from sage.misc import sageinspect # see if the object is defined in its own module - # might be wrong for class instances as the instanciation might appear + # might be wrong for class instances as the instantiation might appear # outside of the module !! module_name = None if sageinspect.isclassinstance(obj): diff --git a/src/sage/misc/fast_methods.pyx b/src/sage/misc/fast_methods.pyx index b5e6cc41516..d38c1802c45 100644 --- a/src/sage/misc/fast_methods.pyx +++ b/src/sage/misc/fast_methods.pyx @@ -194,7 +194,7 @@ cdef class FastHashable_class: This is for internal use only. The class has a cdef attribute ``_hash``, that needs to be assigned (for example, by calling - the init method, or by a direct assignement using + the init method, or by a direct assignment using cython). This is slower than using :func:`provide_hash_by_id`, but has the advantage that the hash can be prescribed, by assigning a cdef attribute ``_hash``. diff --git a/src/sage/misc/function_mangling.pyx b/src/sage/misc/function_mangling.pyx index 8cf4d6e2efa..4e94e29e8cb 100644 --- a/src/sage/misc/function_mangling.pyx +++ b/src/sage/misc/function_mangling.pyx @@ -295,7 +295,7 @@ cdef class ArgumentFixer: cdef Py_ssize_t i for i in range(lenargs, nargs): # in addition to the positional arguments, we take the - # ones with default values, unless they are overridded by + # ones with default values, unless they are overridden by # the named arguments. name = arg_names[i] if name in kwargs: diff --git a/src/sage/misc/latex_standalone.py b/src/sage/misc/latex_standalone.py index de53979662e..483e8f52035 100644 --- a/src/sage/misc/latex_standalone.py +++ b/src/sage/misc/latex_standalone.py @@ -802,10 +802,10 @@ def dvi(self, filename=None, view=True, program='latex'): We test the behavior when a wrong value is provided:: sage: t = Standalone('Hello World') - sage: _ = t.dvi(program='lates') + sage: _ = t.dvi(program='farniente') Traceback (most recent call last): ... - ValueError: program(=lates) should be latex + ValueError: program(=farniente) should be latex """ from sage.features.latex import latex diff --git a/src/sage/misc/lazy_attribute.pyx b/src/sage/misc/lazy_attribute.pyx index 663856d03e3..3ece833bece 100644 --- a/src/sage/misc/lazy_attribute.pyx +++ b/src/sage/misc/lazy_attribute.pyx @@ -512,7 +512,7 @@ class lazy_class_attribute(lazy_attribute): A lazy class attribute for a class is like a usual class attribute, except that, instead of being computed when the class is constructed, it is computed on the fly the first time it is accessed, either through the - class itself or trough on of its objects. + class itself or through one of its objects. This is very similar to :class:`lazy_attribute` except that the attribute is a class attribute. More precisely, once computed, the lazy class diff --git a/src/sage/misc/lazy_format.py b/src/sage/misc/lazy_format.py index d2b549c9e11..6ab9b586c5a 100644 --- a/src/sage/misc/lazy_format.py +++ b/src/sage/misc/lazy_format.py @@ -27,7 +27,7 @@ class LazyFormat(str): sage: LazyFormat("Got `%s`; expected %s")%(3, 2/3) Got `3`; expected 2/3 - To demonstrate the lazyness, let us build an object with a broken + To demonstrate the laziness, let us build an object with a broken ``__repr__`` method:: sage: class IDontLikeBeingPrinted(): diff --git a/src/sage/misc/lazy_list.pyx b/src/sage/misc/lazy_list.pyx index 0bbf217c472..ca65a92fc88 100644 --- a/src/sage/misc/lazy_list.pyx +++ b/src/sage/misc/lazy_list.pyx @@ -1087,7 +1087,7 @@ cdef class lazy_list_from_update_function(lazy_list_generic): The update function should take as input a list and make it longer (using either the methods ``append`` or ``extend``). If after a call to the update function the list of values is shorter a - :exc:`RuntimeError` will occurr. If no value is added then the lazy list + :exc:`RuntimeError` will occur. If no value is added then the lazy list is considered finite. - ``cache`` -- an optional list to be used as the cache. Be careful that diff --git a/src/sage/misc/mrange.py b/src/sage/misc/mrange.py index 5f01348fe81..774008cdd70 100644 --- a/src/sage/misc/mrange.py +++ b/src/sage/misc/mrange.py @@ -105,7 +105,7 @@ def _xmrange_iter(iter_list, typ=list): sage: l1 is l2 False - However, if you would like to re-use the list object:: + However, if you would like to reuse the list object:: sage: iter = sage.misc.mrange._xmrange_iter( [[1,2],[1,3]], lambda x: x ) sage: l1 = next(iter) diff --git a/src/sage/misc/package.py b/src/sage/misc/package.py index ca7a9ffd67c..1169098ae77 100644 --- a/src/sage/misc/package.py +++ b/src/sage/misc/package.py @@ -144,7 +144,7 @@ def spkg_type(name): The type as a string in ``('base', 'standard', 'optional', 'experimental')``. If no ``SPKG`` exists with the given name (or the directory ``SAGE_PKGS`` is - not avaialble), ``None`` is returned. + not available), ``None`` is returned. """ spkg_type = None from sage.env import SAGE_PKGS diff --git a/src/sage/misc/sageinspect.py b/src/sage/misc/sageinspect.py index 87702cd481a..a6e0f7d8ad4 100644 --- a/src/sage/misc/sageinspect.py +++ b/src/sage/misc/sageinspect.py @@ -2255,7 +2255,7 @@ def sage_getsourcelines(obj): sage: sage_getsourcelines(test_func) (['def base(x):\n', ... - ' return x\n'], 7) + ' return x\n'], 8) Here are some cases that were covered in :issue:`11298`; note that line numbers may easily change, and therefore we do diff --git a/src/sage/misc/superseded.py b/src/sage/misc/superseded.py index a78e7eb37e7..6aaa8e6fb6f 100644 --- a/src/sage/misc/superseded.py +++ b/src/sage/misc/superseded.py @@ -327,7 +327,7 @@ class __experimental_self_test: The test below does not issue a warning message because that warning has already been issued by a previous doc-test in the @experimental code. Note that this behaviour cannot be demonstrated within a single documentation - string: Sphinx will itself supress multiple issued warnings. + string: Sphinx will itself suppress multiple issued warnings. TESTS:: diff --git a/src/sage/misc/test_nested_class.py b/src/sage/misc/test_nested_class.py index 58c1808e6f0..e7791f95a3a 100644 --- a/src/sage/misc/test_nested_class.py +++ b/src/sage/misc/test_nested_class.py @@ -159,8 +159,8 @@ class B: class ABB: class B: """ - This class is broken and can't be pickled. - A warning is emmited during compilation. + This class is broken and cannot be pickled. + A warning is emitted during compilation. """ pass diff --git a/src/sage/misc/weak_dict.pyx b/src/sage/misc/weak_dict.pyx index eefd042bf25..ce69b6a840a 100644 --- a/src/sage/misc/weak_dict.pyx +++ b/src/sage/misc/weak_dict.pyx @@ -278,7 +278,7 @@ cdef class WeakValueDictionary(dict): the dictionary values. However, the actual deletion is postponed till after the iteration over the dictionary has finished. Hence, when the callbacks are executed, the values which the callback belongs to has - already been overridded by a new value. Therefore, the callback does not + already been overridden by a new value. Therefore, the callback does not delete the item:: sage: for k in D: # indirect doctest diff --git a/src/sage/modular/arithgroup/arithgroup_generic.py b/src/sage/modular/arithgroup/arithgroup_generic.py index 09d65934165..c70defa96a3 100644 --- a/src/sage/modular/arithgroup/arithgroup_generic.py +++ b/src/sage/modular/arithgroup/arithgroup_generic.py @@ -4,7 +4,7 @@ """ ################################################################################ # -# Copyright (C) 2009, The Sage Group -- http://www.sagemath.org/ +# Copyright (C) 2009, The Sage Group -- https://www.sagemath.org/ # # Distributed under the terms of the GNU General Public License (GPL) # @@ -60,7 +60,7 @@ class ArithmeticSubgroup(Group): Element = ArithmeticSubgroupElement - def __init__(self): + def __init__(self) -> None: r""" Standard init routine. @@ -76,7 +76,7 @@ def _repr_(self) -> str: r""" Return the string representation of ``self``. - NOTE: This function should be overridden by all subclasses. + .. NOTE:: This function should be overridden by all subclasses. EXAMPLES:: @@ -104,7 +104,7 @@ def __reduce__(self): r""" Used for pickling ``self``. - NOTE: This function should be overridden by all subclasses. + .. NOTE:: This function should be overridden by all subclasses. EXAMPLES:: @@ -146,8 +146,10 @@ def _element_constructor_(self, x, check=True): def __contains__(self, x): r""" - Test if x is an element of this group. This checks that x defines (is?) a 2x2 integer matrix of determinant 1, and - then hands over to the routine _contains_sl2, which derived classes should implement. + Test if x is an element of this group. + + This checks that x defines (is?) a 2x2 integer matrix of determinant 1, and + then hands over to the routine ``_contains_sl2``, which derived classes should implement. EXAMPLES:: @@ -165,12 +167,12 @@ def __contains__(self, x): # Do not override this function! Derived classes should override # _contains_sl2. if isinstance(x, list) and len(x) == 4: - if not (x[0] in ZZ and x[1] in ZZ and x[2] in ZZ and x[3] in ZZ): + if not all(y in ZZ for y in x): return False - a,b,c,d = map(ZZ, x) + a, b, c, d = map(ZZ, x) if a*d - b*c != 1: return False - return self._contains_sl2(a,b,c,d) + return self._contains_sl2(a, b, c, d) else: if parent(x) is not SL2Z: try: @@ -178,13 +180,14 @@ def __contains__(self, x): except TypeError: return False x = y - return self._contains_sl2(x.a(),x.b(),x.c(),x.d()) + return self._contains_sl2(x.a(), x.b(), x.c(), x.d()) - def _contains_sl2(self, a,b,c,d): + def _contains_sl2(self, a, b, c, d): r""" Test whether the matrix [a,b;c,d], which may be assumed to have - determinant 1, is an element of ``self``. This must be overridden by all - subclasses. + determinant 1, is an element of ``self``. + + This must be overridden by all subclasses. EXAMPLES:: @@ -234,10 +237,11 @@ def matrix_space(self): """ return Mat2Z - def is_parent_of(self, x): + def is_parent_of(self, x) -> bool: r""" - Check whether this group is a valid parent for the element x. Required - by Sage's testing framework. + Check whether this group is a valid parent for the element x. + + Required by Sage's testing framework. EXAMPLES:: @@ -250,7 +254,7 @@ def is_parent_of(self, x): sage: Gamma(3).is_parent_of(SL2Z(1)) True """ - return (parent(x) == SL2Z and x in self) + return parent(x) == SL2Z and x in self def coset_reps(self, G=None): r""" @@ -352,17 +356,17 @@ def todd_coxeter(self, G=None, on_right=True): if G != SL2Z: raise NotImplementedError("Don't know how to compute coset reps for subgroups yet") - id = SL2Z([1,0,0,1]) - l = SL2Z([1,1,0,1]) - s = SL2Z([0,-1,1,0]) + one = SL2Z.one() + l = SL2Z([1, 1, 0, 1]) + s = SL2Z([0, -1, 1, 0]) - reps = [id] # coset representatives - reps_inv = {id:0} # coset representatives index + reps = [one] # coset representatives + reps_inv = {one: 0} # coset representatives index - l_wait_back = [id] # rep with no incoming s_edge - s_wait_back = [id] # rep with no incoming l_edge - l_wait = [id] # rep with no outgoing l_edge - s_wait = [id] # rep with no outgoing s_edge + l_wait_back = [one] # rep with no incoming s_edge + s_wait_back = [one] # rep with no incoming l_edge + l_wait = [one] # rep with no outgoing l_edge + s_wait = [one] # rep with no outgoing s_edge l_edges = [None] # edges for l s_edges = [None] # edges for s @@ -388,7 +392,7 @@ def todd_coxeter(self, G=None, on_right=True): if yy in self: l_edges[reps_inv[x]] = reps_inv[v] del l_wait_back[i] - if yy != id: + if yy != one: gens.append(self(yy)) not_end = False break @@ -420,7 +424,7 @@ def todd_coxeter(self, G=None, on_right=True): if yy in self: s_edges[reps_inv[x]] = reps_inv[v] del s_wait_back[i] - if yy != id: + if yy != one: gens.append(self(yy)) not_end = False break @@ -436,7 +440,7 @@ def todd_coxeter(self, G=None, on_right=True): return reps, gens, l_edges, s_edges - def nu2(self): + def nu2(self) -> int: r""" Return the number of orbits of elliptic points of order 2 for this arithmetic subgroup. @@ -471,8 +475,9 @@ def nu2(self): # precisely when the preimages are not elliptic.) count = 0 + mati = SL2Z([0, 1, -1, 0]) for g in self.coset_reps(): - if g * SL2Z([0,1,-1,0]) * (~g) in self: + if g * mati * (~g) in self: count += 1 return count @@ -505,16 +510,14 @@ def nu3(self): return 0 count = 0 + matj = SL2Z([0, 1, -1, -1]) for g in self.coset_reps(): - if g * SL2Z([0,1,-1,-1]) * (~g) in self: + if g * matj * (~g) in self: count += 1 - if self.is_even(): - return count - else: - return count // 2 + return count if self.is_even() else count // 2 - def is_abelian(self): + def is_abelian(self) -> bool: r""" Return ``True`` if this arithmetic subgroup is abelian. @@ -534,7 +537,7 @@ def is_abelian(self): """ return False - def is_finite(self): + def is_finite(self) -> bool: r""" Return ``True`` if this arithmetic subgroup is finite. @@ -554,12 +557,13 @@ def is_finite(self): """ return False - def is_subgroup(self, right): + def is_subgroup(self, right) -> bool: r""" - Return ``True`` if ``self`` is a subgroup of right, and ``False`` otherwise. For - generic arithmetic subgroups this is done by the absurdly slow - algorithm of checking all of the generators of ``self`` to see if they are - in ``right``. + Return ``True`` if ``self`` is a subgroup of right, and ``False`` otherwise. + + For generic arithmetic subgroups this is done by the absurdly + slow algorithm of checking all of the generators of ``self`` + to see if they are in ``right``. EXAMPLES:: @@ -571,14 +575,9 @@ def is_subgroup(self, right): True """ # ridiculously slow generic algorithm + return all(g in right for g in self.gens()) - w = self.gens() - for g in w: - if g not in right: - return False - return True - - def is_normal(self): + def is_normal(self) -> bool: r""" Return ``True`` precisely if this subgroup is a normal subgroup of ``SL2Z``. @@ -592,11 +591,11 @@ def is_normal(self): """ for x in self.gens(): for y in SL2Z.gens(): - if y*SL2Z(x)*(~y) not in self: + if y * SL2Z(x) * (~y) not in self: return False return True - def is_odd(self): + def is_odd(self) -> bool: r""" Return ``True`` precisely if this subgroup does not contain the matrix -1. @@ -614,7 +613,7 @@ def is_odd(self): """ return not self.is_even() - def is_even(self): + def is_even(self) -> bool: r""" Return ``True`` precisely if this subgroup contains the matrix -1. @@ -675,7 +674,7 @@ def reduce_cusp(self, c): element `\tfrac{r}{s}` with r,s coprime nonnegative integers, s as small as possible, and r as small as possible for that s. - NOTE: This function should be overridden by all subclasses. + .. NOTE:: This function should be overridden by all subclasses. EXAMPLES:: @@ -743,11 +742,13 @@ def _find_cusps(self): ... NotImplementedError - NOTE: There is a generic algorithm implemented at the top level that - uses the coset representatives of ``self``. This is *very slow* and for all - the standard congruence subgroups there is a quicker way of doing it, - so this should usually be overridden in subclasses; but it doesn't have - to be. + .. NOTE:: + + There is a generic algorithm implemented at the top level that + uses the coset representatives of ``self``. This is *very slow* and for all + the standard congruence subgroups there is a quicker way of doing it, + so this should usually be overridden in subclasses; but it doesn't have + to be. """ i = Cusp([1, 0]) L = [i] @@ -815,7 +816,7 @@ def are_equivalent(self, x, y, trans=False): return True return False - def cusp_data(self, c): + def cusp_data(self, c) -> tuple: r""" Return a triple `(g, w, t)` where `g` is an element of ``self`` generating the stabiliser of the given cusp, `w` is the width of the @@ -833,20 +834,21 @@ def cusp_data(self, c): # first find an element of SL2Z sending infinity to the given cusp w = lift_to_sl2z(c.denominator(), c.numerator(), 0) - g = SL2Z([w[3], w[1], w[2],w[0]]) + g = SL2Z([w[3], w[1], w[2], w[0]]) for d in range(1,1+self.index()): - if g * SL2Z([1,d,0,1]) * (~g) in self: + if g * SL2Z([1, d, 0, 1]) * (~g) in self: return (g * SL2Z([1,d,0,1]) * (~g), d, 1) - elif g * SL2Z([-1,-d,0,-1]) * (~g) in self: - return (g * SL2Z([-1,-d,0,-1]) * (~g), d, -1) + elif g * SL2Z([-1, -d, 0, -1]) * (~g) in self: + return (g * SL2Z([-1, -d, 0, -1]) * (~g), d, -1) raise ArithmeticError("Can't get here!") - def is_regular_cusp(self, c): + def is_regular_cusp(self, c) -> bool: r""" Return ``True`` if the orbit of the given cusp is a regular cusp for - ``self``, otherwise ``False``. This is automatically true if -1 is in - ``self``. + ``self``, otherwise ``False``. + + This is automatically true if -1 is in ``self``. EXAMPLES:: @@ -857,7 +859,7 @@ def is_regular_cusp(self, c): """ if self.is_even(): return True - return (self.cusp_data(c)[2] == 1) + return self.cusp_data(c)[2] == 1 def cusp_width(self, c): r""" @@ -887,7 +889,6 @@ def index(self): ... NotImplementedError """ - return len(list(self.coset_reps())) def generalised_level(self): @@ -937,13 +938,12 @@ def projective_index(self): sage: Gamma1(5).projective_index() 12 """ - if self.is_even(): return self.index() else: return self.index() // 2 - def is_congruence(self): + def is_congruence(self) -> bool: r""" Return ``True`` if ``self`` is a congruence subgroup. @@ -956,7 +956,6 @@ def is_congruence(self): ... NotImplementedError """ - raise NotImplementedError def genus(self): @@ -983,8 +982,9 @@ def genus(self): def farey_symbol(self): r""" - Return the Farey symbol associated to this subgroup. See the - :mod:`~sage.modular.arithgroup.farey_symbol` module for more + Return the Farey symbol associated to this subgroup. + + See the :mod:`~sage.modular.arithgroup.farey_symbol` module for more information. EXAMPLES:: @@ -1083,24 +1083,26 @@ def ngens(self): def ncusps(self): r""" - Return the number of cusps of this arithmetic subgroup. This is - provided as a separate function since for dimension formulae in even - weight all we need to know is the number of cusps, and this can be - calculated very quickly, while enumerating all cusps is much slower. + Return the number of cusps of this arithmetic subgroup. + + This is provided as a separate function since for dimension + formulae in even weight all we need to know is the number of + cusps, and this can be calculated very quickly, while + enumerating all cusps is much slower. EXAMPLES:: sage: sage.modular.arithgroup.arithgroup_generic.ArithmeticSubgroup.ncusps(Gamma0(7)) 2 """ - return ZZ(len(self.cusps())) def nregcusps(self): r""" Return the number of cusps of ``self`` that are "regular", i.e. their - stabiliser has a generator with both eigenvalues +1 rather than -1. If - the group contains -1, every cusp is clearly regular. + stabiliser has a generator with both eigenvalues +1 rather than -1. + + If the group contains -1, every cusp is clearly regular. EXAMPLES:: @@ -1113,8 +1115,9 @@ def nirregcusps(self): r""" Return the number of cusps of ``self`` that are "irregular", i.e. their stabiliser can only be generated by elements with both eigenvalues -1 - rather than +1. If the group contains -1, every cusp is clearly - regular. + rather than +1. + + If the group contains -1, every cusp is clearly regular. EXAMPLES:: @@ -1122,14 +1125,15 @@ def nirregcusps(self): 1 """ if self.is_even(): - return 0 - else: - return ZZ(len([c for c in self.cusps() if not self.is_regular_cusp(c)])) + return ZZ.zero() + return ZZ(len([1 for c in self.cusps() if not self.is_regular_cusp(c)])) def dimension_modular_forms(self, k=2): r""" Return the dimension of the space of weight k modular forms for this - group. This is given by a standard formula in terms of k and various + group. + + This is given by a standard formula in terms of k and various invariants of the group; see Diamond + Shurman, "A First Course in Modular Forms", section 3.5 and 3.6. If k is not given, defaults to k = 2. @@ -1162,7 +1166,9 @@ def dimension_modular_forms(self, k=2): def dimension_cusp_forms(self, k=2): r""" Return the dimension of the space of weight k cusp forms for this - group. For `k \ge 2`, this is given by a standard formula in terms of k + group. + + For `k \ge 2`, this is given by a standard formula in terms of k and various invariants of the group; see Diamond + Shurman, "A First Course in Modular Forms", section 3.5 and 3.6. If k is not given, default to k = 2. @@ -1192,7 +1198,7 @@ def dimension_cusp_forms(self, k=2): """ k = ZZ(k) if k <= 0: - return ZZ(0) + return ZZ.zero() if not (k % 2): # k even @@ -1207,7 +1213,7 @@ def dimension_cusp_forms(self, k=2): # k odd if self.is_even(): - return ZZ(0) + return ZZ.zero() else: e_reg = self.nregcusps() @@ -1217,7 +1223,7 @@ def dimension_cusp_forms(self, k=2): return (k-1)*(self.genus()-1) + (k // ZZ(3)) * self.nu3() + (k-2)/ZZ(2) * e_reg + (k-1)/ZZ(2) * e_irr else: if e_reg > 2*self.genus() - 2: - return ZZ(0) + return ZZ.zero() else: raise NotImplementedError("Computation of dimensions of weight 1 cusp forms spaces not implemented in general") @@ -1243,23 +1249,23 @@ def dimension_eis(self, k=2): 4 """ if k < 0: - return ZZ(0) + return ZZ.zero() if k == 0: - return ZZ(1) + return ZZ.one() - if not (k % 2): # k even + if not (k % 2): # k even if k > 2: return self.ncusps() - else: # k = 2 + else: # k = 2 return self.ncusps() - 1 - else: # k odd + else: # k odd if self.is_even(): - return 0 + return ZZ.zero() if k > 1: return self.nregcusps() - else: # k = 1 - return ZZ(self.nregcusps() / ZZ(2)) + else: # k = 1 + return ZZ(self.nregcusps() // ZZ(2)) def as_permutation_group(self): r""" @@ -1287,7 +1293,7 @@ def as_permutation_group(self): sage: P.an_element() in G True """ - _,_,l_edges,s2_edges = self.todd_coxeter() + _, _, l_edges, s2_edges = self.todd_coxeter() n = len(l_edges) s3_edges = [None] * n r_edges = [None] * n diff --git a/src/sage/modular/hecke/algebra.py b/src/sage/modular/hecke/algebra.py index 4cd632db1aa..f9c6e9c51e3 100644 --- a/src/sage/modular/hecke/algebra.py +++ b/src/sage/modular/hecke/algebra.py @@ -35,12 +35,12 @@ from sage.arith.misc import gcd from sage.misc.latex import latex from sage.matrix.matrix_space import MatrixSpace -from sage.rings.ring import CommutativeRing from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ from sage.structure.element import Element from sage.structure.unique_representation import CachedRepresentation from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent from sage.structure.richcmp import richcmp_method, richcmp @@ -111,7 +111,7 @@ def _heckebasis(M): @richcmp_method -class HeckeAlgebra_base(CachedRepresentation, CommutativeRing): +class HeckeAlgebra_base(CachedRepresentation, Parent): """ Base class for algebras of Hecke operators on a fixed Hecke module. @@ -186,8 +186,7 @@ def __init__(self, M) -> None: raise TypeError(msg) self.__M = M cat = Algebras(M.base_ring()).Commutative() - CommutativeRing.__init__(self, base_ring=M.base_ring(), - category=cat) + Parent.__init__(self, base=M.base_ring(), category=cat) def _an_element_(self): r""" diff --git a/src/sage/modular/quatalg/brandt.py b/src/sage/modular/quatalg/brandt.py index c846411a421..e91e6950e76 100644 --- a/src/sage/modular/quatalg/brandt.py +++ b/src/sage/modular/quatalg/brandt.py @@ -140,7 +140,9 @@ Order of Quaternion Algebra (-1, -23) with base ring Rational Field with basis (1/2 + 1/2*j, 1/2*i + 1/2*k, j, k) sage: B.right_ideals() - (Fractional ideal (2 + 2*j, 2*i + 2*k, 4*j, 4*k), Fractional ideal (2 + 2*j, 2*i + 6*k, 8*j, 8*k), Fractional ideal (2 + 10*j + 8*k, 2*i + 8*j + 6*k, 16*j, 16*k)) + (Fractional ideal (4, 4*i, 2 + 2*j, 2*i + 2*k), + Fractional ideal (8, 8*i, 2 + 2*j, 6*i + 2*k), + Fractional ideal (16, 16*i, 10 + 8*i + 2*j, 8 + 6*i + 2*k)) sage: B.hecke_matrix(2) [1 2 0] @@ -395,9 +397,9 @@ def basis_for_left_ideal(R, gens): sage: sage.modular.quatalg.brandt.basis_for_left_ideal(B.maximal_order(), [i+j,i-j,2*k,A(3)]) doctest:...: DeprecationWarning: The function basis_for_left_ideal() is deprecated, use the _left_ideal_basis() method of quaternion algebras See https://github.com/sagemath/sage/issues/37090 for details. - [1/2 + 1/6*i + 1/3*k, 1/3*i + 2/3*k, 1/2*j + 1/2*k, k] + [1, 1/2 + 1/2*i, j, 1/3*i + 1/2*j + 1/6*k] sage: sage.modular.quatalg.brandt.basis_for_left_ideal(B.maximal_order(), [3*(i+j),3*(i-j),6*k,A(3)]) - [3/2 + 1/2*i + k, i + 2*k, 3/2*j + 3/2*k, 3*k] + [3, 3/2 + 3/2*i, 3*j, i + 3/2*j + 1/2*k] """ from sage.misc.superseded import deprecation deprecation(37090, "The function basis_for_left_ideal() is deprecated, use the _left_ideal_basis() method of quaternion algebras") @@ -426,7 +428,7 @@ def right_order(R, basis): See https://github.com/sagemath/sage/issues/37090 for details. Order of Quaternion Algebra (-3, -17) with base ring Rational Field with basis (1/2 + 1/6*i + 1/3*k, 1/3*i + 2/3*k, 1/2*j + 1/2*k, k) sage: basis - [1/2 + 1/6*i + 1/3*k, 1/3*i + 2/3*k, 1/2*j + 1/2*k, k] + [1, 1/2 + 1/2*i, j, 1/3*i + 1/2*j + 1/6*k] sage: B = BrandtModule(17); A = B.quaternion_algebra(); i,j,k = A.gens() sage: basis = B.maximal_order()._left_ideal_basis([i*j - j]) @@ -803,14 +805,14 @@ def cyclic_submodules(self, I, p): sage: B = BrandtModule(11) sage: I = B.order_of_level_N().unit_ideal() sage: B.cyclic_submodules(I, 2) - [Fractional ideal (1/2 + 3/2*j + k, 1/2*i + j + 1/2*k, 2*j, 2*k), - Fractional ideal (1/2 + 1/2*i + 1/2*j + 1/2*k, i + k, j + k, 2*k), - Fractional ideal (1/2 + 1/2*j + k, 1/2*i + j + 3/2*k, 2*j, 2*k)] + [Fractional ideal (2, 2*i, 3/2 + i + 1/2*j, 1 + 1/2*i + 1/2*k), + Fractional ideal (2, 1 + i, 1 + j, 1/2 + 1/2*i + 1/2*j + 1/2*k), + Fractional ideal (2, 2*i, 1/2 + i + 1/2*j, 1 + 3/2*i + 1/2*k)] sage: B.cyclic_submodules(I, 3) - [Fractional ideal (1/2 + 1/2*j, 1/2*i + 5/2*k, 3*j, 3*k), - Fractional ideal (1/2 + 3/2*j + 2*k, 1/2*i + 2*j + 3/2*k, 3*j, 3*k), - Fractional ideal (1/2 + 3/2*j + k, 1/2*i + j + 3/2*k, 3*j, 3*k), - Fractional ideal (1/2 + 5/2*j, 1/2*i + 1/2*k, 3*j, 3*k)] + [Fractional ideal (3, 3*i, 1/2 + 1/2*j, 5/2*i + 1/2*k), + Fractional ideal (3, 3*i, 3/2 + 2*i + 1/2*j, 2 + 3/2*i + 1/2*k), + Fractional ideal (3, 3*i, 3/2 + i + 1/2*j, 1 + 3/2*i + 1/2*k), + Fractional ideal (3, 3*i, 5/2 + 1/2*j, 1/2*i + 1/2*k)] sage: B.cyclic_submodules(I, 11) Traceback (most recent call last): ... @@ -873,16 +875,17 @@ def cyclic_submodules(self, I, p): # right multiplication by X changes something to be written # in terms of the basis for I. - Y = I.basis_matrix() - X = Y**(-1) + basis = basis_for_quaternion_lattice(I.basis(), reverse=False) + Y = matrix(map(list, basis)) + X = ~Y # Compute the matrix of right multiplication by alpha acting on # our fixed choice of basis for this ideal. M_alpha = (matrix([(i * alpha).coefficient_tuple() - for i in I.basis()]) * X).change_ring(GF(p)) + for i in basis]) * X).change_ring(GF(p)) M_beta = (matrix([(i * beta).coefficient_tuple() - for i in I.basis()]) * X).change_ring(GF(p)) + for i in basis]) * X).change_ring(GF(p)) # step 2: Find j such that if f=I[j], then mod 2 we have span(I[0],alpha*I[i]) # has trivial intersection with span(I[j],alpha*I[j]). @@ -1251,9 +1254,9 @@ def right_ideals(self, B=None): sage: B = BrandtModule(23) sage: B.right_ideals() - (Fractional ideal (2 + 2*j, 2*i + 2*k, 4*j, 4*k), - Fractional ideal (2 + 2*j, 2*i + 6*k, 8*j, 8*k), - Fractional ideal (2 + 10*j + 8*k, 2*i + 8*j + 6*k, 16*j, 16*k)) + (Fractional ideal (4, 4*i, 2 + 2*j, 2*i + 2*k), + Fractional ideal (8, 8*i, 2 + 2*j, 6*i + 2*k), + Fractional ideal (16, 16*i, 10 + 8*i + 2*j, 8 + 6*i + 2*k)) TESTS:: @@ -1332,16 +1335,16 @@ def _ideal_products(self, diagonal_only=False): sage: B = BrandtModule(37) sage: B._ideal_products() - [[Fractional ideal (8 + 8*j + 8*k, 4*i + 8*j + 4*k, 16*j, 16*k)], - [Fractional ideal (8 + 24*j + 8*k, 4*i + 8*j + 4*k, 32*j, 32*k), - Fractional ideal (16 + 16*j + 48*k, 4*i + 8*j + 36*k, 32*j + 32*k, 64*k)], - [Fractional ideal (8 + 24*j + 24*k, 4*i + 24*j + 4*k, 32*j, 32*k), - Fractional ideal (8 + 4*i + 16*j + 28*k, 8*i + 16*j + 8*k, 32*j, 64*k), - Fractional ideal (16 + 16*j + 16*k, 4*i + 24*j + 4*k, 32*j + 32*k, 64*k)]] + [[Fractional ideal (16, 16*i, 8 + 8*i + 8*j, 8 + 12*i + 4*k)], + [Fractional ideal (32, 32*i, 8 + 24*i + 8*j, 24 + 12*i + 4*k), + Fractional ideal (32, 64*i, 16 + 48*i + 16*j, 36*i + 8*j + 4*k)], + [Fractional ideal (32, 32*i, 8 + 8*i + 8*j, 8 + 12*i + 4*k), + Fractional ideal (64, 32 + 32*i, 16 + 16*i + 16*j, 40 + 12*i + 4*k), + Fractional ideal (32, 64*i, 16 + 16*i + 16*j, 16 + 52*i + 8*j + 4*k)]] sage: B._ideal_products(diagonal_only=True) - [Fractional ideal (8 + 8*j + 8*k, 4*i + 8*j + 4*k, 16*j, 16*k), - Fractional ideal (16 + 16*j + 48*k, 4*i + 8*j + 36*k, 32*j + 32*k, 64*k), - Fractional ideal (16 + 16*j + 16*k, 4*i + 24*j + 4*k, 32*j + 32*k, 64*k)] + [Fractional ideal (16, 16*i, 8 + 8*i + 8*j, 8 + 12*i + 4*k), + Fractional ideal (32, 64*i, 16 + 48*i + 16*j, 36*i + 8*j + 4*k), + Fractional ideal (32, 64*i, 16 + 16*i + 16*j, 16 + 52*i + 8*j + 4*k)] """ L = self.right_ideals() n = len(L) diff --git a/src/sage/modules/free_quadratic_module_integer_symmetric.py b/src/sage/modules/free_quadratic_module_integer_symmetric.py index c7473002448..65a5b27d5de 100644 --- a/src/sage/modules/free_quadratic_module_integer_symmetric.py +++ b/src/sage/modules/free_quadratic_module_integer_symmetric.py @@ -51,8 +51,9 @@ # (at your option) any later version. # https://www.gnu.org/licenses/ # **************************************************************************** - +from pathlib import Path from copy import copy + from sage.rings.integer_ring import ZZ from sage.rings.integer import Integer from sage.rings.rational_field import QQ @@ -1480,13 +1481,12 @@ def LLL(self): p, n = self.signature_pair() if p * n != 0: from sage.env import SAGE_EXTCODE - from sage.interfaces.gp import gp from sage.libs.pari import pari - m = self.gram_matrix().__pari__() - gp.read(SAGE_EXTCODE + "/pari/simon/qfsolve.gp") - m = gp.eval('qflllgram_indefgoon(%s)' % m) - # convert the output string to sage - G, U = pari(m).sage() + m = self.gram_matrix() + pari.read(Path(SAGE_EXTCODE) / "pari" / "simon" / "qfsolve.gp") + m = pari('qflllgram_indefgoon')(m) + # convert the output to sage + G, U = m.sage() U = U.T else: e = 1 @@ -1537,13 +1537,15 @@ def _fplll_enumerate(self, target=None): sage: L = IntegralLattice('A4') sage: t = vector([1.2, -3/11, 5.5, -9.1]) sage: short = L.enumerate_short_vectors() # implicit doctest - sage: [next(short) for _ in range(10)] - [(0, 0, 0, 1), (0, 0, 1, 1), (0, 1, 1, 1), (1, 1, 1, 1), (0, 0, 1, 0), - (1, 1, 1, 0), (0, 1, 1, 0), (0, 1, 0, 0), (1, 1, 0, 0), (1, 0, 0, 0)] + sage: vecs = [next(short) for _ in range(10)] + sage: sorted(vecs, key=lambda v: (L(v).inner_product(L(v)), v)) + [(0, 0, 0, 1), (0, 0, 1, 0), (0, 0, 1, 1), (0, 1, 0, 0), (0, 1, 1, 0), + (0, 1, 1, 1), (1, 0, 0, 0), (1, 1, 0, 0), (1, 1, 1, 0), (1, 1, 1, 1)] sage: close = L.enumerate_close_vectors(t) # implicit doctest - sage: [next(close) for _ in range(10)] - [(1, 0, 6, -9), (1, -1, 5, -9), (2, 0, 6, -9), (1, 0, 5, -9), (1, -1, 5, -10), - (2, 1, 6, -9), (1, 0, 5, -10), (2, 0, 5, -9), (1, 0, 6, -8), (1, -1, 6, -9)] + sage: vecs = [next(close) for _ in range(10)] + sage: sorted(vecs, key=lambda v: (L(v).inner_product(L(v)), v)) + [(1, 0, 6, -8), (1, 0, 5, -9), (2, 0, 5, -9), (1, -1, 5, -9), (2, 1, 6, -9), + (1, 0, 6, -9), (2, 0, 6, -9), (1, 0, 5, -10), (1, -1, 6, -9), (1, -1, 5, -10)] """ L = self.LLL() dim = L.dimension() @@ -1598,11 +1600,24 @@ def enumerate_short_vectors(self): sage: L = IntegralLattice(4, [[1,2,3,4], [7,7,8,8], [1,-1,1,0]]) sage: short = L.enumerate_short_vectors() - sage: [next(short) for _ in range(20)] + sage: vecs = [next(short) for _ in range(20)] + sage: sorted(vecs, key=lambda v: (L(v).inner_product(L(v)), v)) [(1, -1, 1, 0), (2, -2, 2, 0), (3, -3, 3, 0), (0, 3, 2, 4), (1, 2, 3, 4), - (4, 4, 1, 0), (3, 2, -2, -4), (3, 5, 0, 0), (4, 1, -1, -4), (-1, 4, 1, 4), - (2, 1, 4, 4), (5, 3, 2, 0), (2, 3, -3, -4), (2, 6, -1, 0), (5, 0, 0, -4), - (-2, 5, 0, 4), (4, -4, 4, 0), (6, 2, 3, 0), (1, 4, -4, -4), (3, 0, 5, 4)] + (3, 2, -2, -4), (4, 4, 1, 0), (-1, 4, 1, 4), (3, 5, 0, 0), (4, 1, -1, -4), + (2, 1, 4, 4), (2, 3, -3, -4), (5, 3, 2, 0), (2, 6, -1, 0), (5, 0, 0, -4), + (-2, 5, 0, 4), (4, -4, 4, 0), (1, 4, -4, -4), (6, 2, 3, 0), (3, 0, 5, 4)] + + This example demonstrates that the lattice inner product is used for the norm:: + + sage: Q = Matrix(QQ, [[1000, 0], [0, 1]]) + sage: B = [[1, 1], [1, -1]] + sage: L = IntegralLattice(Q, basis=B) + sage: short = L.enumerate_short_vectors() + sage: vecs = [next(short) for _ in range(20)] + sage: sorted(vecs, key=lambda v: (L(v).inner_product(L(v)), v)) + [(0, -2), (0, -4), (0, -6), (0, -8), (0, -10), (0, -12), (0, -14), (0, -16), + (0, -18), (0, -20), (0, -22), (0, -24), (0, -26), (0, -28), (0, -30), (-1, -1), + (-1, 1), (-1, -3), (-1, 3), (0, -32)] """ yield from self._fplll_enumerate() @@ -1621,9 +1636,10 @@ def enumerate_close_vectors(self, target): sage: L = IntegralLattice(4, [[1,2,3,4], [7,7,8,8], [1,-1,1,0]]) sage: t = vector([1/2, -133/7, 123.44, -11]) sage: close = L.enumerate_close_vectors(t) - sage: [next(close) for _ in range(10)] - [(1, -18, 123, 148), (2, -19, 124, 148), (0, -17, 122, 148), (3, -20, 125, 148), (-1, -16, 121, 148), - (-2, -20, 125, 152), (-2, -23, 123, 148), (4, -21, 126, 148), (-3, -22, 122, 148), (-3, -19, 124, 152)] + sage: vecs = [next(close) for _ in range(10)] + sage: sorted(vecs, key=lambda v: (L(v).inner_product(L(v)), v)) + [(-1, -16, 121, 148), (0, -17, 122, 148), (-3, -22, 122, 148), (1, -18, 123, 148), (-2, -23, 123, 148), + (2, -19, 124, 148), (3, -20, 125, 148), (4, -21, 126, 148), (-3, -19, 124, 152), (-2, -20, 125, 152)] """ yield from self._fplll_enumerate(target) diff --git a/src/sage/monoids/free_abelian_monoid.py b/src/sage/monoids/free_abelian_monoid.py index 907414e4291..3b8fe3f0e07 100644 --- a/src/sage/monoids/free_abelian_monoid.py +++ b/src/sage/monoids/free_abelian_monoid.py @@ -114,7 +114,7 @@ def FreeAbelianMonoid(index_set=None, names=None, **kwds): Return a free abelian monoid on `n` generators or with the generators indexed by a set `I`. - We construct free abelian monoids by specifing either: + We construct free abelian monoids by specifying either: - the number of generators and/or the names of the generators - the indexing set for the generators (this ignores the other two inputs) diff --git a/src/sage/monoids/free_monoid.py b/src/sage/monoids/free_monoid.py index 9e8553184d1..e7a2a9f6532 100644 --- a/src/sage/monoids/free_monoid.py +++ b/src/sage/monoids/free_monoid.py @@ -73,7 +73,7 @@ class FreeMonoid(Monoid_class, UniqueRepresentation): Return a free monoid on `n` generators or with the generators indexed by a set `I`. - We construct free monoids by specifing either: + We construct free monoids by specifying either: - the number of generators and/or the names of the generators - the indexing set for the generators diff --git a/src/sage/monoids/trace_monoid.py b/src/sage/monoids/trace_monoid.py index 6b72feca4b5..cb1c036e039 100644 --- a/src/sage/monoids/trace_monoid.py +++ b/src/sage/monoids/trace_monoid.py @@ -109,7 +109,7 @@ def _repr_(self) -> str: return "1" return f"[{self.value}]" - def _richcmp_(self, other, op): + def _richcmp_(self, other, op) -> bool: r""" Compare two traces by their lexicographic normal forms. @@ -147,7 +147,7 @@ def lex_normal_form(self): """ return self.value - def foata_normal_form(self): + def foata_normal_form(self) -> tuple: r""" Return the Foata normal form of ``self``. @@ -300,12 +300,12 @@ def min_hasse_diagram(self): elements.reverse() independence = self.parent()._independence reachable = {} - min = set() + mini = set() graph = DiGraph({}) for i, x in enumerate(elements): reachable[i] = set() - front = min.copy() + front = mini.copy() while front: used = set() for j in list(front): @@ -314,14 +314,14 @@ def min_hasse_diagram(self): graph.add_edge(i, j) reachable[i].add(j) reachable[i].update(reachable[j]) - if j in min: - min.remove(j) + if j in mini: + mini.remove(j) used.add(j) forbidden = set(chain.from_iterable(reachable[v] for v in used)) front = {dest for _, dest in graph.outgoing_edges(front, labels=False)} front = front - forbidden - min.add(i) + mini.add(i) length = len(elements) graph.relabel(length - 1 - i for i in range(length)) @@ -432,7 +432,7 @@ class TraceMonoid(UniqueRepresentation, Monoid_class): Return a free partially commuting monoid (trace monoid) on `n` generators over independence relation `I`. - We construct a trace monoid by specifing: + We construct a trace monoid by specifying: - a free monoid and independence relation - or generator names and independence relation, @@ -495,7 +495,7 @@ def __classcall_private__(cls, M=None, I=frozenset(), names=None): rels = set() gen_from_str = {names[i]: gen for i, gen in enumerate(M.gens())} - for (x, y) in I: + for x, y in I: try: if isinstance(x, str): x = gen_from_str[x] @@ -513,7 +513,7 @@ def __classcall_private__(cls, M=None, I=frozenset(), names=None): return super().__classcall__(cls, M, I, names) - def __init__(self, M, I, names): + def __init__(self, M, I, names) -> None: r""" Initialize ``self``. @@ -673,7 +673,7 @@ def _compute_lex_normal_form(self, x): return prod(elements) @cached_method - def _compute_foata_normal_form(self, x): + def _compute_foata_normal_form(self, x) -> tuple: r""" Return Foata normal form of the monoid element. @@ -916,7 +916,7 @@ def words(self, length): if not ((list(word.value)[-1][0], suffix.value) in self._independence and list(word.value)[-1][0] > suffix.value)]) - def _sorted_independence(self): + def _sorted_independence(self) -> list: r""" Return independence relation over the monoid. @@ -951,7 +951,7 @@ def _repr_(self) -> str: ", ".join(f"{{{x}, {y}}}" for (x, y) in self._sorted_independence())) - def _latex_(self): + def _latex_(self) -> str: r""" LaTeX representation of trace monoids. diff --git a/src/sage/plot/contour_plot.py b/src/sage/plot/contour_plot.py index 6b526b1c7c4..26874790ec5 100644 --- a/src/sage/plot/contour_plot.py +++ b/src/sage/plot/contour_plot.py @@ -949,7 +949,7 @@ def f(x,y): return cos(x) + sin(y) # ...make it actually the const_z0 function. xy_data_array.fill(z0) - # We're going to set fill=True in a momemt, so we need to + # We're going to set fill=True in a moment, so we need to # prepend an entry to the cmap so that the user's original # cmap winds up in the right place. if "cmap" in options: diff --git a/src/sage/plot/multigraphics.py b/src/sage/plot/multigraphics.py index d2f70b44526..6ed26974c49 100644 --- a/src/sage/plot/multigraphics.py +++ b/src/sage/plot/multigraphics.py @@ -735,7 +735,7 @@ def _add_subplot(self, figure, index, **options): INPUT: - ``figure`` -- a Matplotlib ``Figure`` object - - ``index`` -- integer specifiying the element of ``self`` + - ``index`` -- integer specifying the element of ``self`` - ``options`` -- extra options to be passed to ``Figure.add_axes`` OUTPUT: a Matplotlib ``Axes`` object @@ -783,7 +783,7 @@ def position(self, index): INPUT: - - ``index`` -- integer specifiying which element of ``self`` + - ``index`` -- integer specifying which element of ``self`` OUTPUT: @@ -1167,7 +1167,7 @@ def _add_subplot(self, figure, index, **options): INPUT: - ``figure`` -- a Matplotlib ``Figure`` object - - ``index`` -- integer specifiying the element of ``self`` + - ``index`` -- integer specifying the element of ``self`` - ``options`` -- extra options to be passed to ``Figure.add_subplot`` OUTPUT: a Matplotlib ``Axes`` object @@ -1254,7 +1254,7 @@ def position(self, index): INPUT: - - ``index`` -- integer specifiying which element of ``self`` + - ``index`` -- integer specifying which element of ``self`` OUTPUT: diff --git a/src/sage/plot/plot3d/list_plot3d.py b/src/sage/plot/plot3d/list_plot3d.py index 565b8c41387..8bfa47ab5c6 100644 --- a/src/sage/plot/plot3d/list_plot3d.py +++ b/src/sage/plot/plot3d/list_plot3d.py @@ -35,7 +35,7 @@ def list_plot3d(v, interpolation_type='default', point_list=None, **kwds): Clough-Tocher scheme. The interpolant is guaranteed to be continuously differentiable. The gradients of the interpolant are chosen so that the curvature of the interpolating surface is - approximatively minimized. + approximately minimized. The option 'spline' interpolates using a bivariate B-spline. diff --git a/src/sage/quadratic_forms/genera/genus.py b/src/sage/quadratic_forms/genera/genus.py index 8868999c367..62b5c98f90b 100644 --- a/src/sage/quadratic_forms/genera/genus.py +++ b/src/sage/quadratic_forms/genera/genus.py @@ -18,7 +18,7 @@ # # https://www.gnu.org/licenses/ # **************************************************************************** - +from pathlib import Path from copy import copy, deepcopy from sage.misc.lazy_import import lazy_import @@ -2930,13 +2930,11 @@ def _compute_representative(self, LLL=True): sig = self.signature_pair_of_matrix() if sig[0] * sig[1] != 0: from sage.env import SAGE_EXTCODE - from sage.interfaces.gp import gp - m = pari(L) - gp.read(SAGE_EXTCODE + "/pari/simon/qfsolve.gp") - m = gp.eval('qflllgram_indefgoon(%s)' % m) + pari.read(Path(SAGE_EXTCODE) / "pari" / "simon" / "qfsolve.gp") + m = pari('qflllgram_indefgoon')(m) # convert the output string to sage - L = pari(m).sage()[0] + L = m.sage()[0] elif sig[1] != 0: U = -(-L).LLL_gram() L = U.T * L * U diff --git a/src/sage/quadratic_forms/quadratic_form__theta.py b/src/sage/quadratic_forms/quadratic_form__theta.py index 2929751bea8..12cffc8fbc1 100644 --- a/src/sage/quadratic_forms/quadratic_form__theta.py +++ b/src/sage/quadratic_forms/quadratic_form__theta.py @@ -82,7 +82,7 @@ def theta_by_pari(self, Max, var_str='q', safe_flag=True): output, or the original output. It is only meaningful when a vector is returned, otherwise a copy is automatically made in creating the power series. By default ``safe_flag=True``, so we - return a copy of the cached information. If this is set to False, + return a copy of the cached information. If this is set to ``False``, then the routine is much faster but the return values are vulnerable to being corrupted by the user. @@ -112,7 +112,7 @@ def theta_by_pari(self, Max, var_str='q', safe_flag=True): self.__theta_vec = theta_vec # Return the answer - if var_str == '': + if not var_str: if safe_flag: return deepcopy(theta_vec) # We must make a copy here to insure the integrity of the cached version! else: @@ -121,16 +121,16 @@ def theta_by_pari(self, Max, var_str='q', safe_flag=True): return PowerSeriesRing(ZZ, var_str)(theta_vec, Max) -# ------------- Compute the theta function by using an explicit Cholesky decomposition ------------ +# -- Compute the theta function by using an explicit Cholesky decomposition -- -########################################################################## -# Routines to compute the Fourier expansion of the theta function of Q ## -# (to a given precision) via a Cholesky decomposition over RR. ## -# ## -# The Cholesky code was taken from: ## -# ~/Documents/290_Project/C/Ver13.2__3-5-2007/Matrix_mpz/Matrix_mpz.cc ## -########################################################################## +######################################################################## +# Routines to compute the Fourier expansion of the theta function of Q # +# (to a given precision) via a Cholesky decomposition over RR. # +# # +# The Cholesky code was taken from: # +# ~/Documents/290_Project/C/Ver13.2__3-5-2007/Matrix_mpz/Matrix_mpz.cc # +######################################################################## def theta_by_cholesky(self, q_prec): @@ -144,24 +144,24 @@ def theta_by_cholesky(self, q_prec): Cohen's "A Course in Computational Algebraic Number Theory" book, p 102. - EXAMPLES:: + EXAMPLES: + + Check the sum of 4 squares form against Jacobi's formula:: - # Check the sum of 4 squares form against Jacobi's formula sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) sage: Theta = Q.theta_by_cholesky(10) sage: Theta 1 + 8*q + 24*q^2 + 32*q^3 + 24*q^4 + 48*q^5 + 96*q^6 + 64*q^7 + 24*q^8 + 104*q^9 + 144*q^10 - sage: Expected = [1] + [8*sum([d for d in divisors(n) if d%4 != 0]) + sage: Expected = [1] + [8*sum(d for d in divisors(n) if d%4) ....: for n in range(1, 11)] sage: Expected [1, 8, 24, 32, 24, 48, 96, 64, 24, 104, 144] sage: Theta.list() == Expected True - :: + Check the form `x^2 + 3y^2 + 5z^2 + 7w^2` represents everything except 2 and 22.:: - # Check the form x^2 + 3y^2 + 5z^2 + 7w^2 represents everything except 2 and 22. sage: Q = DiagonalQuadraticForm(ZZ, [1,3,5,7]) sage: Theta = Q.theta_by_cholesky(50) sage: Theta_list = Theta.list() @@ -176,10 +176,10 @@ def theta_by_cholesky(self, q_prec): from sage.rings.real_mpfr import RealField n = self.dim() - theta = [0 for i in range(q_prec + 1)] + theta = [0] * (q_prec + 1) PS = PowerSeriesRing(ZZ, 'q') - bit_prec = 53 # TO DO: Set this precision to reflect the appropriate roundoff + bit_prec = 53 # TO DO: Set this precision to reflect the appropriate roundoff Cholesky = self.cholesky_decomposition(bit_prec) # error estimate, to be confident through our desired q-precision. Q = Cholesky # <---- REDUNDANT!!! R = RealField(bit_prec) @@ -187,8 +187,8 @@ def theta_by_cholesky(self, q_prec): # 1. Initialize i = n - 1 - T = [R(0) for j in range(n)] - U = [R(0) for j in range(n)] + T = [R.zero()] * n + U = [R.zero()] * n T[i] = R(q_prec) U[i] = 0 L = [0] * n @@ -251,10 +251,7 @@ def theta_by_cholesky(self, q_prec): theta[Q_val] += 2 # 5. Check if x = 0, for exit condition. =) - done_flag = True - for j in range(n): - if x[j] != 0: - done_flag = False + done_flag = all(x[j] == 0 for j in range(n)) # Set the value: theta[0] = 1 theta[0] = 1 @@ -263,7 +260,7 @@ def theta_by_cholesky(self, q_prec): return PS(theta) -def theta_series_degree_2(Q, prec): +def theta_series_degree_2(Q, prec) -> dict: r""" Compute the theta series of degree 2 for the quadratic form `Q`. @@ -322,14 +319,14 @@ def theta_series_degree_2(Q, prec): H = Q.Hessian_matrix() t = cputime() - max = (X + 1) // 4 - v_list = (Q.vectors_by_length(max)) # assume a>0 - v_list = [[V(_) for _ in vs] for vs in v_list] # coerce vectors into V + maxi = (X + 1) // 4 + v_list = (Q.vectors_by_length(maxi)) # assume a>0 + v_list = [[V(c) for c in vs] for vs in v_list] # coerce vectors into V verbose("Computed vectors_by_length", t) # Deal with the singular part coeffs = {(0, 0, 0): ZZ.one()} - for i in range(1, max + 1): + for i in range(1, maxi + 1): coeffs[(0, 0, i)] = ZZ(2) * len(v_list[i]) # Now deal with the non-singular part diff --git a/src/sage/repl/interpreter.py b/src/sage/repl/interpreter.py index 73b619e8101..c0f52dc7c30 100644 --- a/src/sage/repl/interpreter.py +++ b/src/sage/repl/interpreter.py @@ -312,6 +312,7 @@ def prompt_for_code(self): pythonapi.PyOS_setsig(signal.SIGINT, sigint_os) return text + class SageTestShell(SageShellOverride, TerminalInteractiveShell): """ Test Shell. diff --git a/src/sage/repl/ipython_extension.py b/src/sage/repl/ipython_extension.py index b218330d7af..c5059584c89 100644 --- a/src/sage/repl/ipython_extension.py +++ b/src/sage/repl/ipython_extension.py @@ -71,6 +71,7 @@ from sage.misc.lazy_import import LazyImport from sage.misc.misc import run_once + @magics_class class SageMagics(Magics): diff --git a/src/sage/repl/rich_output/output_browser.py b/src/sage/repl/rich_output/output_browser.py index 086a036ad02..77e404151e3 100644 --- a/src/sage/repl/rich_output/output_browser.py +++ b/src/sage/repl/rich_output/output_browser.py @@ -12,6 +12,7 @@ latex_re = re.compile(r'(?P\\\[|\\\()(?P.*)(?P\\\]|\\\))', flags=re.DOTALL) + class OutputHtml(OutputBase): def __init__(self, html): diff --git a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py index 45a46e4a703..481b83c2415 100644 --- a/src/sage/rings/asymptotic/asymptotic_expansion_generators.py +++ b/src/sage/rings/asymptotic/asymptotic_expansion_generators.py @@ -59,18 +59,16 @@ - Clemens Heuberger (2016) - Benjamin Hackl (2016) - ACKNOWLEDGEMENT: - Benjamin Hackl, Clemens Heuberger and Daniel Krenn are supported by the Austrian Science Fund (FWF): P 24644-N26. - Classes and Methods =================== """ -#***************************************************************************** +# **************************************************************************** # Copyright (C) 2015 Daniel Krenn # Copyright (C) 2016 Clemens Heuberger # @@ -78,8 +76,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.misc.superseded import experimental from sage.structure.sage_object import SageObject @@ -582,7 +580,7 @@ def Binomial_kn_over_n(var, k, precision=None, skip_constant_factor=False): if b.parent() is SR: b = SCR(b).canonicalize_radical() result *= n.rpow(b) - result *= n**(-QQ(1)/QQ(2)) + result *= n**(-QQ((1, 2))) if not skip_constant_factor: result *= (k/((k-1)*2*SCR('pi'))).sqrt() @@ -905,7 +903,7 @@ def SingularityAnalysis(var, zeta=1, alpha=0, beta=0, delta=0, from sage.symbolic.ring import SR SCR = SR.subring(no_variables=True) - s = SR('s') + s = SR.var('s') iga = 1/gamma(alpha) if iga.parent() is SR: try: @@ -999,7 +997,7 @@ def inverse_gamma_derivative(shift, r): else: beta_denominator = 0 L = _sa_coefficients_lambda_(max(1, k_max), beta=beta_denominator) - (k, r) = next(it) + k, r = next(it) result = (n**(-k) * log_n**(-r)).O() if alpha in ZZ and beta == 0: @@ -1009,7 +1007,7 @@ def inverse_gamma_derivative(shift, r): from .misc import NotImplementedOZero raise NotImplementedOZero(A, exact_part=A.zero()) - for (k, r) in it: + for k, r in it: result += binomial(beta, r) * \ sum(L[(k, ell)] * (-1)**ell * inverse_gamma_derivative(ell, r) @@ -1125,26 +1123,26 @@ def ImplicitExpansion(var, phi, tau=None, precision=None): sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + 42*u, precision=5) Traceback (most recent call last): ... - ValueError: The function phi does not satisfy the requirements + ValueError: the function phi does not satisfy the requirements sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 42*u + u^2, precision=5) Traceback (most recent call last): ... - ValueError: The function phi does not satisfy the requirements + ValueError: the function phi does not satisfy the requirements sage: asymptotic_expansions.ImplicitExpansion('Z', phi=lambda u: 1 + u^2 + u^42, precision=5) Traceback (most recent call last): ... - ValueError: Fundamental constant tau could not be determined + ValueError: fundamental constant tau could not be determined """ from sage.symbolic.ring import SR from sage.rings.rational_field import QQ from sage.rings.integer_ring import ZZ from sage.rings.asymptotic.asymptotic_ring import AsymptoticRing from sage.arith.srange import srange - y, u = SR('y'), SR('u') - one_half = QQ(1)/2 + y, u = SR.var('y'), SR.var('u') + one_half = QQ((1, 2)) - if phi(QQ(0)).is_zero() or phi(u) == phi(0) + u*phi(u).diff(u)(u=0): - raise ValueError('The function phi does not satisfy the requirements') + if phi(QQ.zero()).is_zero() or phi(u) == phi(0) + u*phi(u).diff(u)(u=0): + raise ValueError('the function phi does not satisfy the requirements') if tau is None: tau = _fundamental_constant_implicit_function_(phi=phi) @@ -1161,7 +1159,7 @@ def H(y): def ansatz(prec=precision): if prec < 1: - return A(1).O() + return A.one().O() if prec == 1: return ((1/Z)**one_half).O() return (-(2*tau/phi(tau)/H(y).diff(y, 2)(y=tau)).sqrt() * (1/Z)**one_half @@ -1170,7 +1168,7 @@ def ansatz(prec=precision): # we compare coefficients between a "single" Z and the # following expansion, this allows us to compute the constants d_j - z = SR('z') + z = SR.var('z') z_expansion = sum(H(z).diff(z, k)(z=tau)/k.factorial() * ansatz(prec=precision+2-k)**k for k in srange(2, precision)) + ((1/Z)**(precision * one_half)).O() @@ -1178,7 +1176,7 @@ def ansatz(prec=precision): solution_dict = dict() for k in srange(2, precision-1): coef = z_expansion.monomial_coefficient((1/Z)**((k+1) * one_half)) - current_var = SR('d{k}'.format(k=k)) + current_var = SR.var('d{k}'.format(k=k)) solution_dict[current_var] = coef.subs(solution_dict).simplify_rational().solve(current_var)[0].rhs() return A(tau) + ansatz(prec=precision-1).map_coefficients(lambda term: term.subs(solution_dict).simplify_rational()) @@ -1264,7 +1262,7 @@ def ImplicitExpansionPeriodicPart(var, phi, period, tau=None, precision=None): phi=lambda u: phi(u**(1/period))**period, tau=tau_p, precision=precision) - rho = tau/phi(tau) + rho = tau / phi(tau) Z = aperiodic_expansion.parent().gen() return 1/rho * (aperiodic_expansion/(1 - 1/Z))**(1/period) @@ -1369,7 +1367,7 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): if tau is None: tau = _fundamental_constant_implicit_function_(phi=phi) - rho = tau/phi(tau) + rho = tau / phi(tau) if period == 1: expansion = asymptotic_expansions.ImplicitExpansion(var=var, phi=phi, @@ -1381,6 +1379,7 @@ def InverseFunctionAnalysis(var, phi, tau=None, period=1, precision=None): n = growth.parent().gen() return growth.subs({n: (n-1)/period}) + def _fundamental_constant_implicit_function_(phi): r""" Return the fundamental constant `\tau` occurring in the analysis of @@ -1411,12 +1410,13 @@ def _fundamental_constant_implicit_function_(phi): 1/2*sqrt(2) """ from sage.symbolic.ring import SR - u = SR('u') + u = SR.var('u') positive_solution = [s for s in (phi(u) - u*phi(u).diff(u)).solve(u) if s.rhs() > 0] if len(positive_solution) == 1: return positive_solution[0].rhs() - raise ValueError('Fundamental constant tau could not be determined') + raise ValueError('fundamental constant tau could not be determined') + def _sa_coefficients_lambda_(K, beta=0): r""" @@ -1460,18 +1460,17 @@ def _sa_coefficients_lambda_(K, beta=0): (4, 4): 5} """ from sage.rings.laurent_series_ring import LaurentSeriesRing - from sage.rings.power_series_ring import PowerSeriesRing + from sage.rings.lazy_series_ring import LazyPowerSeriesRing from sage.rings.rational_field import QQ V = LaurentSeriesRing(QQ, names='v', default_prec=K) v = V.gen() - T = PowerSeriesRing(V, names='t', default_prec=2*K-1) - t = T.gen() + t = LazyPowerSeriesRing(V, names='t').gen() - S = (t - (1+1/v+beta) * (1+v*t).log()).exp() - return dict(((k + L.valuation(), ell), c) - for ell, L in enumerate(S.list()) - for k, c in enumerate(L.list())) + S = (t - (1 + 1/v + beta) * (1 + v*t).log()).exp() + return {(k + L.valuation(), ell): c + for ell, L in enumerate(S[:2 * K - 1]) + for k, c in enumerate(L.list())} # Easy access to the asymptotic expansions generators from the command line: diff --git a/src/sage/rings/cfinite_sequence.py b/src/sage/rings/cfinite_sequence.py index 6b04e1ee66f..4166083de4a 100644 --- a/src/sage/rings/cfinite_sequence.py +++ b/src/sage/rings/cfinite_sequence.py @@ -90,6 +90,7 @@ from numbers import Integral from sage.categories.rings import Rings +from sage.libs.pari import pari from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ @@ -102,11 +103,6 @@ from sage.structure.parent import Parent from sage.structure.unique_representation import UniqueRepresentation -from sage.interfaces.gp import Gp -from sage.misc.sage_eval import sage_eval - -_gp = None - def CFiniteSequences(base_ring, names=None, category=None): r""" @@ -1204,6 +1200,13 @@ def guess(self, sequence, algorithm='sage'): C-finite sequence, generated by -1/2/(x - 1/2) sage: r[0:5] [1, 2, 4, 8, 16] + + Using pari:: + + sage: r = C.guess([1, 1, 1, 2, 2, 3, 4, 5, 7, 9, 12, 16, 21, 28], algorithm='pari'); r + C-finite sequence, generated by (-x - 1)/(x^3 + x^2 - 1) + sage: r[0:5] + [1, 1, 1, 2, 2] """ S = self.polynomial_ring() @@ -1221,22 +1224,18 @@ def guess(self, sequence, algorithm='sage'): return CFiniteSequence(numerator / denominator) if algorithm == 'pari': - global _gp if len(sequence) < 6: raise ValueError('sequence too short for guessing') - if _gp is None: - _gp = Gp() - _gp("ggf(v)=local(l,m,p,q,B);l=length(v);B=floor(l/2);\ + pari("ggf(v)=local(l,m,p,q,B);l=length(v);B=l\\2;\ if(B<3,return(0));m=matrix(B,B,x,y,v[x-y+B+1]);\ q=qflll(m,4)[1];if(length(q)==0,return(0));\ p=sum(k=1,B,x^(k-1)*q[k,1]);\ q=Pol(Pol(vector(l,n,v[l-n+1]))*p+O(x^(B+1)));\ if(polcoeff(p,0)<0,q=-q;p=-p);q=q/p;p=Ser(q+O(x^(l+1)));\ for(m=1,l,if(polcoeff(p,m-1)!=v[m],return(0)));q") - _gp.set('gf', sequence) - _gp("gf=ggf(gf)") - num = S(sage_eval(_gp.eval("Vec(numerator(gf))"))[::-1]) - den = S(sage_eval(_gp.eval("Vec(denominator(gf))"))[::-1]) + pari_guess = pari("ggf")(sequence) + num = S(pari_guess.numerator().Vec().sage()[::-1]) + den = S(pari_guess.denominator().Vec().sage()[::-1]) if num == 0: return 0 return CFiniteSequence(num / den) diff --git a/src/sage/rings/continued_fraction_gosper.py b/src/sage/rings/continued_fraction_gosper.py index bb1a31178e5..980cf62f72f 100644 --- a/src/sage/rings/continued_fraction_gosper.py +++ b/src/sage/rings/continued_fraction_gosper.py @@ -35,6 +35,7 @@ from sage.rings.infinity import Infinity from sage.rings.integer import Integer + class gosper_iterator(): r""" Iterable for the partial quotients of `(a*x+b)/(c*x+d)`, where `a, b, c, d` diff --git a/src/sage/rings/number_field/galois_group.py b/src/sage/rings/number_field/galois_group.py index aca472691d3..c974c3df6ff 100644 --- a/src/sage/rings/number_field/galois_group.py +++ b/src/sage/rings/number_field/galois_group.py @@ -1025,6 +1025,7 @@ def artin_symbol(self, P): raise ValueError("%s is ramified" % P) return t[0] + class GaloisGroup_subgroup(GaloisSubgroup_perm): r""" A subgroup of a Galois group, as returned by functions such as @@ -1188,6 +1189,7 @@ def fixed_field(self, name=None, polred=None, threshold=None): name = G._field.variable_name() + '0' return L.subfield(x, name=name) + class GaloisGroupElement(PermutationGroupElement): r""" An element of a Galois group. This is stored as a permutation, but may also diff --git a/src/sage/rings/number_field/maps.py b/src/sage/rings/number_field/maps.py index b14c4ca48f3..8d8eb1b69ef 100644 --- a/src/sage/rings/number_field/maps.py +++ b/src/sage/rings/number_field/maps.py @@ -52,6 +52,7 @@ IdentityMap = IdentityMorphism + class NumberFieldIsomorphism(Map): r""" A base class for various isomorphisms between number fields and @@ -101,6 +102,7 @@ def is_surjective(self): """ return True + class MapVectorSpaceToNumberField(NumberFieldIsomorphism): r""" The map to an absolute number field from its underlying `\QQ`-vector space. @@ -191,6 +193,7 @@ def _call_(self, v): f = K.polynomial_ring()(v.list()) return K._element_class(K, f) + class MapNumberFieldToVectorSpace(Map): r""" A class for the isomorphism from an absolute number field to its underlying @@ -249,6 +252,7 @@ def _call_(self, x): v = v + [QQ.zero()] * k return self.codomain()(v) + class MapRelativeVectorSpaceToRelativeNumberField(NumberFieldIsomorphism): r""" EXAMPLES:: @@ -314,6 +318,7 @@ def _call_(self, v): g = K._pari_rnfeq()._eltreltoabs(h) return K._element_class(K, g) + class MapRelativeNumberFieldToRelativeVectorSpace(NumberFieldIsomorphism): r""" EXAMPLES:: @@ -456,6 +461,7 @@ def _call_(self, x): y = x._copy_for_parent(self.codomain()) return y + class MapRelativeToAbsoluteNumberField(NumberFieldIsomorphism): r""" EXAMPLES:: @@ -533,6 +539,7 @@ def _call_(self, x): f = x.polynomial() return A._element_class(A, f) + class MapAbsoluteToRelativeNumberField(NumberFieldIsomorphism): r""" See :class:`~MapRelativeToAbsoluteNumberField` for examples. @@ -565,6 +572,7 @@ def _call_(self, x): f = x.polynomial() return R._element_class(R, f) + class MapVectorSpaceToRelativeNumberField(NumberFieldIsomorphism): r""" The isomorphism to a relative number field from its underlying `\QQ`-vector @@ -609,6 +617,7 @@ def _call_(self, x): """ return self._from_K(self._from_V(x)) + class MapRelativeNumberFieldToVectorSpace(NumberFieldIsomorphism): r""" The isomorphism from a relative number field to its underlying `\QQ`-vector diff --git a/src/sage/rings/number_field/number_field_ideal.py b/src/sage/rings/number_field/number_field_ideal.py index fb9bea019a4..d62ae34fb95 100644 --- a/src/sage/rings/number_field/number_field_ideal.py +++ b/src/sage/rings/number_field/number_field_ideal.py @@ -1775,6 +1775,7 @@ def basis_to_module(B, K): C = [to_V(K(b)) for b in B] return M.span_of_basis(C) + def is_NumberFieldIdeal(x): """ Return ``True`` if `x` is an ideal of a number field. diff --git a/src/sage/rings/number_field/number_field_ideal_rel.py b/src/sage/rings/number_field/number_field_ideal_rel.py index 0a1557110fe..7f6cfd9b1b7 100644 --- a/src/sage/rings/number_field/number_field_ideal_rel.py +++ b/src/sage/rings/number_field/number_field_ideal_rel.py @@ -42,6 +42,7 @@ QQ = rational_field.RationalField() ZZ = integer_ring.IntegerRing() + class NumberFieldFractionalIdeal_rel(NumberFieldFractionalIdeal): """ An ideal of a relative number field. @@ -882,6 +883,7 @@ def valuation(self, p): raise ValueError("p (= %s) must be an ideal in %s" % self.number_field()) return self.absolute_ideal().valuation(p.absolute_ideal()) + def is_NumberFieldFractionalIdeal_rel(x): """ Return ``True`` if `x` is a fractional ideal of a relative number field. diff --git a/src/sage/rings/number_field/order_ideal.py b/src/sage/rings/number_field/order_ideal.py index 0f0b2f5d524..da5515b2164 100644 --- a/src/sage/rings/number_field/order_ideal.py +++ b/src/sage/rings/number_field/order_ideal.py @@ -82,6 +82,7 @@ #TODO I*u works when u lies in I.ring().number_field(), but u*I doesn't + def NumberFieldOrderIdeal(O, *args, **kwds): r""" Construct either a :class:`NumberFieldOrderIdeal_generic` @@ -117,6 +118,7 @@ def NumberFieldOrderIdeal(O, *args, **kwds): cls = NumberFieldOrderIdeal_generic return cls(O, *args, **kwds) + class NumberFieldOrderIdeal_generic(Ideal_generic): r""" An ideal of a not necessarily maximal order in a number field. @@ -269,6 +271,7 @@ def norm(self): """ return self.free_module().index_in(self.ring().free_module()) + def _positive_sqrt(R, D): r""" Return the "positive" square root of `D` in `R`, which must be @@ -292,6 +295,7 @@ def _positive_sqrt(R, D): sqrtD, = (s for s in R(D).sqrt(all=True) if s.real() > 0 or s.imag() > 0) return sqrtD + def _gens_from_bqf(O, Q): r""" Helper function to compute generators of the ideal associated to @@ -354,6 +358,7 @@ def _gens_from_bqf(O, Q): t = sqrtD if a < 0 else 1 return a*t, g*t + class NumberFieldOrderIdeal_quadratic(NumberFieldOrderIdeal_generic): r""" An ideal of a not necessarily maximal order in a *quadratic* number field. diff --git a/src/sage/rings/number_field/selmer_group.py b/src/sage/rings/number_field/selmer_group.py index 377dbd9e60c..acdf2954fdf 100644 --- a/src/sage/rings/number_field/selmer_group.py +++ b/src/sage/rings/number_field/selmer_group.py @@ -51,6 +51,7 @@ # A utility function to allow the same code to be used over QQ and # over number fields: + def _ideal_generator(I): r""" Return the generator of a principal ideal. @@ -77,6 +78,7 @@ def _ideal_generator(I): except AttributeError: return I.abs() + def _coords_in_C_p(I, C, p): r""" Return coordinates of the ideal ``I`` with respect to a basis of @@ -130,6 +132,7 @@ def _coords_in_C_p(I, C, p): return [(coords[i] // n) % p for i, n in p_indices] raise ValueError("The {} power of {} is not principal".format(p.ordinal_str(),I)) + def _coords_in_C_mod_p(I,C,p): r""" Return coordinates of the ideal ``I`` with respect to a basis of @@ -181,6 +184,7 @@ def _coords_in_C_mod_p(I,C,p): coords = C(I).exponents() return [coords[i] % p for i in p_indices] + def _root_ideal(I, C, p): r""" Return a `p`-th root of an ideal with respect to the class group. @@ -230,6 +234,7 @@ def _root_ideal(I, C, p): return prod([gen ** wi for wi, gen in zip(w, cyclic_gens)], C.number_field().ideal(1)) + def coords_in_U_mod_p(u, U, p): r""" Return coordinates of a unit ``u`` with respect to a basis of the @@ -277,6 +282,7 @@ def coords_in_U_mod_p(u, U, p): start = 1 - int(p.divides(U.zeta_order())) # 0 or 1 return [c % p for c in coords[start:]] + def basis_for_p_cokernel(S, C, p): r""" Return a basis for the group of ideals supported on ``S`` (mod diff --git a/src/sage/rings/number_field/small_primes_of_degree_one.py b/src/sage/rings/number_field/small_primes_of_degree_one.py index e7e66f43d02..25c06fb5b60 100644 --- a/src/sage/rings/number_field/small_primes_of_degree_one.py +++ b/src/sage/rings/number_field/small_primes_of_degree_one.py @@ -95,6 +95,7 @@ from sage.rings.integer_ring import ZZ + class Small_primes_of_degree_one_iter(): r""" Iterator that finds primes of a number field of absolute degree diff --git a/src/sage/rings/number_field/structure.py b/src/sage/rings/number_field/structure.py index 03748c933a3..212d8e2a6f0 100644 --- a/src/sage/rings/number_field/structure.py +++ b/src/sage/rings/number_field/structure.py @@ -56,6 +56,7 @@ from sage.structure.unique_representation import UniqueRepresentation + class NumberFieldStructure(UniqueRepresentation): r""" Abstract base class encapsulating information about a number fields @@ -136,6 +137,7 @@ def create_structure(self, field): """ raise NotImplementedError + class NameChange(NumberFieldStructure): r""" Structure for a number field created by a change in variable name. @@ -179,6 +181,7 @@ def create_structure(self, field): from . import maps return maps.NameChangeMap(field, self.other), maps.NameChangeMap(self.other, field) + class AbsoluteFromRelative(NumberFieldStructure): r""" Structure for an absolute number field created from a relative number @@ -218,6 +221,7 @@ def create_structure(self, field): from . import maps return maps.MapAbsoluteToRelativeNumberField(field, self.other), maps.MapRelativeToAbsoluteNumberField(self.other, field) + class RelativeFromAbsolute(NumberFieldStructure): r""" Structure for a relative number field created from an absolute number @@ -292,6 +296,7 @@ def create_structure(self, field): return field_to_other, other_to_field + class RelativeFromRelative(NumberFieldStructure): r""" Structure for a relative number field created from another relative number diff --git a/src/sage/rings/number_field/totallyreal_rel.py b/src/sage/rings/number_field/totallyreal_rel.py index 6eea9afcd2c..ac3f52a544c 100644 --- a/src/sage/rings/number_field/totallyreal_rel.py +++ b/src/sage/rings/number_field/totallyreal_rel.py @@ -227,6 +227,7 @@ def integral_elements_in_box(K, C): eps_global = 10**(-6) + class tr_data_rel: r""" This class encodes the data used in the enumeration of totally real diff --git a/src/sage/rings/padics/factory.py b/src/sage/rings/padics/factory.py index d9a86cba9d9..cee585d48a1 100644 --- a/src/sage/rings/padics/factory.py +++ b/src/sage/rings/padics/factory.py @@ -99,6 +99,7 @@ ext_table['re', pAdicRingFloatingPoint] = RelativeRamifiedExtensionRingFloatingPoint ext_table['re', pAdicFieldFloatingPoint] = RelativeRamifiedExtensionFieldFloatingPoint + def _canonicalize_show_prec(type, print_mode, show_prec=None): r""" Return a canonical string value for show_prec depending of the type, @@ -328,6 +329,7 @@ def get_key_base(p, prec, type, print_mode, names, ram_name, print_pos, print_se padic_field_cache = {} DEFAULT_PREC = Integer(20) + class Qp_class(UniqueFactory): r""" A creation function for `p`-adic fields. @@ -1382,6 +1384,7 @@ def Qq(q, prec=None, type='capped-rel', modulus=None, names=None, # Short constructor names for different types ###################################################### + def QpCR(p, prec=None, *args, **kwds): r""" A shortcut function to create capped relative `p`-adic fields. @@ -1396,6 +1399,7 @@ def QpCR(p, prec=None, *args, **kwds): """ return Qp(p, prec, 'capped-rel', *args, **kwds) + def QpFP(p, prec=None, *args, **kwds): r""" A shortcut function to create floating point `p`-adic fields. @@ -1410,6 +1414,7 @@ def QpFP(p, prec=None, *args, **kwds): """ return Qp(p, prec, 'floating-point', *args, **kwds) + def QqCR(q, prec=None, *args, **kwds): r""" A shortcut function to create capped relative unramified `p`-adic @@ -1425,6 +1430,7 @@ def QqCR(q, prec=None, *args, **kwds): """ return Qq(q, prec, 'capped-rel', *args, **kwds) + def QqFP(q, prec=None, *args, **kwds): r""" A shortcut function to create floating point unramified `p`-adic @@ -1440,6 +1446,7 @@ def QqFP(q, prec=None, *args, **kwds): """ return Qq(q, prec, 'floating-point', *args, **kwds) + @experimental(23505) def QpLC(p, prec=None, *args, **kwds): r""" @@ -1455,6 +1462,7 @@ def QpLC(p, prec=None, *args, **kwds): """ return Qp(p, prec, 'lattice-cap', *args, **kwds) + @experimental(23505) def QpLF(p, prec=None, *args, **kwds): r""" @@ -1470,6 +1478,7 @@ def QpLF(p, prec=None, *args, **kwds): """ return Qp(p, prec, 'lattice-float', *args, **kwds) + def QpER(p, prec=None, halt=None, secure=False, *args, **kwds): r""" A shortcut function to create relaxed `p`-adic fields. @@ -1492,6 +1501,7 @@ def QpER(p, prec=None, halt=None, secure=False, *args, **kwds): # ####################################################################################################### + class Zp_class(UniqueFactory): r""" A creation function for `p`-adic rings. @@ -2619,6 +2629,7 @@ def Zq(q, prec=None, type='capped-rel', modulus=None, names=None, # Short constructor names for different types ###################################################### + def ZpCR(p, prec=None, *args, **kwds): r""" A shortcut function to create capped relative `p`-adic rings. @@ -2633,6 +2644,7 @@ def ZpCR(p, prec=None, *args, **kwds): """ return Zp(p, prec, 'capped-rel', *args, **kwds) + def ZpCA(p, prec=None, *args, **kwds): r""" A shortcut function to create capped absolute `p`-adic rings. @@ -2646,6 +2658,7 @@ def ZpCA(p, prec=None, *args, **kwds): """ return Zp(p, prec, 'capped-abs', *args, **kwds) + def ZpFM(p, prec=None, *args, **kwds): r""" A shortcut function to create fixed modulus `p`-adic rings. @@ -2659,6 +2672,7 @@ def ZpFM(p, prec=None, *args, **kwds): """ return Zp(p, prec, 'fixed-mod', *args, **kwds) + def ZpFP(p, prec=None, *args, **kwds): r""" A shortcut function to create floating point `p`-adic rings. @@ -2673,6 +2687,7 @@ def ZpFP(p, prec=None, *args, **kwds): """ return Zp(p, prec, 'floating-point', *args, **kwds) + def ZqCR(q, prec=None, *args, **kwds): r""" A shortcut function to create capped relative unramified `p`-adic rings. @@ -2687,6 +2702,7 @@ def ZqCR(q, prec=None, *args, **kwds): """ return Zq(q, prec, 'capped-rel', *args, **kwds) + def ZqCA(q, prec=None, *args, **kwds): r""" A shortcut function to create capped absolute unramified `p`-adic rings. @@ -2700,6 +2716,7 @@ def ZqCA(q, prec=None, *args, **kwds): """ return Zq(q, prec, 'capped-abs', *args, **kwds) + def ZqFM(q, prec=None, *args, **kwds): r""" A shortcut function to create fixed modulus unramified `p`-adic rings. @@ -2713,6 +2730,7 @@ def ZqFM(q, prec=None, *args, **kwds): """ return Zq(q, prec, 'fixed-mod', *args, **kwds) + def ZqFP(q, prec=None, *args, **kwds): r""" A shortcut function to create floating point unramified `p`-adic rings. @@ -2727,6 +2745,7 @@ def ZqFP(q, prec=None, *args, **kwds): """ return Zq(q, prec, 'floating-point', *args, **kwds) + @experimental(23505) def ZpLC(p, prec=None, *args, **kwds): r""" @@ -2988,6 +3007,7 @@ def ZpLC(p, prec=None, *args, **kwds): """ return Zp(p, prec, 'lattice-cap', *args, **kwds) + @experimental(23505) def ZpLF(p, prec=None, *args, **kwds): r""" @@ -3015,6 +3035,7 @@ def ZpLF(p, prec=None, *args, **kwds): """ return Zp(p, prec, 'lattice-float', *args, **kwds) + def ZpER(p, prec=None, halt=None, secure=False, *args, **kwds): r""" A shortcut function to create relaxed `p`-adic rings. @@ -3494,6 +3515,7 @@ def split(poly, prec): """ raise NotImplementedError("Extensions by general polynomials not yet supported. Please use an unramified or Eisenstein polynomial.") + def truncate_to_prec(poly, R, absprec): r""" Truncates the unused precision off of a polynomial. @@ -3509,6 +3531,7 @@ def truncate_to_prec(poly, R, absprec): """ return R[poly.variable_name()]([R(a, absprec=absprec) for a in poly.list()]) # Is this quite right? We don't want flat necessarily... + def krasner_check(poly, prec): r""" Return ``True`` iff ``poly`` determines a unique isomorphism class of @@ -3526,6 +3549,7 @@ def krasner_check(poly, prec): """ return True #This needs to be implemented + def is_eisenstein(poly): r""" Return ``True`` iff this monic polynomial is Eisenstein. @@ -3555,6 +3579,7 @@ def is_eisenstein(poly): return False return True + def is_unramified(poly): r""" Return ``True`` iff this monic polynomial is unramified. diff --git a/src/sage/rings/padics/generic_nodes.py b/src/sage/rings/padics/generic_nodes.py index 5fb70851043..27ca55b274f 100644 --- a/src/sage/rings/padics/generic_nodes.py +++ b/src/sage/rings/padics/generic_nodes.py @@ -70,6 +70,7 @@ def _prec_type(self): """ return 'capped-abs' + class CappedRelativeGeneric(LocalGeneric): def is_capped_relative(self): """ @@ -107,6 +108,7 @@ def _prec_type(self): """ return 'capped-rel' + class FixedModGeneric(LocalGeneric): def is_fixed_mod(self): """ @@ -145,6 +147,7 @@ def _prec_type(self): """ return 'fixed-mod' + class FloatingPointGeneric(LocalGeneric): def is_floating_point(self): """ @@ -257,15 +260,23 @@ def _test_additive_associativity(self, **options): 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()))) + class FloatingPointRingGeneric(FloatingPointGeneric): pass + + class FloatingPointFieldGeneric(FloatingPointGeneric):#, sage.rings.ring.Field): pass + + class CappedRelativeRingGeneric(CappedRelativeGeneric): pass + + class CappedRelativeFieldGeneric(CappedRelativeGeneric):#, sage.rings.ring.Field): pass + class pAdicLatticeGeneric(pAdicGeneric): r""" An implementation of the `p`-adic rationals with lattice precision. @@ -1339,19 +1350,31 @@ class pAdicFieldGeneric(pAdicGeneric, sage.rings.abc.pAdicField): #def subfields_of_degree(self, n): # raise NotImplementedError + class pAdicFixedModRingGeneric(pAdicRingGeneric, FixedModGeneric): pass + + class pAdicCappedAbsoluteRingGeneric(pAdicRingGeneric, CappedAbsoluteGeneric): pass + + class pAdicCappedRelativeRingGeneric(pAdicRingGeneric, CappedRelativeRingGeneric): pass + + class pAdicCappedRelativeFieldGeneric(pAdicFieldGeneric, CappedRelativeFieldGeneric): pass + + class pAdicFloatingPointRingGeneric(pAdicRingGeneric, FloatingPointRingGeneric): pass + + class pAdicFloatingPointFieldGeneric(pAdicFieldGeneric, FloatingPointFieldGeneric): pass + class pAdicRingBaseGeneric(pAdicBaseGeneric, pAdicRingGeneric): def construction(self, forbid_frac_field=False): """ @@ -1443,6 +1466,7 @@ def random_element(self, algorithm='default'): #def principal_unit_group(self): # raise NotImplementedError + class pAdicFieldBaseGeneric(pAdicBaseGeneric, pAdicFieldGeneric): def composite(self, subfield1, subfield2): r""" diff --git a/src/sage/rings/padics/lattice_precision.py b/src/sage/rings/padics/lattice_precision.py index 705feeaf3fc..efa3a364547 100644 --- a/src/sage/rings/padics/lattice_precision.py +++ b/src/sage/rings/padics/lattice_precision.py @@ -56,6 +56,7 @@ # The number of additional digits used for internal computations STARTING_ADDITIONAL_PREC = 5 + class pRational: r""" This class implements rational numbers viewed as elements of ``Qp``. @@ -2740,6 +2741,7 @@ def precision_lattice(self, elements=None): M *= self._p ** val return M + class pAdicLatticeElementWeakProxy(): r""" The implementations of :class:`DifferentialPrecisionGeneric` hold @@ -2851,6 +2853,7 @@ def __repr__(self): """ return "WeakProxy#%s" % (self._id,) + def list_of_padics(elements): r""" Convert a list of `p`-adic composed elements (such as polynomials, matrices) diff --git a/src/sage/rings/padics/misc.py b/src/sage/rings/padics/misc.py index 00720ba8bbb..d7ce570a732 100644 --- a/src/sage/rings/padics/misc.py +++ b/src/sage/rings/padics/misc.py @@ -30,6 +30,7 @@ python_min = min python_max = max + def gauss_sum(a, p, f, prec=20, factored=False, algorithm='pari', parent=None): r""" Return the Gauss sum `g_q(a)` as a `p`-adic number. @@ -184,6 +185,7 @@ def max(*L): except ValueError: return -infinity + def precprint(prec_type, prec_cap, p): """ String describing the precision mode on a `p`-adic ring or field. @@ -209,6 +211,7 @@ def precprint(prec_type, prec_cap, p): 'relaxed':'handled with relaxed arithmetics'} return precD[prec_type] + def trim_zeros(L): r""" Strips trailing zeros/empty lists from a list. diff --git a/src/sage/rings/padics/padic_base_leaves.py b/src/sage/rings/padics/padic_base_leaves.py index 0cc295f4e69..4a2c61286c4 100644 --- a/src/sage/rings/padics/padic_base_leaves.py +++ b/src/sage/rings/padics/padic_base_leaves.py @@ -404,6 +404,7 @@ def _convert_map_from_(self, R): from sage.rings.padics.padic_generic import ResidueLiftingMap return ResidueLiftingMap._create_(R, self) + class pAdicRingFloatingPoint(pAdicRingBaseGeneric, pAdicFloatingPointRingGeneric): r""" An implementation of the `p`-adic integers with floating point @@ -499,6 +500,7 @@ def _convert_map_from_(self, R): from sage.rings.padics.padic_generic import ResidueLiftingMap return ResidueLiftingMap._create_(R, self) + class pAdicRingFixedMod(pAdicRingBaseGeneric, pAdicFixedModRingGeneric): r""" An implementation of the `p`-adic integers using fixed modulus. @@ -605,6 +607,7 @@ def _convert_map_from_(self, R): from sage.rings.padics.padic_generic import ResidueLiftingMap return ResidueLiftingMap._create_(R, self) + class pAdicFieldCappedRelative(pAdicFieldBaseGeneric, pAdicCappedRelativeFieldGeneric): r""" An implementation of `p`-adic fields with capped relative precision. @@ -740,6 +743,7 @@ def random_element(self, algorithm='default'): else: raise NotImplementedError("Don't know %s algorithm" % algorithm) + class pAdicFieldFloatingPoint(pAdicFieldBaseGeneric, pAdicFloatingPointFieldGeneric): r""" An implementation of the `p`-adic rationals with floating point @@ -841,6 +845,7 @@ def _convert_map_from_(self, R): # Lattice precision ################### + class pAdicRingLattice(pAdicLatticeGeneric, pAdicRingBaseGeneric): """ An implementation of the `p`-adic integers with lattice precision. @@ -972,6 +977,7 @@ def random_element(self, prec=None): x += p**cap * ZZ.random_element(p**v) return self._element_class(self, x, prec=prec) + class pAdicFieldLattice(pAdicLatticeGeneric, pAdicFieldBaseGeneric): """ An implementation of the `p`-adic numbers with lattice precision. @@ -1112,6 +1118,7 @@ def random_element(self, prec=None, integral=False): # Relaxed ######### + class pAdicRingRelaxed(pAdicRelaxedGeneric, pAdicRingBaseGeneric): r""" An implementation of relaxed arithmetics over `\ZZ_p`. @@ -1150,6 +1157,7 @@ def __init__(self, p, prec, print_mode, names): self._element_class_module = padic_relaxed_element self._element_class_prefix = "pAdicRelaxedElement_" + class pAdicFieldRelaxed(pAdicRelaxedGeneric, pAdicFieldBaseGeneric): r""" An implementation of relaxed arithmetics over `\QQ_p`. diff --git a/src/sage/rings/padics/padic_extension_generic.py b/src/sage/rings/padics/padic_extension_generic.py index 2c8ff496f87..e3e97906be2 100644 --- a/src/sage/rings/padics/padic_extension_generic.py +++ b/src/sage/rings/padics/padic_extension_generic.py @@ -41,6 +41,7 @@ from sage.misc.cachefunc import cached_method from sage.structure.richcmp import rich_to_bool + class pAdicExtensionGeneric(pAdicGeneric): def __init__(self, poly, prec, print_mode, names, element_class): """ @@ -668,6 +669,8 @@ def free_module(self, base=None, basis=None, map=True): # an object in two free module categories with # different base rings. So for now we # just stick with Map. + + class pAdicModuleIsomorphism(Map): r""" A base class for various isomorphisms between `p`-adic rings/fields and free modules. @@ -728,6 +731,7 @@ def _richcmp_(self, other, op): else: return rich_to_bool(op, 1) + class MapFreeModuleToOneStep(pAdicModuleIsomorphism): """ The isomorphism from the underlying module of a one-step `p`-adic extension @@ -763,6 +767,7 @@ def _call_with_args(self, x, args=(), kwds={}): """ return self.codomain()(list(x), *args, **kwds) + class MapOneStepToFreeModule(pAdicModuleIsomorphism): """ The isomorphism from a one-step `p`-adic extension to its underlying free module. @@ -787,6 +792,7 @@ def _call_(self, x): """ return self.codomain()(x._polynomial_list(pad=True)) + class MapFreeModuleToTwoStep(pAdicModuleIsomorphism): """ The isomorphism from the underlying module of a two-step `p`-adic extension @@ -834,6 +840,7 @@ def _call_with_args(self, x, args=(), kwds={}): """ return self.codomain()(self._call_(x), *args, **kwds) + class MapTwoStepToFreeModule(pAdicModuleIsomorphism): """ The isomorphism from a two-step `p`-adic extension to its underlying free module. @@ -861,6 +868,7 @@ def _call_(self, x): v = flatten([c._polynomial_list(pad=True) for c in x._polynomial_list(pad=True)]) return self.codomain()(v) + class DefPolyConversion(Morphism): """ Conversion map between `p`-adic rings/fields with the same defining polynomial. diff --git a/src/sage/rings/padics/padic_extension_leaves.py b/src/sage/rings/padics/padic_extension_leaves.py index c57e633c60d..d17563712fb 100644 --- a/src/sage/rings/padics/padic_extension_leaves.py +++ b/src/sage/rings/padics/padic_extension_leaves.py @@ -95,6 +95,7 @@ def _make_integral_poly(exact_modulus, p, prec): except TypeError: return exact_modulus.change_ring(Zmod(p**prec)).change_ring(ZZ) + class UnramifiedExtensionRingCappedRelative(UnramifiedExtensionGeneric, pAdicCappedRelativeRingGeneric): """ TESTS:: @@ -153,6 +154,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self.register_coercion(pAdicCoercion_ZZ_CR(self)) self.register_conversion(pAdicConvert_QQ_CR(self)) + class UnramifiedExtensionFieldCappedRelative(UnramifiedExtensionGeneric, pAdicCappedRelativeFieldGeneric): """ TESTS:: @@ -298,6 +300,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self.register_coercion(pAdicCoercion_ZZ_CA(self)) self.register_conversion(pAdicConvert_QQ_CA(self)) + class UnramifiedExtensionRingFixedMod(UnramifiedExtensionGeneric, pAdicFixedModRingGeneric): """ TESTS:: @@ -360,6 +363,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp # return Morphism_ZpFM_UnrFM(S, self) # return None + class UnramifiedExtensionRingFloatingPoint(UnramifiedExtensionGeneric, pAdicFloatingPointRingGeneric): """ TESTS:: @@ -484,6 +488,7 @@ def _coerce_map_from_(self, R): return super()._coerce_map_from_(R) + class EisensteinExtensionRingCappedRelative(EisensteinExtensionGeneric, pAdicCappedRelativeRingGeneric): """ TESTS:: @@ -539,6 +544,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self._implementation = implementation EisensteinExtensionGeneric.__init__(self, poly, prec, print_mode, names, pAdicZZpXCRElement) + class EisensteinExtensionFieldCappedRelative(EisensteinExtensionGeneric, pAdicCappedRelativeFieldGeneric): """ TESTS:: @@ -595,6 +601,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self._implementation = implementation EisensteinExtensionGeneric.__init__(self, poly, prec, print_mode, names, pAdicZZpXCRElement) + class EisensteinExtensionRingCappedAbsolute(EisensteinExtensionGeneric, pAdicCappedAbsoluteRingGeneric): """ TESTS:: @@ -650,6 +657,7 @@ def __init__(self, exact_modulus, poly, prec, print_mode, shift_seed, names, imp self._implementation = implementation EisensteinExtensionGeneric.__init__(self, poly, prec, print_mode, names, pAdicZZpXCAElement) + class EisensteinExtensionRingFixedMod(EisensteinExtensionGeneric, pAdicFixedModRingGeneric): """ TESTS:: diff --git a/src/sage/rings/padics/padic_generic.py b/src/sage/rings/padics/padic_generic.py index ffa0eba1b05..3f041a5e146 100644 --- a/src/sage/rings/padics/padic_generic.py +++ b/src/sage/rings/padics/padic_generic.py @@ -1743,6 +1743,7 @@ def _richcmp_(self, other, op): # A class for the Teichmüller lift would also be reasonable.... + class ResidueLiftingMap(Morphism): r""" Lifting map to a `p`-adic ring or field from its residue field or ring. @@ -1875,6 +1876,7 @@ def _richcmp_(self, other, op): return NotImplemented return richcmp((self.domain(), self.codomain()), (other.domain(), other.codomain()), op) + def local_print_mode(obj, print_options, pos=None, ram_name=None): r""" Context manager for safely temporarily changing the print_mode diff --git a/src/sage/rings/padics/padic_valuation.py b/src/sage/rings/padics/padic_valuation.py index 7ee6124eebe..1050055e1fb 100644 --- a/src/sage/rings/padics/padic_valuation.py +++ b/src/sage/rings/padics/padic_valuation.py @@ -48,6 +48,7 @@ from sage.rings.infinity import infinity + class PadicValuationFactory(UniqueFactory): r""" Create a ``prime``-adic valuation on ``R``. @@ -1391,6 +1392,7 @@ def extensions(self, ring): return [pAdicValuation(ring, approximant)] return super().extensions(ring) + def _fraction_field(ring): r""" Return a fraction field of ``ring``. diff --git a/src/sage/rings/padics/precision_error.py b/src/sage/rings/padics/precision_error.py index e7ef94f949b..3dcf4b08d8e 100644 --- a/src/sage/rings/padics/precision_error.py +++ b/src/sage/rings/padics/precision_error.py @@ -18,5 +18,6 @@ # http://www.gnu.org/licenses/ #***************************************************************************** + class PrecisionError(ArithmeticError): pass diff --git a/src/sage/rings/padics/relative_extension_leaves.py b/src/sage/rings/padics/relative_extension_leaves.py index b377a446081..3005ae0825b 100644 --- a/src/sage/rings/padics/relative_extension_leaves.py +++ b/src/sage/rings/padics/relative_extension_leaves.py @@ -28,6 +28,7 @@ from .relative_ramified_FP import RelativeRamifiedFloatingPointElement from .pow_computer_relative import PowComputer_relative_maker + class pAdicRelativeBaseringInjection(Morphism): """ The injection of the unramified base into the two-step extension. @@ -123,6 +124,7 @@ def section(self): """ return pAdicRelativeBaseringSection(self.codomain(), self.domain()) + class pAdicRelativeBaseringSection(Morphism): """ The map from a two-step extension back to its maximal unramified subextension. @@ -193,6 +195,7 @@ def _call_with_args(self, x, args=(), kwds={}): """ return self.codomain()(self._call_(x), *args, **kwds) + class RelativeRamifiedExtensionRingFixedMod(EisensteinExtensionGeneric, pAdicFixedModRingGeneric): """ Two-step extension ring with fixed-mod precision. @@ -230,6 +233,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring(), self)) self.register_conversion(pAdicConvert_QQ_FM(self)) + class RelativeRamifiedExtensionRingCappedAbsolute(EisensteinExtensionGeneric, pAdicCappedAbsoluteRingGeneric): """ Two-step extension ring with capped absolute precision. @@ -267,6 +271,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring(), self)) self.register_conversion(pAdicConvert_QQ_CA(self)) + class RelativeRamifiedExtensionRingCappedRelative(EisensteinExtensionGeneric, pAdicCappedRelativeRingGeneric): """ Two-step extension ring with capped relative precision. @@ -304,6 +309,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring(), self)) self.register_conversion(pAdicConvert_QQ_CR(self)) + class RelativeRamifiedExtensionFieldCappedRelative(EisensteinExtensionGeneric, pAdicCappedRelativeFieldGeneric): """ Two-step extension field with capped relative precision. @@ -343,6 +349,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring().integer_ring(), self)) self.register_coercion(pAdicCoercion_QQ_CR(self)) + class RelativeRamifiedExtensionRingFloatingPoint(EisensteinExtensionGeneric, pAdicFloatingPointRingGeneric): """ Two-step extension ring with floating point precision. @@ -380,6 +387,7 @@ def __init__(self, exact_modulus, approx_modulus, prec, print_mode, shift_seed, self.register_coercion(pAdicRelativeBaseringInjection(approx_modulus.base_ring(), self)) self.register_conversion(pAdicConvert_QQ_FP(self)) + class RelativeRamifiedExtensionFieldFloatingPoint(EisensteinExtensionGeneric, pAdicFloatingPointFieldGeneric): """ Two-step extension field with floating point precision. diff --git a/src/sage/rings/polynomial/infinite_polynomial_element.py b/src/sage/rings/polynomial/infinite_polynomial_element.py index db55eff5dd1..f7a5ae24f19 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_element.py +++ b/src/sage/rings/polynomial/infinite_polynomial_element.py @@ -552,6 +552,41 @@ def is_nilpotent(self): """ return self._p.is_nilpotent() + def numerator(self): + r""" + Return a numerator of ``self``, computed as ``self * self.denominator()``. + + .. WARNING:: + + This is not the numerator of the rational function + defined by ``self``, which would always be ``self`` since it is a + polynomial. + + EXAMPLES:: + + sage: X. = InfinitePolynomialRing(QQ) + sage: p = 2/3*x[1] + 4/9*x[2] - 2*x[1]*x[3] + sage: num = p.numerator(); num + -18*x_3*x_1 + 4*x_2 + 6*x_1 + + TESTS:: + + sage: num.parent() + Infinite polynomial ring in x over Rational Field + + Check that :issue:`37756` is fixed:: + + sage: R. = InfinitePolynomialRing(QQ) + sage: P. = QQ[] + sage: FF = P.fraction_field() + sage: FF(a[0]) + Traceback (most recent call last): + ... + TypeError: Could not find a mapping of the passed element to this ring. + """ + P = self.parent() + return InfinitePolynomial(P, self._p.numerator()) + @cached_method def variables(self): """ @@ -569,9 +604,69 @@ def variables(self): () """ if hasattr(self._p, 'variables'): - return tuple(self._p.variables()) + P = self.parent() + return tuple(InfinitePolynomial(P, v) for v in self._p.variables()) return () + def monomials(self): + """ + Return the list of monomials in ``self``. + + The returned list is decreasingly ordered by the term ordering of + ``self.parent()``. + + EXAMPLES:: + + sage: X. = InfinitePolynomialRing(QQ) + sage: p = x[1]^3 + x[2] - 2*x[1]*x[3] + sage: p.monomials() + [x_3*x_1, x_2, x_1^3] + + sage: X. = InfinitePolynomialRing(QQ, order='deglex') + sage: p = x[1]^3 + x[2] - 2*x[1]*x[3] + sage: p.monomials() + [x_1^3, x_3*x_1, x_2] + """ + P = self.parent() + return [InfinitePolynomial(P, m) for m in self._p.monomials()] + + def monomial_coefficient(self, mon): + """ + Return the base ring element that is the coefficient of ``mon`` + in ``self``. + + This function contrasts with the function :meth:`coefficient`, + which returns the coefficient of a monomial viewing this + polynomial in a polynomial ring over a base ring having fewer + variables. + + INPUT: + + - ``mon`` -- a monomial in the parent of ``self`` + + OUTPUT: coefficient in base ring + + .. SEEALSO:: + + For coefficients in a base ring of fewer variables, + look at :meth:`coefficient`. + + EXAMPLES:: + + sage: X. = InfinitePolynomialRing(QQ) + sage: f = 2*x[0]*x[2] + 3*x[1]^2 + sage: c = f.monomial_coefficient(x[1]^2); c + 3 + sage: c.parent() + Rational Field + + sage: c = f.coefficient(x[2]); c + 2*x_0 + sage: c.parent() + Infinite polynomial ring in x over Rational Field + """ + return self._p.monomial_coefficient(mon._p) + @cached_method def max_index(self): r""" @@ -997,42 +1092,42 @@ def coefficient(self, monomial): sage: a.coefficient({x[0]:1, x[1]:1}) 2 """ + P = self.parent() if self._p == 0: - res = 0 - elif isinstance(monomial, self.__class__): - if not (self.parent().has_coerce_map_from(monomial.parent())): - res = 0 + return P.zero() + if isinstance(monomial, self.__class__): + if not P.has_coerce_map_from(monomial.parent()): + return P.zero() + if hasattr(self._p, 'variables'): + VarList = [str(X) for X in self._p.variables()] else: - if hasattr(self._p, 'variables'): - VarList = [str(X) for X in self._p.variables()] - else: - VarList = [] - if hasattr(monomial._p, 'variables'): - VarList.extend([str(X) for X in monomial._p.variables()]) - VarList = list(set(VarList)) - VarList.sort(key=self.parent().varname_key, reverse=True) - from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing - if len(VarList) == 1: - # 'xx' is guaranteed to be no variable - # name of monomial, since coercions - # were tested before - R = PolynomialRing(self._p.base_ring(), VarList + ['xx'], order=self.parent()._order) - - res = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order)(R(self._p).coefficient(R(monomial._p))) - else: - R = PolynomialRing(self._p.base_ring(), VarList, order=self.parent()._order) - res = R(self._p).coefficient(R(monomial._p)) - elif isinstance(monomial, dict): + VarList = [] + if hasattr(monomial._p, 'variables'): + VarList.extend([str(X) for X in monomial._p.variables()]) + VarList = list(set(VarList)) + VarList.sort(key=P.varname_key, reverse=True) + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + if len(VarList) == 1: + # 'xx' is guaranteed to be no variable + # name of monomial, since coercions + # were tested before + R = PolynomialRing(self._p.base_ring(), VarList + ['xx'], order=P._order) + S = PolynomialRing(self._p.base_ring(), VarList, order=P._order) + res = S(R(self._p).coefficient(R(monomial._p))) + return InfinitePolynomial(P, res) + + R = PolynomialRing(self._p.base_ring(), VarList, order=P._order) + res = R(self._p).coefficient(R(monomial._p)) + return InfinitePolynomial(P, res) + + if isinstance(monomial, dict): if monomial: I = iter(monomial) K = next(I) del monomial[K] - res = self.coefficient(K).coefficient(monomial) - else: - return self - else: - raise TypeError("Objects of type %s have no coefficients in InfinitePolynomials" % (type(monomial))) - return self.parent()(res) + return self.coefficient(K).coefficient(monomial) + return self + raise TypeError("Objects of type %s have no coefficients in InfinitePolynomials" % (type(monomial))) # Essentials for Buchberger def reduce(self, I, tailreduce=False, report=None): diff --git a/src/sage/rings/polynomial/infinite_polynomial_ring.py b/src/sage/rings/polynomial/infinite_polynomial_ring.py index afa4a4dc416..05735a21cd2 100644 --- a/src/sage/rings/polynomial/infinite_polynomial_ring.py +++ b/src/sage/rings/polynomial/infinite_polynomial_ring.py @@ -279,8 +279,8 @@ class InfinitePolynomialRingFactory(UniqueFactory): """ A factory for creating infinite polynomial ring elements. It - handles making sure that they are unique as well as handling - pickling. For more details, see + makes sure that they are unique as well as handling pickling. + For more details, see :class:`~sage.structure.factory.UniqueFactory` and :mod:`~sage.rings.polynomial.infinite_polynomial_ring`. @@ -564,7 +564,7 @@ def __init__(self, parent, start): def __next__(self): """ - Return a dictionary that can be used to interprete strings in the base ring of ``self``. + Return a dictionary that can be used to interpret strings in the base ring of ``self``. EXAMPLES:: @@ -701,7 +701,7 @@ def __init__(self, R, names, order): names = ['x'] for n in names: if not (isinstance(n, str) and n.isalnum() and (not n[0].isdigit())): - raise ValueError("generator names must be alpha-numeric strings not starting with a digit, but %s is not" % n) + raise ValueError("generator names must be alphanumeric strings not starting with a digit, but %s is not" % n) if len(names) != len(set(names)): raise ValueError("generator names must be pairwise different") self._names = tuple(names) @@ -884,6 +884,17 @@ def _element_constructor_(self, x): Traceback (most recent call last): ... ValueError: cannot convert 1/3 into an element of Infinite polynomial ring in x over Integer Ring + + .. WARNING:: + + The :issue:`37756` is not yet fixed:: + + sage: L. = QQ[] + sage: R. = InfinitePolynomialRing(QQ) + sage: M = InfinitePolynomialRing(L, names=["a"]) + sage: c = a[0] + sage: M(c) # known bug + a_0 """ from sage.rings.polynomial.infinite_polynomial_element import InfinitePolynomial # In many cases, the easiest solution is to "simply" evaluate diff --git a/src/sage/rings/polynomial/multi_polynomial.pyx b/src/sage/rings/polynomial/multi_polynomial.pyx index 6863e5a7316..c1fcaba8187 100644 --- a/src/sage/rings/polynomial/multi_polynomial.pyx +++ b/src/sage/rings/polynomial/multi_polynomial.pyx @@ -2665,7 +2665,7 @@ cdef class MPolynomial(CommutativePolynomial): if gens: # substituting all variables (in a polynomial ring with variables) with 0 - d = {str(gen): 0 for gen in gens} + d = {str(gen): self.base_ring().zero() for gen in gens} tester.assertEqual(self.subs(**d).parent(), self.parent().base_ring()) # substituting all variables (in a polynomial ring with variables) @@ -2678,7 +2678,7 @@ cdef class MPolynomial(CommutativePolynomial): if len(gens) > 1: # substituting one variable (in a polynomial ring with variables) with 0 - d = {str(gens[0]): 0} + d = {str(gens[0]): self.base_ring().zero()} tester.assertEqual(self.subs(**d).parent(), self.parent()) # test error checking: partial substitution by elements diff --git a/src/sage/rings/polynomial/multi_polynomial_element.py b/src/sage/rings/polynomial/multi_polynomial_element.py index 0e8d831b808..2f3abcfc26b 100644 --- a/src/sage/rings/polynomial/multi_polynomial_element.py +++ b/src/sage/rings/polynomial/multi_polynomial_element.py @@ -176,9 +176,14 @@ def __call__(self, *x, **kwds): K = x[0].parent() except AttributeError: K = self.parent().base_ring() - y = K(0) + try: + y = K.zero() + one = K.one() + except (AttributeError, RuntimeError): + y = K(0) + one = K(1) for m, c in self.element().dict().items(): - y += c * prod(v ** e for v, e in zip(x, m) if e) + y += c * prod((v ** e for v, e in zip(x, m) if e), one) return y def _richcmp_(self, right, op): diff --git a/src/sage/rings/polynomial/polydict.pyx b/src/sage/rings/polynomial/polydict.pyx index 0fbc3fb3860..caa60be81e6 100644 --- a/src/sage/rings/polynomial/polydict.pyx +++ b/src/sage/rings/polynomial/polydict.pyx @@ -800,7 +800,9 @@ cdef class PolyDict: ring = self.__repn[E[0]].parent() pos_one = ring.one() neg_one = -pos_one - except AttributeError: + except (AttributeError, ArithmeticError): + # AritchmeticError occurs when self.__repn[E[0]] is a tropical + # semiring element # probably self.__repn[E[0]] is not a ring element pos_one = 1 neg_one = -1 @@ -901,7 +903,9 @@ cdef class PolyDict: ring = self.__repn[E[0]].parent() pos_one = ring.one() neg_one = -pos_one - except AttributeError: + except (AttributeError, ArithmeticError): + # AritchmeticError occurs when self.__repn[E[0]] is a tropical + # semiring element # probably self.__repn[E[0]] is not a ring element pos_one = 1 neg_one = -1 diff --git a/src/sage/rings/polynomial/polynomial_element.pyx b/src/sage/rings/polynomial/polynomial_element.pyx index 4f20542237f..2338bbcb34f 100644 --- a/src/sage/rings/polynomial/polynomial_element.pyx +++ b/src/sage/rings/polynomial/polynomial_element.pyx @@ -6051,7 +6051,7 @@ cdef class Polynomial(CommutativePolynomial): - Naqi Jaffery (2006-01-24): examples """ - return not self.is_zero() and self[self.degree()] == 1 + return not self.is_zero() and self[self.degree()] == self.base_ring().one() def is_unit(self): r""" diff --git a/src/sage/rings/polynomial/polynomial_ring_constructor.py b/src/sage/rings/polynomial/polynomial_ring_constructor.py index 674a84f0ff7..a135fe8de6c 100644 --- a/src/sage/rings/polynomial/polynomial_ring_constructor.py +++ b/src/sage/rings/polynomial/polynomial_ring_constructor.py @@ -537,7 +537,7 @@ def PolynomialRing(base_ring, *args, **kwds): sage: PolynomialRing(4) Traceback (most recent call last): ... - TypeError: base_ring 4 must be a ring + TypeError: base_ring 4 must be a ring or the tropical semiring sage: PolynomialRing(QQ, -1) Traceback (most recent call last): ... @@ -622,8 +622,9 @@ def PolynomialRing(base_ring, *args, **kwds): sage: R. = PolynomialRing(RIF,2) sage: TestSuite(R).run(skip=['_test_elements', '_test_elements_eq_transitive']) """ - if base_ring not in Rings(): - raise TypeError("base_ring {!r} must be a ring".format(base_ring)) + from sage.rings.semirings.tropical_semiring import TropicalSemiring + if base_ring not in Rings() and not isinstance(base_ring, TropicalSemiring): + raise TypeError("base_ring {!r} must be a ring or the tropical semiring".format(base_ring)) n = -1 # Unknown number of variables names = None # Unknown variable names @@ -792,7 +793,11 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non # Generic implementations if constructor is None: - if base_ring not in _CommutativeRings: + from sage.rings.semirings.tropical_semiring import TropicalSemiring + if isinstance(base_ring, TropicalSemiring): + from sage.rings.semirings.tropical_polynomial import TropicalPolynomialSemiring + constructor = TropicalPolynomialSemiring + elif base_ring not in _CommutativeRings: constructor = polynomial_ring.PolynomialRing_general elif base_ring in _CompleteDiscreteValuationRings: constructor = polynomial_ring.PolynomialRing_cdvr @@ -804,6 +809,7 @@ def _single_variate(base_ring, name, sparse=None, implementation=None, order=Non constructor = polynomial_ring.PolynomialRing_integral_domain else: constructor = polynomial_ring.PolynomialRing_commutative + implementation_names = constructor._implementation_names(implementation, base_ring, sparse) # Only use names which are not supported by the specialized class. @@ -861,7 +867,11 @@ def _multi_variate(base_ring, names, sparse=None, order='degrevlex', implementat if R is None and implementation == "generic": from . import multi_polynomial_ring - if base_ring in _Domains: + from sage.rings.semirings.tropical_semiring import TropicalSemiring + if isinstance(base_ring, TropicalSemiring): + from sage.rings.semirings.tropical_mpolynomial import TropicalMPolynomialSemiring + constructor = TropicalMPolynomialSemiring + elif base_ring in _Domains: constructor = multi_polynomial_ring.MPolynomialRing_polydict_domain else: constructor = multi_polynomial_ring.MPolynomialRing_polydict @@ -1024,4 +1034,4 @@ def BooleanPolynomialRing_constructor(n=None, names=None, order='lex'): ############################################################################ # END (Factory function for making polynomial rings) -############################################################################ +############################################################################ \ No newline at end of file diff --git a/src/sage/rings/ring.pyx b/src/sage/rings/ring.pyx index 5ad885351cc..d3915484b8b 100644 --- a/src/sage/rings/ring.pyx +++ b/src/sage/rings/ring.pyx @@ -18,7 +18,7 @@ The class inheritance hierarchy is: - :class:`Ring` (to be deprecated) - - :class:`Algebra` (to be deprecated) + - :class:`Algebra` (deprecated and essentially removed) - :class:`CommutativeRing` - :class:`NoetherianRing` (deprecated) @@ -70,12 +70,12 @@ This is to test a deprecation:: sage: from sage.rings.ring import CommutativeAlgebra sage: class Nein(CommutativeAlgebra): ....: pass - sage: F = Nein(QQ, QQ) + sage: F = Nein(QQ) ...: DeprecationWarning: use the category CommutativeAlgebras See https://github.com/sagemath/sage/issues/37999 for details. sage: F.category() - Category of commutative rings + Category of commutative algebras over Rational Field sage: from sage.rings.ring import PrincipalIdealDomain sage: class Non(PrincipalIdealDomain): @@ -86,6 +86,17 @@ This is to test a deprecation:: See https://github.com/sagemath/sage/issues/37719 for details. sage: F.category() Category of principal ideal domains + + sage: from sage.rings.ring import Algebra + sage: class Nichts(Algebra): + ....: pass + sage: F = Nichts(QQ) + ...: + DeprecationWarning: use the category Algebras + See https://github.com/sagemath/sage/issues/38502 for details. + sage: F.category() + Category of algebras over Rational Field + """ # **************************************************************************** @@ -105,6 +116,8 @@ from sage.structure.parent cimport Parent from sage.structure.category_object cimport check_default_category from sage.misc.prandom import randint from sage.categories.rings import Rings +from sage.categories.algebras import Algebras +from sage.categories.commutative_algebras import CommutativeAlgebras from sage.categories.commutative_rings import CommutativeRings from sage.categories.integral_domains import IntegralDomains from sage.categories.dedekind_domains import DedekindDomains @@ -1474,32 +1487,18 @@ cdef class Field(CommutativeRing): cdef class Algebra(Ring): - """ - Generic algebra - """ - def __init__(self, base_ring, names=None, normalize=True, category=None): - """ - Initialize ``self``. - - EXAMPLES:: - - sage: A = Algebra(ZZ); A # needs sage.modules - - """ - # 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 Algebras(base_ring). - if category is None: - category = check_default_category(Algebras(base_ring), category) - Ring.__init__(self,base_ring, names=names, normalize=normalize, - category=category) + def __init__(self, base_ring, *args, **kwds): + if 'category' not in kwds: + kwds['category'] = Algebras(base_ring) + deprecation(38502, "use the category Algebras") + super().__init__(base_ring, *args, **kwds) cdef class CommutativeAlgebra(CommutativeRing): - __default_category = _CommutativeRings - def __init__(self, base_ring, *args, **kwds): + self._default_category = CommutativeAlgebras(base_ring) deprecation(37999, "use the category CommutativeAlgebras") - super().__init__(*args, **kwds) + super().__init__(base_ring, *args, **kwds) def is_Ring(x): diff --git a/src/sage/rings/semirings/tropical_mpolynomial.py b/src/sage/rings/semirings/tropical_mpolynomial.py new file mode 100644 index 00000000000..a482e097f89 --- /dev/null +++ b/src/sage/rings/semirings/tropical_mpolynomial.py @@ -0,0 +1,692 @@ +r""" +Multivariate Tropical Polynomials + +AUTHORS: + +- Verrel Rievaldo Wijaya (2024-06): initial version + +EXAMPLES:: + + sage: T = TropicalSemiring(QQ, use_min=True) + sage: R. = PolynomialRing(T) + sage: z.parent() + Multivariate Tropical Polynomial Semiring in x, y, z over Rational Field + sage: R(2)*x + R(-1)*x + R(5)*y + R(-3) + (-1)*x + 5*y + (-3) + sage: (x+y+z)^2 + 0*x^2 + 0*x*y + 0*y^2 + 0*x*z + 0*y*z + 0*z^2 + +REFERENCES: + +- [Bru2014]_ +- [Fil2017]_ +""" + +# **************************************************************************** +# Copyright (C) 2024 Verrel Rievaldo Wijaya +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.structure.parent import Parent +from sage.structure.unique_representation import UniqueRepresentation +from sage.rings.polynomial.multi_polynomial_element import MPolynomial_polydict + +class TropicalMPolynomial(MPolynomial_polydict): + r""" + A multivariate tropical polynomial. + + Let `x_1, x_2, \ldots, x_n` be indeterminants. A tropical monomial is + any product of these variables, possibly including repetitions: + `x_1^{i_1}\cdots x_n^{i_n}` where `i_j \in \{0,1,\ldots\}`, for all + `j\in \{1,\ldots,n\}`. A multivariate tropical polynomial is a finite + linear combination of tropical monomials, + `p(x_1, \ldots, x_n) = \sum_{i=1}^n c_i x_1^{i_1}\cdots x_n^{i_n}`. + + In classical arithmetic, we can rewrite the general form of a tropical + monomial: `x_1^{i_1}\cdots x_n^{i_n} \mapsto i_1 x_1 + \cdots + i_n x_n`. + Thus, the tropical polynomial can be viewed as the minimum (maximum) of + a finite collection of linear functions. + + EXAMPLES: + + Construct a multivariate tropical polynomial semiring in two variables:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T); R + Multivariate Tropical Polynomial Semiring in a, b over Rational Field + + Define some multivariate tropical polynomials:: + + sage: p1 = R(3)*a*b + a + R(-1)*b; p1 + 3*a*b + 0*a + (-1)*b + sage: p2 = R(1)*a + R(1)*b + R(1)*a*b; p2 + 1*a*b + 1*a + 1*b + + Some basic arithmetic operations for multivariate tropical polynomials:: + + sage: p1 + p2 + 3*a*b + 1*a + 1*b + sage: p1 * p2 + 4*a^2*b^2 + 4*a^2*b + 4*a*b^2 + 1*a^2 + 1*a*b + 0*b^2 + sage: T(2) * p1 + 5*a*b + 2*a + 1*b + sage: p1(T(1),T(2)) + 6 + + Let us look at the different result for tropical curve and 3d graph + of tropical polynomial in two variables when different algebra is used. + First for the min-plus algebra:: + + sage: T = TropicalSemiring(QQ, use_min=True) + sage: R. = PolynomialRing(T) + sage: p1 = R(3)*a*b + a + R(-1)*b + sage: p1.tropical_variety() + Tropical curve of 3*a*b + 0*a + (-1)*b + sage: p1.tropical_variety().plot() + Graphics object consisting of 3 graphics primitives + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=True) + R = PolynomialRing(T, ('a,b')) + a, b = R.gen(), R.gen(1) + p1 = R(3)*a*b + a + R(-1)*b + tv1 = p1.tropical_variety() + sphinx_plot(tv1.plot()) + + Tropical polynomial in two variables will induce a function in three + dimension that consists of a number of surfaces:: + + sage: p1.plot3d() + Graphics3d Object + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=True) + R = PolynomialRing(T, ('a,b')) + a, b = R.gen(), R.gen(1) + p1 = R(3)*a*b + a + R(-1)*b + sphinx_plot(p1.plot3d()) + + If we use a max-plus algebra, we will get a slightly different result:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = R(3)*a*b + a + R(-1)*b + sage: p1.tropical_variety() + Tropical curve of 3*a*b + 0*a + (-1)*b + sage: p1.tropical_variety().plot() + Graphics object consisting of 3 graphics primitives + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=False) + R = PolynomialRing(T, ('a,b')) + a, b = R.gen(), R.gen(1) + p1 = R(3)*a*b + a + R(-1)*b + tv1 = p1.tropical_variety() + sphinx_plot(tv1.plot()) + + :: + + sage: p1.plot3d() + Graphics3d Object + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=False) + R = PolynomialRing(T, ('a,b')) + a, b = R.gen(), R.gen(1) + p1 = R(3)*a*b + a + R(-1)*b + sphinx_plot(p1.plot3d()) + + TESTS: + + There is no subtraction defined for tropical polynomials:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: a - b + Traceback (most recent call last): + ... + ArithmeticError: cannot negate any non-infinite element + """ + def subs(self, fixed=None, **kwds): + r""" + Fix some given variables in ``self`` and return the changed + tropical multivariate polynomials. + + .. SEEALSO:: + + :meth:`sage.rings.polynomial.multi_polynomial_element.MPolynomial_polydict.subs` + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = x^2 + y + R(3) + sage: p1((R(4),y)) + 0*y + 8 + sage: p1.subs({x: 4}) + 0*y + 8 + """ + variables = list(self.parent().gens()) + for i in range(len(variables)): + if str(variables[i]) in kwds: + variables[i] = kwds[str(variables[i])] + elif fixed: + if variables[i] in fixed: + variables[i] = fixed[variables[i]] + elif i in fixed: + variables[i] = fixed[i] + if len(kwds) < len(variables): + for i, v in enumerate(variables): + variables[i] = self.parent()(v) + return self(tuple(variables)) + + def plot3d(self, color='random'): + """ + Return the 3d plot of ``self``. + + Only implemented for tropical polynomial in two variables. + The `x`-`y` axes for this 3d plot is the same as the `x`-`y` + axes of the corresponding tropical curve. + + OUTPUT: Graphics3d Object + + EXAMPLES: + + A simple tropical polynomial that consist of only one surface:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = x^2 + sage: p1.plot3d() + Graphics3d Object + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=False) + R = PolynomialRing(T, ('x,y')) + x, y = R.gen(), R.gen(1) + p1 = x**2 + sphinx_plot(p1.plot3d()) + + Tropical polynomials often have graphs that represent a combination + of multiple surfaces:: + + sage: p2 = R(3) + R(2)*x + R(2)*y + R(3)*x*y + sage: p2.plot3d() + Graphics3d Object + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=False) + R = PolynomialRing(T, ('x,y')) + x, y = R.gen(), R.gen(1) + p2 = R(3) + R(2)*x + R(2)*y + R(3)*x*y + sphinx_plot(p2.plot3d()) + + :: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p3 = R(2)*x^2 + x*y + R(2)*y^2 + x + R(-1)*y + R(3) + sage: p3.plot3d() + Graphics3d Object + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ) + R = PolynomialRing(T, ('x,y')) + x, y = R.gen(), R.gen(1) + p3 = R(2)*x**2 + x*y + R(2)*y**2 + x + R(-1)*y + R(3) + sphinx_plot(p3.plot3d()) + + TESTS:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x*y*z + x + sage: p1.plot3d() + Traceback (most recent call last): + ... + NotImplementedError: can only plot the graph of tropical + multivariate polynomial in two variables + """ + from random import random + from sage.plot.graphics import Graphics + from sage.geometry.polyhedron.constructor import Polyhedron + from sage.sets.real_set import RealSet + from sage.symbolic.relation import solve + + if len(self.parent().variable_names()) != 2: + raise NotImplementedError("can only plot the graph of tropical " + "multivariate polynomial in two variables") + tv = self.tropical_variety() + axes = tv._axes() + edge = set() + if tv.components(): + v = tv._vars[0] + T = self.parent().base() + R = self.base_ring().base_ring() + + # Finding the point of curve that touch the edge of the axes + for comp in tv.components(): + if len(comp[1]) == 1: + valid_int = RealSet(comp[1][0]) + else: + valid_int = RealSet(comp[1][0]).intersection(RealSet(comp[1][1])) + for i, eqn in enumerate(comp[0]): + j = (i+1) % 2 + if not eqn.is_numeric(): + for k in range(2): + sol = solve(eqn == axes[i][k], v) + if sol[0].rhs() in valid_int: + valid_point = [R(eq.subs(**{str(v): sol[0].rhs()})) for eq in comp[0]] + if valid_point[j] in RealSet(axes[j]): + edge.add(tuple(valid_point)) + + # Combine the edge, vertices, and corner point + vertices = self.tropical_variety().vertices() + corner = set() + for i in axes[0]: + for j in axes[1]: + corner.add((i,j)) + marks = corner | vertices | edge + + # Calculate the value of polynomial at each marked point + variables = self.parent().gens() + terms = [a*variables[0]**b[0] * variables[1]**b[1] for a, b in zip(self.coefficients(), self.exponents())] + point_terms = {} + for mark in marks: + mark_terms = [] + value = self(T(mark[0]), T(mark[1])) + value_terms = [term(T(mark[0]), T(mark[1])) for term in terms] + for i in range(len(terms)): + if value_terms[i] == value: + mark_terms.append(terms[i]) + point_terms[(R(mark[0]), R(mark[1]), value.lift())] = mark_terms + + # Plot the points that attained its value at one term only + combined_plot = Graphics() + for elms in point_terms.values(): + if len(elms) == 1: + poly_vert = [] + term = elms[0] + for p, t in point_terms.items(): + if term in t: + poly_vert.append(p) + t.remove(term) + if color == 'random': + rand_color = (random(), random(), random()) + plot = Polyhedron(vertices=poly_vert).plot(color=rand_color) + combined_plot += plot + + # Plot the remaining points + for remain in point_terms.values(): + for term in remain: + poly_vert = [] + for p, t in point_terms.items(): + if term in t: + poly_vert.append(p) + t.remove(term) + if color == 'random': + rand_color = (random(), random(), random()) + plot = Polyhedron(vertices=poly_vert).plot(color=rand_color) + combined_plot += plot + return combined_plot + + def tropical_variety(self): + r""" + Return tropical roots of ``self``. + + In the multivariate case, the roots can be represented by a + tropical variety. In two dimensions, this is known as a tropical + curve. For dimensions higher than two, it is referred to as a + tropical hypersurface. + + OUTPUT: a :class:`sage.rings.semirings.tropical_variety.TropicalVariety` + + EXAMPLES: + + Tropical curve for tropical polynomials in two variables:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = x + y + R(0); p1 + 0*x + 0*y + 0 + sage: p1.tropical_variety() + Tropical curve of 0*x + 0*y + 0 + + Tropical hypersurface for tropical polynomials in more than two + variables:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = R(1)*x*y + R(-1/2)*x*z + R(4)*z^2; p1 + 1*x*y + (-1/2)*x*z + 4*z^2 + 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 + + if self.parent().ngens() == 2: + return TropicalCurve(self) + if self.parent().ngens() == 3: + return TropicalSurface(self) + return TropicalVariety(self) + + def _repr_(self): + r""" + Return string representation of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: x + R(-1)*y + R(-3) + 0*x + (-1)*y + (-3) + """ + if not self.dict(): + return str(self.parent().base().zero()) + s = super()._repr_() + if self.monomials()[-1].is_constant(): + if self.monomial_coefficient(self.parent()(0)) < 0: + s = s.replace(" - ", " + -") + const = str(self.monomial_coefficient(self.parent(0))) + s = s.replace(f" {const}", f" ({const})") + return s + + def _latex_(self): + r""" + Return the latex representation of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x^2 + R(-1)*x*y + R(-1) + sage: latex(p1) + 0 x^{2} + \left(-1\right) x y + \left(-1\right) + sage: latex(R.zero()) + \infty + """ + if not self.dict(): + return self.parent().base().zero()._latex_() + s = super()._latex_() + if self.monomials()[-1].is_constant(): + if self.monomial_coefficient(self.parent()(0)) < 0: + s = s.replace(" - ", " + -") + const = str(self.monomial_coefficient(self.parent(0))) + s = s.replace(f" {const}", f" \\left({const}\\right)") + return s + + +class TropicalMPolynomialSemiring(UniqueRepresentation, Parent): + r""" + The semiring of tropical polynomials in multiple variables. + + This is the commutative semiring consisting of all finite linear + combinations of tropical monomials under (tropical) addition + and multiplication with coefficients in a tropical semiring. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: f = T(1)*x + T(-1)*y + sage: g = T(2)*x + T(-2)*y + sage: f + g + 1*x + (-2)*y + sage: f * g + 3*x^2 + (-1)*x*y + (-3)*y^2 + sage: f + R.zero() == f + True + sage: f * R.zero() == R.zero() + True + sage: f * R.one() == f + True + """ + def __init__(self, base_semiring, n, names, order): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 5, 'x') + sage: TestSuite(R).run() + """ + from sage.rings.semirings.tropical_semiring import TropicalSemiring + from sage.categories.semirings import Semirings + 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()) + self._ngens = n + self._term_order = order + + def term_order(self): + """ + Return the defined term order of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: R.term_order() + Degree reverse lexicographic term order + """ + return self._term_order + + Element = TropicalMPolynomial + + def _element_constructor_(self, x): + r"""" + Convert ``x`` into ``self``. + + INPUT: + + - ``x`` -- ``dict``, constant, or :class:`MPolynomial` + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 'x,y') + sage: dict1 = {(1,0):0, (0,1):-1, (1,1):3} + sage: p1 = R(dict1); p1 + 3*x*y + 0*x + (-1)*y + sage: S. = PolynomialRing(QQ) + sage: f = -x*y + 1 + sage: R(f) + (-1)*x*y + 1 + + TESTS:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: S. = PolynomialRing(T) + sage: R(a + b) + Traceback (most recent call last): + ... + ValueError: can not convert 0*a + 0*b to Multivariate Tropical + Polynomial Semiring in x, y over Rational Field + """ + from sage.rings.polynomial.multi_polynomial import MPolynomial + if isinstance(x, TropicalMPolynomial): + if x.parent() is not self: + raise ValueError(f"can not convert {x} to {self}") + if isinstance(x, MPolynomial): + if x.parent().variable_names() == self.variable_names(): + x = x.dict() + else: + raise ValueError(f"can not convert {x} to {self}") + elif (x in self.base().base_ring()) or (x in self.base()): + term = [0] * self.ngens() + x = {tuple(term): x} + + if isinstance(x, dict): + for key, value in x.items(): + x[key] = self.base()(value) + return self.element_class(self, x) + + @cached_method + def one(self): + r""" + Return the multiplicative identity of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 'x,y') + sage: R.one() + 0 + """ + exponent = [0] * self.ngens() + return self.element_class(self, {tuple(exponent): self.base().one()}) + + @cached_method + def zero(self): + r""" + Return the additive identity of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 'x,y') + sage: R.zero() + +infinity + """ + exponent = [0] * self.ngens() + return self.element_class(self, {tuple(exponent): self.base().zero()}) + + def _repr_(self): + r""" + Return a string representation of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(RR) + sage: R. = PolynomialRing(T); R + Multivariate Tropical Polynomial Semiring in u, v, w over Real + Field with 53 bits of precision + """ + if self._ngens == 0: + return (f"Multivariate Tropical Polynomial Semiring in no variables" + f" over {self.base_ring().base_ring()}") + return (f"Multivariate Tropical Polynomial Semiring in {', '.join(self.variable_names())}" + f" over {self.base_ring().base_ring()}") + + def random_element(self, degree=2, terms=None, choose_degree=False, + *args, **kwargs): + r""" + Return a random multivariate tropical polynomial from ``self``. + + OUTPUT: a :class:`TropicalMPolynomial` + + .. SEEALSO:: + + :meth:`sage.rings.polynomial.multi_polynomial_ring_base.MPolynomialRing_base.random_element` + + EXAMPLES: + + A random polynomial of at most degree `d` and at most `t` terms:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: f = R.random_element(2, 5) + sage: f.degree() <= 2 + True + sage: f.parent() is R + True + sage: len(list(f)) <= 5 + True + + Choose degrees of monomials randomly first rather than monomials + uniformly random:: + + sage: f = R.random_element(3, 6, choose_degree=True) + sage: f.degree() <= 3 + True + sage: f.parent() is R + True + sage: len(list(f)) <= 6 + True + """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self.base().base_ring(), self.variable_names()) + f = R.random_element(degree=degree, terms=terms, choose_degree=choose_degree, + *args, **kwargs) + new_dict = {} + for key, value in f.dict().items(): + new_dict[key] = self.base()(value) + return self.element_class(self, new_dict) + + def gen(self, n=0): + r""" + Return the ``n``-th generator of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: R.gen() + 0*a + sage: R.gen(2) + 0*c + + TESTS:: + + sage: R.gen(3) + Traceback (most recent call last): + ... + IndexError: tuple index out of range + """ + return self.gens()[n] + + @cached_method + def gens(self): + r""" + Return the generators of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 5, 'x') + sage: R.gens() + (0*x0, 0*x1, 0*x2, 0*x3, 0*x4) + """ + gens = [] + for i in range(self.ngens()): + exponent = [0] * self.ngens() + exponent[i] = 1 + element = self.element_class(self, {tuple(exponent): self.base().one()}) + gens.append(element) + return tuple(gens) + + def ngens(self): + r""" + Return the number of generators of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 10, 'z') + sage: R.ngens() + 10 + """ + from sage.rings.integer_ring import ZZ + return ZZ(self._ngens) diff --git a/src/sage/rings/semirings/tropical_polynomial.py b/src/sage/rings/semirings/tropical_polynomial.py new file mode 100644 index 00000000000..f1d41c17ee0 --- /dev/null +++ b/src/sage/rings/semirings/tropical_polynomial.py @@ -0,0 +1,993 @@ +r""" +Univariate Tropical Polynomials + +AUTHORS: + +- Verrel Rievaldo Wijaya (2024-06): initial version + +EXAMPLES:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: x.parent() + Univariate Tropical Polynomial Semiring in x over Rational Field + sage: (x + R(3)*x) * (x^2 + x) + 3*x^3 + 3*x^2 + sage: (x^2 + R(1)*x + R(-1))^2 + 0*x^4 + 1*x^3 + 2*x^2 + 0*x + (-2) + +REFERENCES: + +- [Bru2014]_ +- [Fil2017]_ +""" + +# **************************************************************************** +# Copyright (C) 2024 Verrel Rievaldo Wijaya +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# https://www.gnu.org/licenses/ +# **************************************************************************** + +from sage.misc.cachefunc import cached_method +from sage.structure.unique_representation import UniqueRepresentation +from sage.structure.parent import Parent +from sage.rings.polynomial.polynomial_element_generic import Polynomial_generic_sparse + +class TropicalPolynomial(Polynomial_generic_sparse): + r""" + A univariate tropical polynomial. + + A tropical polynomial is a polynomial whose coefficients come from + a tropical semiring. Tropical polynomial induces a function which is + piecewise linear, where each segment of the function has a non-negative + integer slope. Tropical roots (zeros) of polynomial `P(x)` is defined + as all points `x_0` for which the graph of `P(x)` change its slope. + The difference in the slopes of the two pieces adjacent to this root + gives the order of the root. + + The tropical polynomials are implemented with a sparse format by using + a ``dict`` whose keys are the exponent and values the corresponding + coefficients. Each coefficient is a tropical number. + + EXAMPLES: + + First, we construct a tropical polynomial semiring by defining a base + tropical semiring and then inputting it to :class:`PolynomialRing`:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T); R + Univariate Tropical Polynomial Semiring in x over Rational Field + sage: R.0 + 0*x + + One way to construct an element is to provide a list or tuple of + coefficients. Another way to define an element is to write a polynomial + equation with each coefficient converted to the semiring:: + + sage: p1 = R([1,4,None,0]); p1 + 0*x^3 + 4*x + 1 + sage: p2 = R(1)*x^2 + R(2)*x + R(3); p2 + 1*x^2 + 2*x + 3 + + We can do some basic arithmetic operations for these tropical polynomials. + Remember that numbers given have to be in the tropical semiring. + If not, then it will raise an error:: + + sage: p1 + p2 + 0*x^3 + 1*x^2 + 4*x + 3 + sage: p1 * p2 + 1*x^5 + 2*x^4 + 5*x^3 + 6*x^2 + 7*x + 4 + sage: 2 * p1 + Traceback (most recent call last): + ... + ArithmeticError: cannot negate any non-infinite element + sage: T(2) * p1 + 2*x^3 + 6*x + 3 + sage: p1(3) + Traceback (most recent call last): + ... + TypeError: no common canonical parent for objects with parents: + 'Tropical semiring over Rational Field' and 'Integer Ring' + sage: p1(T(3)) + 9 + + We can find all tropical roots of a tropical polynomial, counted + with their multiplicities:: + + sage: p1.roots() + [-3, 2, 2] + sage: p2.roots() + [1, 1] + + Even though every tropical polynomials have tropical roots, this does not + neccessarily means it can be factored into its linear factors:: + + sage: p1.factor() + (0) * (0*x^3 + 4*x + 1) + sage: p2.factor() + (1) * (0*x + 1)^2 + + Every tropical polynomial `p(x)` have a corresponding unique tropical + polynomial `\bar{p}(x)` with the same roots that can be factored. We + call `\bar{p}(x)` the tropical polynomial split form of `p(x)`:: + + sage: p1.split_form() + 0*x^3 + 2*x^2 + 4*x + 1 + sage: p2.split_form() + 1*x^2 + 2*x + 3 + + Every tropical polynomial induce a piecewise linear function that can be + invoked in the following way:: + + sage: p1.piecewise_function() + piecewise(x|-->1 on (-oo, -3], x|-->x + 4 on (-3, 2), x|-->3*x on [2, +oo); x) + sage: p1.plot() + Graphics object consisting of 1 graphics primitive + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=False) + R = PolynomialRing(T, 'x') + p1 = R([1,4,None,0]) + sphinx_plot(p1.plot()) + + :: + + sage: p2.piecewise_function() + piecewise(x|-->3 on (-oo, 1], x|-->2*x + 1 on (1, +oo); x) + sage: p2.plot() + Graphics object consisting of 1 graphics primitive + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=False) + R = PolynomialRing(T, 'x') + x = R.gen() + p2 = R(1)*x**2 + R(2)*x + R(3) + sphinx_plot(plot(p2, xmin=-1, xmax=3)) + + TESTS: + + There is no subtraction for tropical polynomials because element in + tropical semiring doesn't necessarily have additive inverse:: + + sage: -p1 + Traceback (most recent call last): + ... + ArithmeticError: cannot negate any non-infinite element + """ + def roots(self): + r""" + Return the list of all tropical roots of ``self``, counted with + multiplicity. + + OUTPUT: a list of tropical numbers + + ALGORITHM: + + For each pair of monomials in the polynomial, we find the point + where their values are equal. This is the same as solving the + equation `c_1 + a_1 \cdot x = c_2 + a_2 \cdot x` for `x`, where + `(c_1, a_1)` and `(c_2, a_2)` are the coefficients and exponents + of monomials. + + The solution to this equation is `x = (c_2-c_1)/(a_1-a_2)`. We + substitute this `x` to each monomials in polynomial and check if + the maximum (minimum) is achieved by the previous two monomials. + If it is, then `x` is the root of tropical polynomial. In this + case, the order of the root at `x` is the maximum of `|i-j|` for + all possible pairs `i,j` which realise this maximum (minimum). + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ, use_min=True) + sage: R. = PolynomialRing(T) + sage: p1 = R([5,4,1,0,2,4,3]); p1 + 3*x^6 + 4*x^5 + 2*x^4 + 0*x^3 + 1*x^2 + 4*x + 5 + sage: p1.roots() + [-1, -1, -1, 1, 2, 2] + + There will be no tropical root for constant polynomial. Additionaly, + for a monomial, the tropical root is assumed to be the additive + identity of its base tropical semiring:: + + sage: p2 = R(2) + sage: p2.roots() + [] + sage: p3 = x^3 + sage: p3.roots() + [+infinity, +infinity, +infinity] + """ + from itertools import combinations + tropical_roots = [] + data = self.dict() + R = self.parent().base() + if len(data) == 1: + exponent = next(iter(data)) + if not exponent: + return tropical_roots + return [R.zero()] * exponent + dict_root = {} + dict_coeff = {i: c.lift() for i, c in data.items()} + for comb in combinations(dict_coeff, 2): + index1, index2 = comb[0], comb[1] + root = (dict_coeff[index1]-dict_coeff[index2]) / (index2-index1) + val_root = dict_coeff[index1] + index1*root + check_maks = True + for key in dict_coeff: + if key not in comb: + val = dict_coeff[key] + key*root + if R._use_min: + if val < val_root: + check_maks = False + break + elif val > val_root: + check_maks = False + break + if check_maks: + order = abs(index1-index2) + if root not in dict_root: + dict_root[root] = order + elif order > dict_root[root]: + dict_root[root] = order + for root in dict_root: + tropical_roots += [root] * dict_root[root] + return sorted(tropical_roots) + + def split_form(self): + r""" + Return the tropical polynomial which has the same roots as ``self`` + but which can be reduced to its linear factors. + + If a tropical polynomial has roots at `x_1, x_2, \ldots, x_n`, then + its split form is the tropical product of linear terms of the form + `(x + x_i)` for all `i=1,2,\ldots,n`. + + OUTPUT: :class:`TropicalPolynomial` + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ, use_min=True) + sage: R. = PolynomialRing(T) + sage: p1 = R([5,4,1,0,2,4,3]); p1 + 3*x^6 + 4*x^5 + 2*x^4 + 0*x^3 + 1*x^2 + 4*x + 5 + sage: p1.split_form() + 3*x^6 + 2*x^5 + 1*x^4 + 0*x^3 + 1*x^2 + 3*x + 5 + + :: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = R([5,4,1,0,2,4,3]) + sage: p1.split_form() + 3*x^6 + 4*x^5 + 21/5*x^4 + 22/5*x^3 + 23/5*x^2 + 24/5*x + 5 + + TESTS: + + We verify that the roots of tropical polynomial and its split form + is really the same:: + + sage: p1.roots() == p1.split_form().roots() + True + """ + roots = self.roots() + R = self.parent() + poly = R(self.dict()[self.degree()].lift()) + for root in roots: + linear = R([root, 0]) + poly *= linear + return poly + + def factor(self): + r""" + Return the factorization of ``self`` into its tropical linear factors. + + Note that the factor `x - x_0` in classical algebra gets transformed + to the factor `x + x_0`, since the root of the tropical polynomial + `x + x_0` is `x_0` and not `-x_0`. However, not every tropical + polynomial can be factored. + + OUTPUT: a :class:'Factorization' + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ, use_min=True) + sage: R. = PolynomialRing(T) + sage: p1 = R([6,3,1,0]); p1 + 0*x^3 + 1*x^2 + 3*x + 6 + sage: factor(p1) + (0) * (0*x + 1) * (0*x + 2) * (0*x + 3) + + Such factorization is not always possible:: + + sage: p2 = R([4,4,2]); p2 + 2*x^2 + 4*x + 4 + sage: p2.factor() + (2) * (0*x^2 + 2*x + 2) + + TESTS: + + The factorization for a constant:: + + sage: p3 = R(3) + sage: p3.factor() + (3) * 0 + """ + from sage.structure.factorization import Factorization + unit = self.dict()[self.degree()] + if self != self.split_form() or not self.roots(): + factor = [(self * self.parent(-unit.lift()), 1)] + return Factorization(factor, unit=unit) + + R = self.parent() + roots_order = {} + for root in self.roots(): + if root in roots_order: + roots_order[root] += 1 + else: + roots_order[root] = 1 + factors = [] + for root in roots_order: + factors.append((R([root, 0]), roots_order[root])) + return Factorization(factors, unit=unit) + + def piecewise_function(self): + r""" + Return the tropical polynomial function of ``self``. + + The function is a piecewise linear function with the domains are + divided by the roots. First we convert each term of polynomial to + its corresponding linear function. Next, we must determine which + term achieves the minimum (maximum) at each interval. + + OUTPUT: A piecewise function + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = R([4,2,1,3]); p1 + 3*x^3 + 1*x^2 + 2*x + 4 + sage: p1.piecewise_function() + piecewise(x|-->4 on (-oo, 1/3], x|-->3*x + 3 on (1/3, +oo); x) + + A constant tropical polynomial will result in a constant function:: + + sage: p2 = R(3) + sage: p2.piecewise_function() + 3 + + A monomial will resulted in a linear function:: + + sage: p3 = R(1)*x^3 + 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 + + x = SR.var('x') + data = self.dict() + R = self.parent().base() + if not self.roots(): + f = data[0].lift() + return f + + if len(data) == 1: + gradient = list(data)[0] + intercept = data[gradient].lift() + f = intercept + gradient*x + return f + + unique_root = sorted(list(set(self.roots()))) + pieces = [] + domain = [] + for i in range(len(unique_root)+1): + if i == 0: + test_number = R(unique_root[i] - 1) + elif i == len(unique_root): + test_number = R(unique_root[i-1] + 1) + else: + test_number = R((unique_root[i]+unique_root[i-1]) / 2) + terms = {i: c * test_number**i for i, c in data.items()} + if R._use_min: + critical = min(terms.values()) + else: + critical = max(terms.values()) + found_key = None + for key, value in terms.items(): + if value == critical: + found_key = key + break + gradient = found_key + intercept = data[found_key].lift() + + # To make sure all roots is included in the domain + if i == 0: + interval = RealSet.unbounded_below_closed(unique_root[i]) + piecewise_linear = (interval, intercept + gradient*x) + domain.append(interval) + elif i == len(unique_root): + if domain[i-1][0].upper_closed(): + interval = RealSet.unbounded_above_open(unique_root[i-1]) + else: + interval = RealSet.unbounded_above_closed(unique_root[i-1]) + piecewise_linear = (interval, intercept + gradient*x) + domain.append(interval) + else: + if domain[i-1][0].upper_closed(): + interval = RealSet((unique_root[i-1], unique_root[i])) + else: + interval = RealSet([unique_root[i-1], unique_root[i]]) + piecewise_linear = (interval, intercept + gradient*x) + domain.append(interval) + pieces.append(piecewise_linear) + + f = piecewise(pieces) + return f + + def plot(self, xmin=None, xmax=None): + r""" + Return the plot of ``self``, which is the tropical polynomial + function we get from ``self.piecewise_function()``. + + INPUT: + + - ``xmin`` -- (optional) real number + - ``xmax`` -- (optional) real number + + OUTPUT: + + If ``xmin`` and ``xmax`` is given, then it return a plot of + piecewise linear function of ``self`` with the axes start from + ``xmin`` to ``xmax``. Otherwise, the domain will start from the + the minimum root of ``self`` minus 1 to maximum root of ``self`` + plus 1. If the function of ``self`` is constant or linear, then + the default domain will be `[-1,1]`. + + EXAMPLES: + + If the tropical semiring use a max-plus algebra, then the graph + will be of piecewise linear convex function:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = R([4,2,1,3]); p1 + 3*x^3 + 1*x^2 + 2*x + 4 + sage: p1.roots() + [1/3, 1/3, 1/3] + sage: p1.plot() + Graphics object consisting of 1 graphics primitive + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=False) + R = PolynomialRing(T, 'x') + p1 = p1 = R([4,2,1,3]) + sphinx_plot(p1.plot()) + + A different result will be obtained if the tropical semiring employs + a min-plus algebra. Rather, a graph of the piecewise linear concave + function will be obtained:: + + sage: T = TropicalSemiring(QQ, use_min=True) + sage: R. = PolynomialRing(T) + sage: p1 = R([4,2,1,3]) + sage: p1.roots() + [-2, 1, 2] + sage: p1.plot() + Graphics object consisting of 1 graphics primitive + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=True) + R = PolynomialRing(T, 'x') + p1 = R([4,2,1,3]) + sphinx_plot(plot(p1, xmin=-4, xmax=4)) + + TESTS: + + If ``xmin`` or ``xmax`` is given as an input, then the others also + have to be given. Otherwise it will raise an error:: + + sage: plot(p1, 5) + Traceback (most recent call last): + ... + ValueError: expected 2 inputs for xmin and xmax, but got 1 + + Error also occured when ``xmin`` is greater or equal than``xmax``:: + + sage: plot(p1, 5, 3) + Traceback (most recent call last): + ... + ValueError: xmin = 5 should be less than xmax = 3 + """ + from sage.plot.plot import plot + f = self.piecewise_function() + if (xmin is None) and (xmax is None): + roots = sorted(self.roots()) + if (not roots) or (self.parent().base().zero() in roots): + return plot(f, xmin=-1, xmax=1) + else: + return plot(f, xmin=roots[0]-1, xmax=roots[-1]+1) + elif xmin is None or xmax is None: + raise ValueError("expected 2 inputs for xmin and xmax, but got 1") + elif xmin >= xmax: + raise ValueError(f"xmin = {xmin} should be less than xmax = {xmax}") + return plot(f, xmin=xmin, xmax=xmax) + + def _repr_(self): + r""" + Return a string represemtation of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: R([-3,-1,2,-1]) + (-1)*x^3 + 2*x^2 + (-1)*x + (-3) + """ + import re + if not self.dict(): + return str(self.parent().base().zero()) + + def replace_negatives(expr): + modified_expr = re.sub(r'(-\d+/\d+|-\d+)', r'(\1)', expr) + return modified_expr + + s = super()._repr() + v = self.parent().variable_name() + if s[0] == v: + s = "1*" + s + s = s.replace(" - ", " + -") + s = s.replace(" + "+v, " + 1*"+v) + s = s.replace("-"+v, "-1*"+v) + s = replace_negatives(s) + return s + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 'x') + sage: p1 = R([-1,2,None,-3]) + sage: latex(p1) + \left(-3\right) x^{3} + 2 x + \left(-1\right) + """ + s = " " + coeffs = self.list(copy=False) + m = len(coeffs) + name = self.parent().latex_variable_names()[0] + for n in reversed(range(m)): + x = coeffs[n] + x = x._latex_() + if x != self.parent().base().zero()._latex_(): + if n != m-1: + s += " + " + if x.find("-") == 0: + x = "\\left(" + x + "\\right)" + if n > 1: + v = "|%s^{%s}" % (name, n) + elif n == 1: + v = "|%s" % name + else: + v = "" + s += "%s %s" % (x, v) + s = s.replace("|", "") + if s == " ": + return self.parent().base().zero()._latex_() + return s[1:].lstrip().rstrip() + + +class TropicalPolynomialSemiring(UniqueRepresentation, Parent): + r""" + The semiring of univariate tropical polynomials. + + This is the commutative semiring consisting of finite linear + combinations of tropical monomials under (tropical) + addition and multiplication with the identity element + being `+\infty` (or `-\infty` depending on whether the + base tropical semiring is using min-plus or max-plus algebra). + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: f = T(1)*x + sage: g = T(2)*x + sage: f + g + 1*x + sage: f * g + 3*x^2 + sage: f + R.zero() == f + True + sage: f * R.zero() == R.zero() + True + sage: f * R.one() == f + True + """ + @staticmethod + def __classcall_private__(cls, base_semiring, names): + """ + Ensures the names parameter is a tuple. + + EXAMPLES:: + + sage: from sage.rings.semirings.tropical_polynomial import TropicalPolynomialSemiring + sage: T = TropicalSemiring(ZZ) + sage: TPS = TropicalPolynomialSemiring + sage: TPS(T, 'x') == TPS(T, ('x')) + True + """ + if isinstance(names, str): + names = (names,) + return super().__classcall__(cls, base_semiring, tuple(names)) + + def __init__(self, base_semiring, names): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 'x') + sage: TestSuite(R).run() + + TESTS:: + + sage: from sage.rings.semirings.tropical_polynomial import TropicalPolynomialSemiring + sage: TropicalPolynomialSemiring(ZZ, names='x') + Traceback (most recent call last): + ... + ValueError: Integer Ring is not a tropical semiring + """ + 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()) + + Element = TropicalPolynomial + + def _element_constructor_(self, x=None, check=True): + """ + Convert ``x`` into ``self``, possibly non-canonically. + + INPUT: + + - ``x`` -- a list or tuple of coefficients, a polynomial, or a + dictionary + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 'x') + sage: R([1,2,3]) + 3*x^2 + 2*x + 1 + sage: S. = PolynomialRing(QQ) + sage: R(x^2 - x + 1) + 1*x^2 + (-1)*x + 1 + + If ``x`` is a tropical polynomial from different semiring, then it + will converted to constant:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: S. = PolynomialRing(T) + sage: p1 = R(y); p1 + 0*y + sage: p1.parent() + Univariate Tropical Polynomial Semiring in x over Rational Field + sage: p1.degree() + 0 + """ + if isinstance(x, (list, tuple)): + for i, coeff in enumerate(x): + if coeff == 0: + x[i] = self.base().one() + elif isinstance(x, TropicalPolynomial): + if x.parent() is not self: + x = {0: x} + check = False + return self.element_class(self, x, check=check) + + @cached_method + def one(self): + """ + Return the multiplicative identity of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 'x') + sage: R.one() + 0 + """ + return self.element_class(self, [self.base().one()]) + + @cached_method + def zero(self): + """ + Return the additive identity of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 'x') + sage: R.zero() + +infinity + """ + return self.element_class(self, [self.base().zero()]) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(ZZ) + sage: R. = PolynomialRing(T); R + Univariate Tropical Polynomial Semiring in abc over Integer Ring + """ + return (f"Univariate Tropical Polynomial Semiring in {self.variable_name()}" + f" over {self.base_ring().base_ring()}") + + def gen(self, n=0): + """ + Return the indeterminate generator of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: R.gen() + 0*abc + + TESTS:: + + sage: R.gen(2) + Traceback (most recent call last): + ... + IndexError: generator n not defined + """ + if n != 0: + raise IndexError("generator n not defined") + return self.gens()[n] + + @cached_method + def gens(self): + """ + Return a tuple whose entries are the generators for ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: R.gens() + (0*abc,) + """ + R = self.base() + return (self.element_class(self, [R.zero(), R.one()]),) + + def ngens(self): + """ + Return the number of generators of ``self``, which is 1 + since it is a univariate polynomial ring. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 'x') + sage: R.ngens() + 1 + """ + from sage.rings.integer_ring import ZZ + return ZZ.one() + + def random_element(self, degree=(-1, 2), monic=False, *args, **kwds): + r""" + Return a random tropical polynomial of given degrees (bounds). + + OUTPUT: a :class:`TropicalPolynomial` + + .. SEEALSO:: + + :meth:`sage.rings.polynomial.polynomial_ring.PolynomialRing_general.random_element` + + EXAMPLES: + + Tropical polynomial over an integer with each coefficient bounded + between ``x`` and ``y``:: + + sage: T = TropicalSemiring(ZZ) + sage: R = PolynomialRing(T, 'x') + sage: f = R.random_element(8, x=3, y=10) + sage: f.degree() + 8 + sage: f.parent() is R + True + sage: all(a >= T(3) for a in f.coefficients()) + True + sage: all(a < T(10) for a in f.coefficients()) + True + + If a tuple of two integers is provided for the ``degree`` argument, + a polynomial is selected with degrees within that range:: + + sage: all(R.random_element(degree=(1, 5)).degree() in range(1, 6) for _ in range(10^3)) + True + + Note that the zero polynomial (`\pm \infty`) has degree `-1`. + To include it, set the minimum degree to `-1`:: + + sage: while R.random_element(degree=(-1,2), x=-1, y=1) != R.zero(): + ....: pass + + Monic polynomials are chosen among all monic polynomials with degree + between the given ``degree`` argument:: + + sage: all(R.random_element(degree=(-1, 2), monic=True).is_monic() for _ in range(10^3)) + True + """ + from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + R = PolynomialRing(self.base().base_ring(), self.variable_names()) + f = R.random_element(degree=degree, monic=monic, *args, **kwds) + new_dict = f.dict() + if monic: + new_dict[f.degree()] = 0 + return self.element_class(self, new_dict) + + def is_sparse(self): + """ + Return ``True`` to indicate that the objects are sparse polynomials. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R = PolynomialRing(T, 'x') + sage: R.is_sparse() + True + """ + return True + + def interpolation(self, points): + """ + Return a tropical polynomial with its function is a linear + interpolation of point in ``points`` if possible. + + If there is only one point, then it will give a constant polynomial. + Because we are using linear interpolation, each point is actually + a root of the resulted tropical polynomial. + + INPUT: + + - ``points`` -- a list of tuples ``(x, y)`` + + OUTPUT: a :class:`TropicalPolynomial` + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ, use_min=True) + sage: R = PolynomialRing(T, 'x') + sage: points = [(-2,-3),(1,3),(2,4)] + sage: p1 = R.interpolation(points); p1 + 1*x^2 + 2*x + 4 + sage: p1.plot() + Graphics object consisting of 1 graphics primitive + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=True) + R = PolynomialRing(T, 'x') + points = [(-2,-3),(1,3),(2,4)] + p1 = R.interpolation(points) + sphinx_plot(p1.plot()) + + :: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R = PolynomialRing(T,'x') + sage: points = [(0,0),(1,1),(2,4)] + sage: p1 = R.interpolation(points); p1 + (-2)*x^3 + (-1)*x^2 + 0*x + 0 + sage: p1.plot() + Graphics object consisting of 1 graphics primitive + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=False) + R = PolynomialRing(T, 'x') + points = [(0,0),(1,1),(2,4)] + p1 = R.interpolation(points) + sphinx_plot(p1.plot()) + + TESTS: + + Every piecewise linear component of tropical polynomial function + has to have an integer slope:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R = PolynomialRing(T,'x') + sage: points = [(0,0),(2,3)] + sage: R.interpolation(points) + Traceback (most recent call last): + ... + ValueError: the slope is not an integer + + For max-plus algebra, the slope of the componenets has to be + increasing as we move from left to right. Conversely for min-plus + algebra, the slope of the componenets has to be decreasing from + left to right:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R = PolynomialRing(T,'x') + sage: points = [(-2,-3),(1,3),(2,4)] + sage: R.interpolation(points) + Traceback (most recent call last): + ... + ValueError: can not interpolate these points + """ + points = sorted(points, key=lambda point: point[0]) + all_slope = [0] + roots = {} + R = self.base() + if R._use_min: + point_order = range(len(points)-1, 0, -1) + else: + point_order = range(len(points)-1) + for i in point_order: + if R._use_min: + slope = (points[i-1][1]-points[i][1]) / (points[i-1][0]-points[i][0]) + else: + slope = (points[i+1][1]-points[i][1]) / (points[i+1][0]-points[i][0]) + if not slope.is_integer(): + raise ValueError("the slope is not an integer") + if slope < all_slope[-1]: + raise ValueError("can not interpolate these points") + elif slope > all_slope[-1]: + order = slope - all_slope[-1] + all_slope.append(slope) + roots[points[i][0]] = order + + if len(all_slope) == 1: # constant polynomial + return self(points[0][1]) + + result = self.one() + for root, order in roots.items(): + result *= self([root,0])**order + test_value = result(R(points[0][0])) + unit = R(points[0][1] - test_value.lift()) + result *= unit + return result + + @classmethod + def _implementation_names(cls, implementation, base_ring, sparse): + """ + Return the only implementation currently available for this semiring, + which is ``[None]``. + + EXAMPLES:: + + sage: from sage.rings.semirings.tropical_polynomial import TropicalPolynomialSemiring + sage: T = TropicalSemiring(QQ) + sage: TropicalPolynomialSemiring._implementation_names(None, T, True) + [None] + """ + names = [None] + assert isinstance(names, list) + assert implementation in names + return names diff --git a/src/sage/rings/semirings/tropical_variety.py b/src/sage/rings/semirings/tropical_variety.py new file mode 100644 index 00000000000..a8328ee3e48 --- /dev/null +++ b/src/sage/rings/semirings/tropical_variety.py @@ -0,0 +1,1186 @@ +r""" +Tropical Varieties + +A tropical variety is a piecewise-linear geometric object derived from +a classical algebraic variety by using tropical mathematics, where the +tropical semiring replaces the usual arithmetic operations. + +AUTHORS: + +- Verrel Rievaldo Wijaya (2024-06): initial version + +REFERENCES: + +- [Bru2014]_ +- [Fil2017]_ +""" + +# **************************************************************************** +# Copyright (C) 2024 Verrel Rievaldo Wijaya +# +# 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.structure.sage_object import SageObject +from sage.rings.infinity import infinity +from sage.structure.unique_representation import UniqueRepresentation + +class TropicalVariety(UniqueRepresentation, SageObject): + r""" + A tropical variety in `\RR^n`. + + A tropical variety is defined as a corner locus of tropical polynomial + function. This means it consist of all points in `\RR^n` for which + the minimum (maximum) of the function is attained at least twice. + + We represent the tropical variety as a list of lists, where the + inner list consist of three parts. The first one is a parametric + equations for tropical roots. The second one is the condition + for parameters. The third one is the order of the corresponding + component. + + INPUT: + + - ``poly`` -- a :class:`TropicalMPolynomial` + + ALGORITHM: + + We need to determine a corner locus of this tropical polynomial + function, which is all points `(x_1, x_2, \ldots, x_n)` for which + the maximum (minimum) is obtained at least twice. First, we convert + each monomial to its corresponding linear function. Then for each two + monomials of polynomial, we find the points where their values are + equal. Since we attempt to solve the equality of two equations in `n` + variables, the solution set will be described by `n-1` parameters. + + Next, we need to check if the value of previous two monomials at the + points in solution set is really the maximum (minimum) of function. + We do this by solving the inequality of the previous monomial with all + other monomials in the polynomial after substituting the parameter. + This will give us the condition of parameters. Each of this condition + is then combined by union operator. If this final condition is not an + empty set, then it represent one component of tropical root. Then we + calculate the weight of this particular component by the maximum of + gcd of the numbers `|i-k|` and `|j-l|` for all pairs `(i,j)` and + `(k,l)` such that the value of on this component is given by the + corresponding monomials. + + EXAMPLES: + + We construct a tropical variety in `\RR^2`, where it is called a + tropical curve:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = R(1)*x + x*y + R(0); p1 + 0*x*y + 1*x + 0 + sage: tv = p1.tropical_variety(); tv + Tropical curve of 0*x*y + 1*x + 0 + sage: tv.components() + [[(t1, 1), [t1 >= -1], 1], [(-1, t1), [t1 <= 1], 1], [(-t1, t1), [t1 >= 1], 1]] + sage: tv.vertices() + {(-1, 1)} + sage: tv.plot() + Graphics object consisting of 3 graphics primitives + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=False) + R = PolynomialRing(T, ('x,y')) + x, y = R.gen(), R.gen(1) + p1 = R(1)*x + x*y + R(0) + sphinx_plot(p1.tropical_variety().plot()) + + A slightly different result will be obtained if we use min-plus algebra + for the base tropical semiring:: + + sage: T = TropicalSemiring(QQ, use_min=True) + sage: R. = PolynomialRing(T) + sage: p1 = R(1)*x + x*y + R(0) + sage: tv = p1.tropical_variety(); tv + Tropical curve of 0*x*y + 1*x + 0 + sage: tv.components() + [[(t1, 1), [t1 <= -1], 1], [(-1, t1), [t1 >= 1], 1], [(-t1, t1), [t1 <= 1], 1]] + sage: tv.plot() + Graphics object consisting of 3 graphics primitives + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=True) + R = PolynomialRing(T, ('x,y')) + x, y = R.gen(), R.gen(1) + p1 = R(1)*x + x*y + R(0) + sphinx_plot(p1.tropical_variety().plot()) + + Tropical variety can consist of multiple components with varying orders:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = R(7) + T(4)*x + y + R(4)*x*y + R(3)*y^2 + R(-3)*x^2 + sage: tv = p1.tropical_variety(); tv + Tropical curve of (-3)*x^2 + 4*x*y + 3*y^2 + 4*x + 0*y + 7 + sage: tv.components() + [[(3, t1), [t1 <= 0], 1], + [(-t1 + 3, t1), [0 <= t1, t1 <= 2], 1], + [(t1, 2), [t1 <= 1], 2], + [(t1, 0), [3 <= t1, t1 <= 7], 1], + [(7, t1), [t1 <= 0], 1], + [(t1 - 1, t1), [2 <= t1], 1], + [(t1 + 7, t1), [0 <= t1], 1]] + sage: tv.plot() + Graphics object consisting of 8 graphics primitives + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ, use_min=False) + R = PolynomialRing(T, ('x,y')) + x, y = R.gen(), R.gen(1) + p1 = R(7) + T(4)*x + y + R(4)*x*y + R(3)*y**2 + R(-3)*x**2 + sphinx_plot(p1.tropical_variety().plot()) + + If the tropical polynomial have `n>2` variables, then the result will be + a tropical hypersurface embedded in a real space `\RR^n`:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x*y + R(-1/2)*x*z + R(4)*z^2 + a*x + sage: tv = p1.tropical_variety(); tv + Tropical hypersurface of 0*a*x + 0*x*y + (-1/2)*x*z + 4*z^2 + sage: tv.components() + [[(t1, t2, t3 - 1/2, t3), [t2 - 9/2 <= t3, t3 <= t1 + 1/2, t2 - 5 <= t1], 1], + [(t1, 2*t2 - t3 + 4, t3, t2), [t3 + 1/2 <= t2, t3 <= t1], 1], + [(t1, t2, t1, t3), [max(t1 + 1/2, 1/2*t1 + 1/2*t2 - 2) <= t3], 1], + [(t1, t2 + 9/2, t3, t2), [t2 <= min(t3 + 1/2, t1 + 1/2)], 1], + [(t1 - 1/2, t2, t3, t1), [t2 - 9/2 <= t1, t1 <= t3 + 1/2, t2 - 5 <= t3], 1], + [(2*t1 - t2 + 4, t2, t3, t1), [t1 <= min(1/2*t2 + 1/2*t3 - 2, t2 - 9/2)], 1]] + """ + def __init__(self, poly): + r""" + Initialize ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: tv = (x+y).tropical_variety() + sage: TestSuite(tv).run() + + TESTS:: + + sage: from sage.rings.semirings.tropical_variety import TropicalVariety + sage: R. = QQ[] + sage: p1 = x + y + sage: TropicalVariety(p1) + Traceback (most recent call last): + ... + ValueError: x + y is not a multivariate tropical polynomial + """ + 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 + + if not isinstance(poly, TropicalMPolynomial): + raise ValueError(f"{poly} is not a multivariate tropical polynomial") + + self._poly = poly + self._hypersurface = [] + tropical_roots = [] + variables = [] + for name in poly.parent().variable_names(): + variables.append(SR.var(name)) + + # Convert each term to its linear function + linear_eq = {} + pd = poly.dict() + for key in pd: + eq = sum(variables[i] * e for i, e in enumerate(key)) + eq += pd[key].lift() + linear_eq[key] = eq + temp_keys = [] + temp_order = [] + + # Checking for all possible combinations of two terms + for keys in combinations(pd, 2): + sol = solve(linear_eq[keys[0]] == linear_eq[keys[1]], variables) + + # Parametric solution of the chosen two terms + final_sol = [] + for s in sol[0]: + final_sol.append(s.right()) + xy_interval = [] + xy_interval.append(tuple(final_sol)) + + # Comparing with other terms + min_max = linear_eq[keys[0]] + for i, v in enumerate(variables): + min_max = min_max.subs(**{str(v): final_sol[i]}) + all_sol_compare = [] + no_solution = False + for compare in pd: + if compare not in keys: + temp_compare = linear_eq[compare] + for i, v in enumerate(variables): + temp_compare = temp_compare.subs(**{str(v): final_sol[i]}) + if min_max == temp_compare: + sol_compare = [[]] + elif poly.parent().base()._use_min: + sol_compare = solve(min_max < temp_compare, variables) + else: + sol_compare = solve(min_max > temp_compare, variables) + if sol_compare: + if isinstance(sol_compare[0], list): + if sol_compare[0]: + all_sol_compare.append(sol_compare[0][0]) + else: # solution is unbounded on one side + all_sol_compare.append(sol_compare[0]) + else: + no_solution = True + break + + # Solve the condition for parameter + if not no_solution: + parameter = set() + for sol in all_sol_compare: + parameter = parameter.union(set(sol.variables())) + parameter_solution = solve(all_sol_compare, list(parameter)) + if parameter_solution: + xy_interval.append(parameter_solution[0]) + tropical_roots.append(xy_interval) + # Calculate the order + index_diff = [] + for i in range(len(keys[0])): + index_diff.append(abs(keys[0][i] - keys[1][i])) + order = gcd(index_diff) + temp_order.append(order) + temp_keys.append(keys) + + # Changing all the operator symbol to be <= or >= + self._keys = [] + components = [] + dim_param = 0 + if tropical_roots: + dim_param = len(tropical_roots[0][0]) - 1 + vars = [SR.var('t{}'.format(i)) for i in range(1, dim_param+1)] + for arg in tropical_roots: + subs_dict = {} + index_vars = 0 + new_eq = [] + for eq in arg[0]: + var_eq = eq.variables() + for var in var_eq: + if var not in subs_dict: + subs_dict[var] = vars[index_vars] + index_vars += 1 + new_eq.append(eq.subs(subs_dict)) + new_eq = tuple(new_eq) + arg.remove(arg[0]) + arg.insert(0, new_eq) + if not arg[1] or not isinstance(arg[1], list): + arg[1] = [] + for var in vars: + expr1 = -infinity < var + expr2 = var < infinity + arg[1].append(expr1) + arg[1].append(expr2) + else: + params = arg[1] + arg.remove(params) + new_param = [] + for param in params: + lhs = param.lhs().subs(subs_dict) + rhs = param.rhs().subs(subs_dict) + if param.operator() == operator.gt: + expr = lhs >= rhs + else: + expr = lhs <= rhs + new_param.append(expr) + arg.insert(1, new_param) + components.append(arg) + + # Determine the order of each component + self._vars = vars + final_order = [] + for i, component in enumerate(components): + if component not in self._hypersurface: + self._hypersurface.append(component) + final_order.append(temp_order[i]) + self._keys.append(temp_keys[i]) + else: + index = self._hypersurface.index(component) + if temp_order[i] > final_order[index]: + final_order[index] = temp_order[i] + self._keys[index] = temp_keys[i] + for i in range(len(self._hypersurface)): + self._hypersurface[i].append(final_order[i]) + + def dimension(self): + """ + Return the dimension of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x*y + R(-1)*x*z + sage: p1.tropical_variety().dimension() + 4 + """ + return self._poly.parent().ngens() + + def number_of_components(self): + """ + Return the number of components that make up ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x*y*a + x*z + y^2 + a*x + y + z + sage: p1.tropical_variety().number_of_components() + 13 + """ + from sage.rings.integer_ring import ZZ + return ZZ(len(self._hypersurface)) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: (w).tropical_variety() + Tropical hypersurface of 0*w + """ + return f"Tropical hypersurface of {self._poly}" + + def _latex_(self): + r""" + Return a latex representation of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: tv = (R(1)*w^2 + x*y*z + R(-1)).tropical_variety() + sage: latex(tv) + TV\left(0 x y z + 1 w^{2} + \left(-1\right)\right) + """ + return f"TV\\left({self._poly._latex_()}\\right)" + + def components(self): + """ + Return all components of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: tv = (a+x+y+z).tropical_variety() + sage: tv.components() + [[(t1, t1, t2, t3), [t1 <= min(t3, t2)], 1], + [(t1, t2, t1, t3), [t1 <= t3, t1 <= t2], 1], + [(t1, t2, t3, t1), [t1 <= min(t3, t2)], 1], + [(t1, t2, t2, t3), [t2 <= t3, t2 <= t1], 1], + [(t1, t2, t3, t2), [t2 <= min(t3, t1)], 1], + [(t1, t2, t3, t3), [t3 <= min(t1, t2)], 1]] + """ + return self._hypersurface + + def _components_intersection(self): + r""" + Return the intersection of three or more components of ``self``. + + For a tropical variety in `\RR^n`, the intersection is characterized + by a linear equation in `\RR^{n-1}`. Specifically, this becomes a + vertex for tropical curve and an edges for tropical surface. + + OUTPUT: + + A dictionary where the keys represent component indices and the + values are lists of tuples. Each tuple contains a parametric + equation of points and the corresponding parameter's condition. + + EXAMPLES: + + In two dimension, it will provide vertices that are incident with + each component:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = R(2)*x^2 + x*y + R(2)*y^2 + x + R(-1)*y + R(3) + sage: tv = p1.tropical_variety() + sage: tv._components_intersection() + {0: [((-2, 0), {})], + 1: [((-2, 0), {})], + 2: [((-1, -3), {})], + 3: [((-2, 0), {}), ((-1, 0), {})], + 4: [((-1, -3), {}), ((-1, 0), {})], + 5: [((-1, -3), {})], + 6: [((-1, 0), {}), ((3, 4), {})], + 7: [((3, 4), {})], + 8: [((3, 4), {})]} + + In three dimensions, it will provide all parametric equations of + lines that lie within each component:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x + y + z + x^2 + sage: tv = p1.tropical_variety() + sage: tv._components_intersection() + {0: [((t2, t2, t2), {0 <= t2}), ((0, 0, t2), {0 <= t2})], + 1: [((0, t2, 0), {0 <= t2}), ((t2, t2, t2), {0 <= t2})], + 2: [((0, t1, 0), {0 <= t1}), ((0, 0, t2), {0 <= t2})], + 3: [((t1, t1, t1), {0 <= t1}), ((t1, 2*t1, 2*t1), {t1 <= 0})], + 4: [((1/2*t2, t2, t2), {t2 <= 0}), ((0, 0, t2), {0 <= t2})], + 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.symbolic.expression import Expression + from sage.sets.set import Set + + def update_result(result): + sol_param = solve(new_expr, vars) + sol_param_sim = set() + for sol in sol_param: + if sol == []: + for v in vars: + if v != var: + sol_param_sim.add(v < infinity) + elif isinstance(sol, list): + for eqn in sol: + if eqn.operator() == operator.eq: + if not eqn.rhs().is_numeric(): + eqn_var = eqn.rhs().variables() + param_var = [v for v in eqn_var if v in vars] + if not param_var: + v = eqn.lhs() + if v != var: + sol_param_sim.add(v < infinity) + elif eqn.operator() == operator.lt: + sol_param_sim.add(eqn.lhs() <= eqn.rhs()) + elif eqn.operator() == operator.gt: + sol_param_sim.add(eqn.lhs() >= eqn.rhs()) + else: + sol_param_sim.add(sol) + # Checking there are no conditions with the same variables + # that use the <= and >= operators simultaneously + unique_sol_param = set() + temp = [s for s in sol_param_sim] + op_temp = {i: set(temp[i].operands()) for i in range(len(temp))} + for s_value in op_temp.values(): + match_keys = [k for k, v in op_temp.items() if v == s_value] + if len(match_keys) == 1: + for i in match_keys: + unique_sol_param.add(temp[i]) + + if (unique_sol_param) or (self.dimension() == 2): + if not unique_sol_param: + unique_sol_param = Set() + if index not in result: + result[index] = [(tuple(points), unique_sol_param)] + else: + result[index].append((tuple(points), unique_sol_param)) + + result = {} + vars = self._vars + for index, comp in enumerate(self._hypersurface): + for expr in comp[1]: + left = expr.lhs() + right = expr.rhs() + # If the lhs contains a min or max operator + if (left.operator() == max_symbolic) or (left.operator() == min_symbolic): + for operand in expr.lhs().operands(): + points = list(comp[0]) + new_expr = [e.subs(**{str(right): operand}) for e in comp[1]] + for i, p in enumerate(points): + new_eq = p.subs(**{str(right): operand}) + points[i] = new_eq + update_result(result) + # If the rhs contains a min or max operator + elif (right.operator() == max_symbolic) or (right.operator() == min_symbolic): + for operand in expr.rhs().operands(): + points = list(comp[0]) + new_expr = [e.subs(**{str(left): operand}) for e in comp[1]] + for i, p in enumerate(points): + new_eq = p.subs(**{str(left): operand}) + points[i] = new_eq + update_result(result) + else: + var = expr.variables()[0] + points = list(comp[0]) + subs_expr = solve(left == right, var)[0].rhs() + new_expr = [e.subs(**{str(var): subs_expr}) for e in comp[1]] + for i, p in enumerate(points): + new_eq = p.subs(**{str(var): subs_expr}) + points[i] = new_eq + update_result(result) + return result + + +class TropicalSurface(TropicalVariety): + r""" + A tropical surface in `\RR^3`. + + The tropical surface consists of planar regions and facets, which we + can call cells. These cells are connected in such a way that they form + a piecewise linear structure embedded in three-dimensional space. These + cells meet along edges, where the balancing condition is satisfied. + This balancing condition ensures that the sum of the outgoing normal + vectors at each edge is zero, reflecting the equilibrium. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = x + y + z + R(0) + sage: tv = p1.tropical_variety(); tv + Tropical surface of 0*x + 0*y + 0*z + 0 + sage: tv.components() + [[(t1, t1, t2), [t2 <= t1, 0 <= t1], 1], + [(t1, t2, t1), [max(0, t2) <= t1], 1], + [(0, t1, t2), [t2 <= 0, t1 <= 0], 1], + [(t1, t2, t2), [max(0, t1) <= t2], 1], + [(t1, 0, t2), [t2 <= 0, t1 <= 0], 1], + [(t1, t2, 0), [t1 <= 0, t2 <= 0], 1]] + """ + def _axes(self): + r""" + Set the default axes for ``self``. + + This default axes is used for the 3d plot. The axes is centered + around where the intersection of the components occured so it + gives a nice visual representation for the interactions between + different components of the surface. Additionally, it enhances + the visibility and interpretation of how the components align + and interact in three-dimensional space. + + OUTPUT: + + A list of three lists, where the first inner list represent value + of x-axis, the second inner list represent value of y-axis, and + the third inner list represent value of z-axis. If there are + either no components or only one component, the axis will be set + to `[[-1, 1], [-1, 1], [-1, 1]]`. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x + sage: p1.tropical_variety()._axes() + [[-1, 1], [-1, 1], [-1, 1]] + sage: p2 = x + y + z + x^2 + R(1) + sage: p2.tropical_variety()._axes() + [[-1, 2], [-1, 2], [-1, 2]] + """ + from sage.symbolic.relation import solve + from sage.arith.srange import srange + + if not self._hypersurface: + return [[-1, 1], [-1, 1], [-1, 1]] + elif len(self._hypersurface) == 1: + bound = 1 + for eqn in self._hypersurface[0][0]: + for op in eqn.operands(): + if op.is_numeric(): + if op > bound: + bound = op + return [[-bound, bound]] * 3 + + u_set = set() + v_set = set() + for comp in self._hypersurface: + list_expr = [] + temp_u = set() + temp_v = set() + for expr in comp[1]: + if expr.lhs().is_numeric(): + if bool(expr.rhs() == self._vars[0]): + temp_u.add(expr.lhs()) + else: + temp_v.add(expr.lhs()) + elif expr.rhs().is_numeric(): + if bool(expr.lhs() == self._vars[0]): + temp_u.add(expr.rhs()) + else: + temp_v.add(expr.rhs()) + else: + list_expr.append(expr) + if not temp_u: + temp_u.add(0) + if not temp_v: + temp_v.add(0) + for expr in list_expr: + for u in temp_u: + sol = solve(expr.subs(**{str(self._vars[0]): u}), self._vars[1]) + if not sol: + temp_v.add(0) + elif not sol[0]: + temp_v.add(0) + else: + temp_v.add(sol[0][0].rhs()) + for v in temp_v: + sol = solve(expr.subs(**{str(self._vars[1]): v}), self._vars[0]) + if not sol: + temp_u.add(0) + elif not sol[0]: + temp_u.add(0) + else: + temp_u.add(sol[0][0].rhs()) + u_set = u_set.union(temp_u) + v_set = v_set.union(temp_v) + axes = [[min(u_set)-1, max(u_set)+1], [min(v_set)-1, max(v_set)+1]] + + # Finding the z-axis + step = 10 + du = (axes[0][1]-axes[0][0]) / step + dv = (axes[1][1]-axes[1][0]) / step + u_range = srange(axes[0][0], axes[0][1]+du, du) + v_range = srange(axes[1][0], axes[1][1]+dv, dv) + zmin, zmax = None, None + for comp in self._hypersurface: + for u in u_range: + for v in v_range: + checkpoint = True + for exp in comp[1]: + final_exp = exp.subs(**{str(self._vars[0]): u, str(self._vars[1]): v}) + if not final_exp: + checkpoint = False + break + if checkpoint: + z = comp[0][2].subs(**{str(self._vars[0]): u, str(self._vars[1]): v}) + if (zmin is None) and (zmax is None): + zmin = z + zmax = z + else: + if z < zmin: + zmin = z + if z > zmax: + zmax = z + axes.append([zmin, zmax]) + return axes + + def _polygon_vertices(self): + r""" + Return the vertices of the polygon for each components of ``self`` + to be used for plotting. + + OUTPUT: + + A dictionary where the keys represent component indices and the + values are a set of points in three dimensional space. + + EXAMPLES: + + A tropical surface with only one component:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x + z + sage: tv1 = p1.tropical_variety() + sage: tv1._polygon_vertices() + {0: {(-1, -1, -1), (-1, 1, -1), (1, -1, 1), (1, 1, 1)}} + + A tropical surface with multiple components:: + + sage: p2 = x^2 + x + y + z + R(1) + sage: tv2 = p2.tropical_variety() + sage: tv2._polygon_vertices() + {0: {(0, 0, 0), (0, 0, 2), (1, 1, 1), (2, 2, 2)}, + 1: {(0, 0, 0), (0, 2, 0), (1, 1, 1), (2, 2, 2)}, + 2: {(0, 0, 0), (0, 0, 2), (0, 2, 0), (0, 2, 2)}, + 3: {(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2)}, + 4: {(-1/2, -1, -1), (0, 0, 0), (1, 1, 1), (2, -1, -1), (2, 1, 1)}, + 5: {(-1/2, -1, -1), (-1/2, -1, 2), (0, 0, 0), (0, 0, 2)}, + 6: {(1, 1, 1), (1, 1, 2), (2, 1, 1), (2, 1, 2)}, + 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.sets.real_set import RealSet + from sage.symbolic.relation import solve + from sage.rings.rational_field import QQ + + poly_verts = {i: set() for i in range(self.number_of_components())} + axes = self._axes() + comps = self.components() + vars = self._vars + comps_int = self._components_intersection() + + # Finding the inside vertices + for index, lines in comps_int.items(): + for line in lines: + v = list(line[1])[0].variables()[0] + for param in line[1]: + left = param.lhs() + right = param.rhs() + if left.is_numeric(): + vertex = [QQ(e.subs(**{str(v): left})) for e in line[0]] + poly_verts[index].add(tuple(vertex)) + elif right.is_numeric(): + vertex = [QQ(e.subs(**{str(v): right})) for e in line[0]] + poly_verts[index].add(tuple(vertex)) + + def find_edge_vertices(i): + j = (i+1) % 2 + if i == 0: # interval for t1 + interval = interval1 + else: # interval for t2 + interval = interval2 + for p in [interval.inf(), interval.sup()]: + new_param = [e.subs(**{str(vars[i]): p}) for e in comps[index][1]] + sol = solve(new_param, vars[j]) + if sol: + interval_param = RealSet() + for s in sol: + if s != []: + # Handle cases where 's' is not a list (s = r1 < +Infinity), + # or if 's' is a list, ensure that its elements define a real + # interval (catch invalid cases like s = [t1 == r100]). + try: + interval_param += RealSet(s[0]) + except (IndexError, ValueError): + interval_param += RealSet(-infinity, infinity) + else: + interval_param += RealSet(-infinity, infinity) + interval_param = interval_param.intersection(interval2) + if is_doublevar: + int1 = RealSet() + for s1 in sol1: + subs1 = solve(s1[0].subs(**{str(vars[i]): p}), vars[j]) + try: + int1 += RealSet(subs1[0]) + except TypeError: + int1 += RealSet(subs1[0][0]) + int2 = RealSet() + for s2 in sol2: + subs2 = solve(s2[0].subs(**{str(vars[i]): p}), vars[j]) + try: + int2 += RealSet(subs2[0]) + except TypeError: + int2 += RealSet(subs2[0][0]) + final_int = int1.intersection(int2) + interval_param = interval_param.intersection(final_int) + if interval_param: + vertex1 = [QQ(e.subs(**{str(vars[i]): p, str(vars[j]): interval_param.inf()})) for e in comps[index][0]] + vertex2 = [QQ(e.subs(**{str(vars[i]): p, str(vars[j]): interval_param.sup()})) for e in comps[index][0]] + poly_verts[index].add(tuple(vertex1)) + poly_verts[index].add(tuple(vertex2)) + + # Find the interval of parameter for outer vertex + for index in range(len(comps)): + interval1 = RealSet(-infinity,infinity) # represent t1 + interval2 = RealSet(-infinity,infinity) # represent t2 + is_doublevar = False + for i, point in enumerate(comps[index][0]): + pv = point.variables() + if len(pv) == 1: + temp1 = RealSet(solve(point >= axes[i][0], pv[0])[0][0]) + temp2 = RealSet(solve(point <= axes[i][1], pv[0])[0][0]) + temp = temp1.intersection(temp2) + if pv[0] == vars[0]: + interval1 = interval1.intersection(temp) + else: + interval2 = interval2.intersection(temp) + elif len(pv) == 2: + sol1 = solve(point >= axes[i][0], pv) + sol2 = solve(point <= axes[i][1], pv) + is_doublevar = True + # Finding the edge vertices (those that touch the axes) + find_edge_vertices(0) # t1 fixed + find_edge_vertices(1) # t2 fixed + return poly_verts + + def plot(self, color='random'): + """ + Return the plot of ``self`` by constructing a polyhedron from + vertices in ``self.polygon_vertices()``. + + INPUT: + + - ``color`` -- string or tuple that represent a color (default: + ``random``); ``random`` means each polygon will be assigned + a different color. If instead a specific ``color`` is provided, + then all polygon will be given the same color. + + OUTPUT: Graphics3d Object + + EXAMPLES: + + A tropical surface that consist of only one cell:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x + z + sage: tv = p1.tropical_variety() + sage: tv.plot() + Graphics3d Object + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ) + R = PolynomialRing(T, ('x,y,z')) + x, y, z = R.gen(), R.gen(1), R.gen(2) + p1 = x + z + sphinx_plot(p1.tropical_variety().plot()) + + A tropical surface with multiple cell that exhibit complex and + intriguing geometric structures:: + + sage: p2 = x^2 + x + y + z + R(1) + sage: tv = p2.tropical_variety() + sage: tv.plot() + Graphics3d Object + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ) + R = PolynomialRing(T, ('x,y,z')) + x, y, z = R.gen(), R.gen(1), R.gen(2) + p2 = x**2 + x + y + z + R(1) + sphinx_plot(p2.tropical_variety().plot()) + """ + from random import random + from sage.plot.graphics import Graphics + from sage.geometry.polyhedron.constructor import Polyhedron + + if color == 'random': + colors = [] + for _ in range(self.number_of_components()): + color = (random(), random(), random()) + colors.append(color) + elif isinstance(color, str): + colors = [color] * self.number_of_components() + else: + colors = color + + combined_plot = Graphics() + for i, vertex in self._polygon_vertices().items(): + points = list(vertex) + plot = Polyhedron(vertices=points).plot(color=colors[i]) + combined_plot += plot + return combined_plot + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: (x^4+z^2).tropical_variety() + Tropical surface of 0*x^4 + 0*z^2 + """ + return f"Tropical surface of {self._poly}" + + +class TropicalCurve(TropicalVariety): + r""" + A tropical curve in `\RR^2`. + + The tropical curve consists of line segments and half-lines, which we + call edges. These edges are connected in such a way that they form a + piecewise linear graph embedded in the plane. These edges meet at + a vertices, where the balancing condition is satisfied. This balancing + condition ensures that the sum of the outgoing slopes at each vertex + is zero, reflecting the equilibrium. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ, use_min=False) + sage: R. = PolynomialRing(T) + sage: p1 = x + y + R(0) + sage: tv = p1.tropical_variety(); tv + Tropical curve of 0*x + 0*y + 0 + sage: tv.components() + [[(t1, t1), [t1 >= 0], 1], [(0, t1), [t1 <= 0], 1], [(t1, 0), [t1 <= 0], 1]] + """ + def _axes(self): + """ + Set the default axes for ``self``. + + This default axes is used for plot of tropical curve and also the + 3d plot of tropical polynomial function. The axes is chosen by first + find all vertices of this tropical curve. Then we choose the minimum + and maximum of all x-component in this vertices to be the x-axis. + The same apply to the y-axis. + + OUTPUT: + + A list of two lists, where the first inner list represent value of + x-axis and the second inner list represent value of y-axis. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x^2 + sage: p1.tropical_variety()._axes() + [[-1, 1], [-1, 1]] + sage: p2 = R(12)*x*y + R(-2)*y^2 + R(16)*y + R(25) + sage: p2.tropical_variety()._axes() + [[-3/2, 1/2], [25/2, 29/2]] + """ + if self.number_of_components() == 0: + return [[-1, 1], [-1, 1]] + if self.number_of_components() <= 2: + bound = 1 + for comps in self._hypersurface: + eqns = comps[0] + temp_operands = [] + for eq in eqns: + if not eq.operator(): + temp_operands.append(eq) + else: + temp_operands += eq.operands() + for op in temp_operands: + if op.is_numeric(): + if abs(op) > bound: + bound = abs(op) + return [[-bound, bound]] * 2 + + verts = self.vertices() + xmin = xmax = list(verts)[0][0] + for vertex in verts: + if vertex[0] < xmin: + xmin = vertex[0] + elif vertex[0] > xmax: + xmax = vertex[0] + ymin = ymax = list(verts)[0][1] + for vertex in verts: + if vertex[1] < ymin: + ymin = vertex[1] + elif vertex[1] > ymax: + ymax = vertex[1] + return [[xmin-1, xmax+1], [ymin-1, ymax+1]] + + def vertices(self): + r""" + Return all vertices of ``self``, which is the point where three or + more edges intersect. + + OUTPUT: A set of `(x,y)` points + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = x + y + sage: p1.tropical_variety().vertices() + set() + sage: p2 = R(-2)*x^2 + R(-1)*x + R(1/2)*y + R(1/6) + sage: p2.tropical_variety().vertices() + {(1, -1/2), (7/6, -1/3)} + """ + if len(self._hypersurface) < 3: + return set() + + vertices = set() + for i, component in enumerate(self._hypersurface): + parametric_function = component[0] + var = component[1][0].variables()[0] + interval = self._parameter_intervals()[i] + lower = interval[0].lower() + upper = interval[0].upper() + if lower != -infinity: + x = parametric_function[0].subs(**{str(var): lower}) + y = parametric_function[1].subs(**{str(var): lower}) + vertices.add((x,y)) + if upper != infinity: + x = parametric_function[0].subs(**{str(var): upper}) + y = parametric_function[1].subs(**{str(var): upper}) + vertices.add((x,y)) + return vertices + + def _parameter_intervals(self): + r""" + Return the intervals of each component's parameter of ``self``. + + OUTPUT: A list of ``RealSet`` + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: p1 = y + y^2 + sage: p1.tropical_variety()._parameter_intervals() + [(-oo, +oo)] + sage: p2 = x^2 + R(-1)*x*y + R(-1)*x + R(1/3) + sage: p2.tropical_variety()._parameter_intervals() + [(-oo, 0], [0, +oo), [-1, 4/3], (-oo, 0], [0, +oo)] + """ + from sage.sets.real_set import RealSet + + intervals = [] + R = self._poly.parent().base().base_ring() + for component in self._hypersurface: + if len(component[1]) == 1: + interval = RealSet(component[1][0]) + else: + lower = component[1][0].left() + upper = component[1][1].right() + if lower == -infinity: + interval = RealSet(-infinity, infinity) + else: + interval = RealSet([R(lower), R(upper)]) + intervals.append(interval) + return intervals + + def plot(self): + """ + Return the plot of ``self``. + + Generates a visual representation of the tropical curve in cartesian + coordinates. The plot shows piecewise-linear segments representing + each components. The axes are centered around the vertices. + + OUTPUT: + + A Graphics object. The weight of the component will be written if it + is greater or equal than 2. The weight is written near the vertex. + + EXAMPLES: + + A polynomial with only two terms will give one straight line:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: (y+R(1)).tropical_variety().components() + [[(t1, 1), [-Infinity < t1, t1 < +Infinity], 1]] + sage: (y+R(1)).tropical_variety().plot() + Graphics object consisting of 1 graphics primitive + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ) + R = PolynomialRing(T, ('x,y')) + x, y = R.gen(), R.gen(1) + sphinx_plot((y+R(1)).tropical_variety().plot()) + + An intriguing and fascinating tropical curve can be obtained with + a more complex tropical polynomial:: + + sage: p1 = R(1) + R(2)*x + R(3)*y + R(6)*x*y + R(10)*x*y^2 + sage: p1.tropical_variety().components() + [[(-1, t1), [-2 <= t1], 1], + [(t1, -2), [-1 <= t1], 1], + [(t1 + 1, t1), [-4 <= t1, t1 <= -2], 1], + [(t1, -4), [t1 <= -3], 2], + [(-t1 - 7, t1), [t1 <= -4], 1]] + sage: p1.tropical_variety().plot() + Graphics object consisting of 6 graphics primitives + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ) + R = PolynomialRing(T, ('x,y')) + x, y = R.gen(), R.gen(1) + p1 = R(1) + R(2)*x + R(3)*y + R(6)*x*y + R(10)*x*y**2 + sphinx_plot(p1.tropical_variety().plot()) + + Another tropical polynomial with numerous components, resulting + in a more intricate structure:: + + sage: p2 = (x^6 + R(4)*x^4*y^2 + R(2)*x^3*y^3 + R(3)*x^2*y^4 + x*y^5 + ....: + R(7)*x^2 + R(5)*x*y + R(3)*y^2 + R(2)*x + y + R(10)) + sage: p2.tropical_variety().plot() + Graphics object consisting of 11 graphics primitives + + .. PLOT:: + :width: 300 px + + T = TropicalSemiring(QQ) + R = PolynomialRing(T, ('x,y')) + x, y = R.gen(), R.gen(1) + p2 = x**6 + R(4)*x**4*y**2 + R(2)*x**3*y**3 + R(3)*x**2*y**4 + \ + x*y**5 + R(7)*x**2 + R(5)*x*y + R(3)*y**2 + R(2)*x + y + R(10) + sphinx_plot(p2.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 + + if not self._hypersurface: + return plot(lambda x: float('nan'), {-1, 1}) + + combined_plot = Graphics() + large_int = 100 + intervals = self._parameter_intervals() + for i, component in enumerate(self._hypersurface): + var = component[1][0].variables()[0] + parametric_function = component[0] + order = component[2] + interval = intervals[i] + if interval[0].lower() == -infinity: + lower = interval[0].upper() - large_int + upper = interval[0].upper() + midpoint = upper - 0.5 + elif interval[0].upper() == infinity: + lower = interval[0].lower() + upper = interval[0].lower() + large_int + midpoint = lower + 0.5 + else: + lower = interval[0].lower() + upper = interval[0].upper() + midpoint = (lower+upper) / 2 + + if (lower == infinity) and (upper == infinity): + midpoint = 0 + plot = parametric_plot(parametric_function, (var, -large_int, + large_int), color='red') + else: + plot = parametric_plot(parametric_function, (var, lower, upper), + color='red') + + # Add the order if it is greater than or equal to 2 + if component[2] > 1: + point = [] + for eq in component[0]: + value = eq.subs(**{str(var): midpoint}) + point.append(value) + text_order = text(str(order), (point[0], point[1]), + fontsize=16, color='black') + combined_plot += plot + text_order + else: + combined_plot += plot + + # Set default axes + axes = self._axes() + xmin, xmax = axes[0][0], axes[0][1] + ymin, ymax = axes[1][0], axes[1][1] + combined_plot.set_axes_range(xmin=xmin, xmax=xmax, + ymin=ymin, ymax=ymax) + return combined_plot + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: T = TropicalSemiring(QQ) + sage: R. = PolynomialRing(T) + sage: (x^2+R(0)).tropical_variety() + Tropical curve of 0*x^2 + 0 + """ + return f"Tropical curve of {self._poly}" diff --git a/src/sage/sat/converters/anf2cnf.py b/src/sage/sat/converters/anf2cnf.py index e6dd330feff..eafc8b0a440 100644 --- a/src/sage/sat/converters/anf2cnf.py +++ b/src/sage/sat/converters/anf2cnf.py @@ -8,5 +8,6 @@ - Martin Albrecht (2012): first version """ + class ANF2CNFConverter(): pass diff --git a/src/sage/sat/solvers/dimacs.py b/src/sage/sat/solvers/dimacs.py index 424442930de..92d011f4e12 100644 --- a/src/sage/sat/solvers/dimacs.py +++ b/src/sage/sat/solvers/dimacs.py @@ -542,6 +542,7 @@ def __call__(self, assumptions=None): else: raise ValueError("When parsing the output(={}), no line starts with letter v or s".format(self._output)) + class RSat(DIMACS): """ An instance of the RSat solver. @@ -642,6 +643,7 @@ class Glucose(DIMACS): """ command = "glucose -verb=0 -model {input}" + class GlucoseSyrup(DIMACS): """ An instance of the Glucose-syrup parallel solver. @@ -705,6 +707,7 @@ class GlucoseSyrup(DIMACS): """ command = "glucose-syrup -model -verb=0 {input}" + class Kissat(DIMACS): """ An instance of the Kissat SAT solver. diff --git a/src/sage/sat/solvers/sat_lp.py b/src/sage/sat/solvers/sat_lp.py index 76446e1f0f8..5a027f6ae9b 100644 --- a/src/sage/sat/solvers/sat_lp.py +++ b/src/sage/sat/solvers/sat_lp.py @@ -10,6 +10,7 @@ from .satsolver import SatSolver from sage.numerical.mip import MixedIntegerLinearProgram, MIPSolverException + class SatLP(SatSolver): def __init__(self, solver=None, verbose=0, *, integrality_tolerance=1e-3): r""" diff --git a/src/sage/schemes/elliptic_curves/BSD.py b/src/sage/schemes/elliptic_curves/BSD.py index 73f1f57d41c..a1520670e15 100755 --- a/src/sage/schemes/elliptic_curves/BSD.py +++ b/src/sage/schemes/elliptic_curves/BSD.py @@ -148,6 +148,7 @@ def mwrank_two_descent_work(E, two_tor_rk): sha2_upper_bd = MWRC.selmer_rank() - two_tor_rk - rank_lower_bd return rank_lower_bd, rank_upper_bd, sha2_lower_bd, sha2_upper_bd, gens + def pari_two_descent_work(E): r""" Prepare the output from pari by two-isogeny. diff --git a/src/sage/schemes/elliptic_curves/cm.py b/src/sage/schemes/elliptic_curves/cm.py index faf4f75f2ce..6760719e789 100755 --- a/src/sage/schemes/elliptic_curves/cm.py +++ b/src/sage/schemes/elliptic_curves/cm.py @@ -287,6 +287,7 @@ def is_HCP(f, check_monic_irreducible=True): return zero return D if f == hilbert_class_polynomial(D) else zero + def OrderClassNumber(D0,h0,f): r""" Return the class number h(f**2 * D0), given h(D0)=h0. @@ -652,6 +653,7 @@ class number `h`, and the number of fundamental negative discriminants with except KeyError: raise NotImplementedError("largest fundamental discriminant not available for class number %s" % h) + def largest_disc_with_class_number(h): r""" Return largest absolute value of any negative discriminant with @@ -723,6 +725,7 @@ class number `h` is also the largest discriminant, but this is not [(-3, 1), (-3, 2), (-3, 3), (-4, 1), (-4, 2), (-7, 1), (-7, 2), (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]]} + def discriminants_with_bounded_class_number(hmax, B=None, proof=None): r"""Return a dictionary with keys class numbers `h\le hmax` and values the list of all pairs `(D_0, f)`, with `D_0<0` a fundamental discriminant such diff --git a/src/sage/schemes/elliptic_curves/constructor.py b/src/sage/schemes/elliptic_curves/constructor.py index ebbc55e6799..831ee47e280 100755 --- a/src/sage/schemes/elliptic_curves/constructor.py +++ b/src/sage/schemes/elliptic_curves/constructor.py @@ -438,6 +438,9 @@ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, # Interpret x as a Cremona or LMFDB label. from sage.databases.cremona import CremonaDatabase x, data = CremonaDatabase().coefficients_and_data(x) + # data is only valid for elliptic curves over QQ. + if R not in (None, QQ): + data = {} # User-provided keywords may override database entries. data.update(kwds) kwds = data @@ -457,7 +460,7 @@ def create_key_and_extra_args(self, x=None, y=None, j=None, minimal_twist=True, return (R, tuple(R(a) for a in x)), kwds - def create_object(self, version, key, **kwds): + def create_object(self, version, key, *, names=None, **kwds): r""" Create an object from a ``UniqueFactory`` key. @@ -467,18 +470,46 @@ def create_object(self, version, key, **kwds): sage: type(E) + ``names`` is ignored at the moment, however it is used to support a convenient way to get a generator:: + + sage: E.

= EllipticCurve(QQ, [1, 3]) + sage: P + (-1 : 1 : 1) + sage: E.

= EllipticCurve(GF(5), [1, 3]) + sage: P + (4 : 1 : 1) + .. NOTE:: Keyword arguments are currently only passed to the constructor for elliptic curves over `\QQ`; elliptic curves over other fields do not support them. + + TESTS:: + + sage: E = EllipticCurve.create_object(0, (QQ, (1, 2, 0, 1, 2)), rank=2) + sage: E = EllipticCurve.create_object(0, (GF(3), (1, 2, 0, 1, 2)), rank=2) + Traceback (most recent call last): + ... + TypeError: unexpected keyword arguments: {'rank': 2} + + Coverage tests:: + + sage: E = EllipticCurve(QQ, [2, 5], modular_degree=944, regulator=1) + sage: E.modular_degree() + 944 + sage: E.regulator() + 1.00000000000000 """ R, x = key if R is QQ: from .ell_rational_field import EllipticCurve_rational_field return EllipticCurve_rational_field(x, **kwds) - elif isinstance(R, NumberField): + elif kwds: + raise TypeError(f"unexpected keyword arguments: {kwds}") + + if isinstance(R, NumberField): from .ell_number_field import EllipticCurve_number_field return EllipticCurve_number_field(R, x) elif isinstance(R, sage.rings.abc.pAdicField): @@ -536,6 +567,7 @@ def EllipticCurve_from_Weierstrass_polynomial(f): """ return EllipticCurve(coefficients_from_Weierstrass_polynomial(f)) + def coefficients_from_Weierstrass_polynomial(f): r""" Return the coefficients `[a_1, a_2, a_3, a_4, a_6]` of a cubic in @@ -1277,6 +1309,7 @@ def tangent_at_smooth_point(C,P): except NotImplementedError: return C.tangents(P,factor=False)[0] + def chord_and_tangent(F, P): r"""Return the third point of intersection of a cubic with the tangent at one point. diff --git a/src/sage/schemes/elliptic_curves/ec_database.py b/src/sage/schemes/elliptic_curves/ec_database.py index 1cc03fdb8b3..7d418feb437 100755 --- a/src/sage/schemes/elliptic_curves/ec_database.py +++ b/src/sage/schemes/elliptic_curves/ec_database.py @@ -72,6 +72,7 @@ from .constructor import EllipticCurve + class EllipticCurves: def rank(self, rank, tors=0, n=10, labels=False): r""" diff --git a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py index c095eb1ee89..15c9f80fde1 100755 --- a/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py +++ b/src/sage/schemes/elliptic_curves/ell_curve_isogeny.py @@ -103,6 +103,8 @@ # Private function for parsing input to determine the type of # algorithm # + + def _isogeny_determine_algorithm(E, kernel): r""" Helper function to infer the algorithm to be used from the @@ -171,6 +173,7 @@ def _isogeny_determine_algorithm(E, kernel): raise ValueError("invalid parameters to EllipticCurveIsogeny constructor") + def isogeny_codomain_from_kernel(E, kernel): r""" Compute the isogeny codomain given a kernel. @@ -223,6 +226,7 @@ def isogeny_codomain_from_kernel(E, kernel): raise NotImplementedError + def compute_codomain_formula(E, v, w): r""" Compute the codomain curve given parameters `v` and `w` (as in @@ -263,6 +267,7 @@ def compute_codomain_formula(E, v, w): return EllipticCurve([a1, a2, a3, A4, A6]) + def compute_vw_kohel_even_deg1(x0, y0, a1, a2, a4): r""" Compute Vélu's `(v,w)` using Kohel's formulas for isogenies of @@ -298,6 +303,7 @@ def compute_vw_kohel_even_deg1(x0, y0, a1, a2, a4): w = x0 * v return v, w + def compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3): r""" Compute Vélu's `(v,w)` using Kohel's formulas for isogenies of @@ -335,6 +341,7 @@ def compute_vw_kohel_even_deg3(b2, b4, s1, s2, s3): w = 3*(s1**3 - 3*s1*s2 + 3*s3) + (b2*temp1 + b4*s1)/2 return v, w + def compute_vw_kohel_odd(b2, b4, b6, s1, s2, s3, n): r""" Compute Vélu's `(v,w)` using Kohel's formulas for isogenies of odd @@ -373,6 +380,7 @@ def compute_vw_kohel_odd(b2, b4, b6, s1, s2, s3, n): w = 10*(s1**3 - 3*s1*s2 + 3*s3) + 2*b2*(s1**2 - 2*s2) + 3*b4*s1 + n*b6 return v, w + def compute_codomain_kohel(E, kernel): r""" Compute the codomain from the kernel polynomial using Kohel's @@ -480,6 +488,7 @@ def compute_codomain_kohel(E, kernel): return compute_codomain_formula(E, v, w) + def two_torsion_part(E, psi): r""" Return the greatest common divisor of ``psi`` and the 2-torsion @@ -3456,6 +3465,7 @@ def compute_isogeny_bmss(E1, E2, l): ker = Rx(Q).reverse(degree=l//2) return ker.monic() + def compute_isogeny_stark(E1, E2, ell): r""" Return the kernel polynomial of an isogeny of degree ``ell`` @@ -3659,6 +3669,7 @@ def compute_isogeny_kernel_polynomial(E1, E2, ell, algorithm=None): raise NotImplementedError(f'unknown algorithm {algorithm}') + def compute_intermediate_curves(E1, E2): r""" Return intermediate curves and isomorphisms. @@ -3755,6 +3766,7 @@ def compute_intermediate_curves(E1, E2): post_iso = WeierstrassIsomorphism(E2w, urst, E2) return E1w, E2w, pre_iso, post_iso + def compute_sequence_of_maps(E1, E2, ell): r""" Return intermediate curves, isomorphisms and kernel polynomial. @@ -3854,6 +3866,7 @@ def compute_sequence_of_maps(E1, E2, ell): # Utility functions for manipulating isogeny degree matrices + def fill_isogeny_matrix(M): """ Return a filled isogeny matrix giving all degrees from one giving only prime degrees. @@ -3913,6 +3926,7 @@ def pr(M1, M2): M2 = pr(M0, M1) return M1 + def unfill_isogeny_matrix(M): """ Reverses the action of ``fill_isogeny_matrix``. diff --git a/src/sage/schemes/elliptic_curves/ell_field.py b/src/sage/schemes/elliptic_curves/ell_field.py index decf0a3d0b5..a63dbf57809 100755 --- a/src/sage/schemes/elliptic_curves/ell_field.py +++ b/src/sage/schemes/elliptic_curves/ell_field.py @@ -27,6 +27,7 @@ from .ell_curve_isogeny import EllipticCurveIsogeny, isogeny_codomain_from_kernel from . import ell_generic + class EllipticCurve_field(ell_generic.EllipticCurve_generic, ProjectivePlaneCurve_field): def __init__(self, R, data, category=None): @@ -2501,6 +2502,7 @@ def compute_model(E, name): raise NotImplementedError(f'cannot compute {name} model') + def point_of_order(E, n): r""" Given an elliptic curve `E` over a finite field or a number field diff --git a/src/sage/schemes/elliptic_curves/ell_finite_field.py b/src/sage/schemes/elliptic_curves/ell_finite_field.py index 8cf0cdb2cb0..fcd23e7243f 100755 --- a/src/sage/schemes/elliptic_curves/ell_finite_field.py +++ b/src/sage/schemes/elliptic_curves/ell_finite_field.py @@ -1868,6 +1868,7 @@ def twists(self): return [self, self.quadratic_twist(D)] + def curves_with_j_0(K): r""" Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 0 over the finite field `K`. @@ -1937,6 +1938,7 @@ def curves_with_j_0(K): # then you can also compute the orders! return curves + def curves_with_j_1728(K): r""" Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 1728 over the finite field `K`. @@ -1993,6 +1995,7 @@ def curves_with_j_1728(K): curves = [EllipticCurve(K, [D**i, 0]) for i in range(4)] return curves + def curves_with_j_0_char2(K): r""" Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 0 over the finite field `K` of characteristic 2. @@ -2086,6 +2089,7 @@ def curves_with_j_0_char2(K): return [EllipticCurve(K, ai) for ai in [[0,0,1,0,0], [0,0,1,0,b], [0,0,1,c,0], [0,0,a,0,0], [0,0,a,0,d], [0,0,asq,0,0], [0,0,asq,0,e]]] + def curves_with_j_0_char3(K): r""" Return a complete list of pairwise nonisomorphic elliptic curves with `j`-invariant 0 over the finite field `K` of characteristic 3. @@ -2182,6 +2186,7 @@ def curves_with_j_0_char3(K): supersingular_j_polynomials = {} + def fill_ss_j_dict(): r""" Fill the global cache of supersingular j-_polynomials. @@ -2251,6 +2256,7 @@ def fill_ss_j_dict(): supersingular_j_polynomials[283] = [212, 4, 42, 155, 38, 1, 270, 175, 172, 256, 264, 232, 50, 82, 244, 127, 148, 46, 249, 72, 59, 124, 75, 1] supersingular_j_polynomials[293] = [264, 66, 165, 144, 243, 25, 163, 210, 18, 107, 160, 153, 70, 255, 91, 211, 22, 7, 256, 50, 150, 94, 225, 60, 1] + def supersingular_j_polynomial(p, use_cache=True): r""" Return a polynomial whose roots are the supersingular @@ -2332,6 +2338,7 @@ def supersingular_j_polynomial(p, use_cache=True): supersingular_j_polynomials[p] = R.coefficients(sparse=False) return R + def is_j_supersingular(j, proof=True): r""" Return ``True`` if `j` is a supersingular `j`-invariant. @@ -2465,6 +2472,7 @@ def is_j_supersingular(j, proof=True): return E.trace_of_frobenius() % p == 0 + def special_supersingular_curve(F, *, endomorphism=False): r""" Given a finite field ``F``, construct a "special" supersingular @@ -2662,6 +2670,7 @@ def special_supersingular_curve(F, *, endomorphism=False): endo.trace.set_cache(ZZ.zero()) return E, endo + def EllipticCurve_with_order(m, *, D=None): r""" Return an iterator for elliptic curves over finite fields with the given order. The curves are diff --git a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py index ba10a3c6e1a..b6bdccff654 100755 --- a/src/sage/schemes/elliptic_curves/ell_modular_symbols.py +++ b/src/sage/schemes/elliptic_curves/ell_modular_symbols.py @@ -107,6 +107,7 @@ oo = Cusps(infinity) zero = Integer(0) + def modular_symbol_space(E, sign, base_ring, bound=None): r""" Create the space of modular symbols of a given sign over a give base_ring, @@ -220,6 +221,7 @@ def _repr_(self): return "Modular symbol with sign %s over %s attached to %s" % ( self._sign, self._base_ring, self._E) + class ModularSymbolECLIB(ModularSymbol): def __init__(self, E, sign, nap=1000): r"""Modular symbols attached to `E` using ``eclib``. diff --git a/src/sage/schemes/elliptic_curves/ell_point.py b/src/sage/schemes/elliptic_curves/ell_point.py index 09ed1e20df3..0da080ffdbe 100755 --- a/src/sage/schemes/elliptic_curves/ell_point.py +++ b/src/sage/schemes/elliptic_curves/ell_point.py @@ -2379,6 +2379,7 @@ def point_of_jacobian_of_curve(self): G = J.group(self.base_ring()) return G(P - P.degree()*Pinf) + class EllipticCurvePoint_number_field(EllipticCurvePoint_field): """ A point on an elliptic curve over a number field. diff --git a/src/sage/schemes/elliptic_curves/ell_rational_field.py b/src/sage/schemes/elliptic_curves/ell_rational_field.py index 2d5da94a8bd..993c25f38db 100755 --- a/src/sage/schemes/elliptic_curves/ell_rational_field.py +++ b/src/sage/schemes/elliptic_curves/ell_rational_field.py @@ -157,6 +157,13 @@ def __init__(self, ainvs, **kwds): TESTS: + Passing unexpected keyword arguments will raise an error:: + + sage: EllipticCurve.create_object(0, (QQ, (1, 2, 0, 1, 2)), base=QQ) + Traceback (most recent call last): + ... + TypeError: unexpected keyword arguments: {'base': Rational Field} + When constructing a curve from the large database using a label, we must be careful that the copied generators have the right curve (see :issue:`10999`: the following used not to work when @@ -181,21 +188,23 @@ def __init__(self, ainvs, **kwds): EllipticCurve_number_field.__init__(self, Q, ainvs) if 'conductor' in kwds: - self._set_conductor(kwds['conductor']) + self._set_conductor(kwds.pop('conductor')) if 'cremona_label' in kwds: - self._set_cremona_label(kwds['cremona_label']) + self._set_cremona_label(kwds.pop('cremona_label')) if 'gens' in kwds: - self._set_gens(kwds['gens']) + self._set_gens(kwds.pop('gens')) if 'lmfdb_label' in kwds: - self._lmfdb_label = kwds['lmfdb_label'] + self._lmfdb_label = kwds.pop('lmfdb_label') if 'modular_degree' in kwds: - self._set_modular_degree(kwds['modular_degree']) + self._set_modular_degree(kwds.pop('modular_degree')) if 'rank' in kwds: - self._set_rank(kwds['rank']) + self._set_rank(kwds.pop('rank')) if 'regulator' in kwds: - self.__regulator = (kwds['regulator'], True) + self.__regulator = (kwds.pop('regulator'), True) if 'torsion_order' in kwds: - self._set_torsion_order(kwds['torsion_order']) + self._set_torsion_order(kwds.pop('torsion_order')) + if kwds: + raise TypeError(f"unexpected keyword arguments: {kwds}") def _set_rank(self, r): r""" @@ -7097,6 +7106,7 @@ def cremona_curves(conductors): conductors = [conductors] return sage.databases.cremona.CremonaDatabase().iter(conductors) + def cremona_optimal_curves(conductors): r""" Return iterator over all known optimal curves (in database) with @@ -7123,6 +7133,7 @@ def cremona_optimal_curves(conductors): conductors = [conductors] return sage.databases.cremona.CremonaDatabase().iter_optimal(conductors) + def integral_points_with_bounded_mw_coeffs(E, mw_base, N, x_bound): r""" Return the set of integers `x` which are diff --git a/src/sage/schemes/elliptic_curves/ell_wp.py b/src/sage/schemes/elliptic_curves/ell_wp.py index a1a5c8fb5fe..5c8e7930830 100755 --- a/src/sage/schemes/elliptic_curves/ell_wp.py +++ b/src/sage/schemes/elliptic_curves/ell_wp.py @@ -54,6 +54,7 @@ # Note: Part of the documentation is replicated in ell_field.py for # users' convenience. Make sure to keep the two copies synchronized. + def weierstrass_p(E, prec=20, algorithm=None): r""" Compute the Weierstrass `\wp`-function on an elliptic curve. @@ -165,6 +166,7 @@ def weierstrass_p(E, prec=20, algorithm=None): u = E.isomorphism_to(Esh).u return wp(z*u) * u**2 + def compute_wp_pari(E,prec): r""" Compute the Weierstrass `\wp`-function with the ``ellwp`` function @@ -251,6 +253,7 @@ def compute_wp_quadratic(k, A, B, prec): return pe(Z**2).add_bigoh(prec) + def compute_wp_fast(k, A, B, m): r""" Compute the Weierstrass function of an elliptic curve defined by short Weierstrass model: diff --git a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py index accde11b636..a4eb66a6df7 100755 --- a/src/sage/schemes/elliptic_curves/gal_reps_number_field.py +++ b/src/sage/schemes/elliptic_curves/gal_reps_number_field.py @@ -422,6 +422,7 @@ def reducible_primes(self): return [l for l in self.isogeny_bound() if self.E.isogenies_prime_degree(l)] + def _non_surjective(E, patience=100): r""" Return a list of primes `p` including all primes for which the mod-`p` @@ -775,6 +776,7 @@ def _over_numberfield(E): K = K.absolute_field('a') return E.change_ring(K) + def deg_one_primes_iter(K, principal_only=False): r""" Return an iterator over degree 1 primes of ``K``. @@ -823,6 +825,7 @@ def deg_one_primes_iter(K, principal_only=False): if not principal_only or P.is_principal(): yield P + def _semistable_reducible_primes(E, verbose=False): r"""Find a list containing all semistable primes l unramified in K/QQ for which the Galois image for E could be reducible. @@ -1151,6 +1154,7 @@ def _possible_normalizers(E, SA): # elliptiques", Nicolas Billerey, https://arxiv.org/abs/0908.1084 # + def Billerey_P_l(E, l): r""" Return Billerey's `P_l^*` as defined in [Bil2011]_, equation (9). @@ -1186,6 +1190,7 @@ def Billerey_P_l(E, l): P = P.composed_op(E.reduction(q).frobenius_polynomial().adams_operator_on_roots(12*e), mul, monic=True) return P + def Billerey_B_l(E,l,B=0): r""" Return Billerey's `B_l`, adapted from the definition in [Bil2011]_, after (9). diff --git a/src/sage/schemes/elliptic_curves/gp_simon.py b/src/sage/schemes/elliptic_curves/gp_simon.py index 39a60361ec6..729380dccf1 100644 --- a/src/sage/schemes/elliptic_curves/gp_simon.py +++ b/src/sage/schemes/elliptic_curves/gp_simon.py @@ -27,6 +27,8 @@ gp = None + + def init(): """ Function to initialize the gp process diff --git a/src/sage/schemes/elliptic_curves/heegner.py b/src/sage/schemes/elliptic_curves/heegner.py index fb5306f32b3..1bff085023c 100755 --- a/src/sage/schemes/elliptic_curves/heegner.py +++ b/src/sage/schemes/elliptic_curves/heegner.py @@ -138,6 +138,7 @@ # ############################################################################### + def heegner_points(N, D=None, c=None): """ Return all Heegner points of given level `N`. Can also restrict @@ -597,6 +598,7 @@ def is_subfield(self, M): # ################################################################################## + class GaloisGroup(SageObject): """ A Galois group of a ring class field. @@ -2111,6 +2113,7 @@ def discriminants(self, n=10, weak=False): v.append(D) return v + class HeegnerPoints_level_disc(HeegnerPoints): """ Set of Heegner points of given level and all conductors associated @@ -4003,6 +4006,8 @@ def kolyvagin_cohomology_class(self, n=None): ######################################################################################### # Kolyvagin Points P_c ######################################################################################### + + class KolyvaginPoint(HeegnerPoint): """ A Kolyvagin point. @@ -4612,6 +4617,7 @@ def heegner_point(self): """ return self.__kolyvagin_point.heegner_point() + class KolyvaginCohomologyClassEn(KolyvaginCohomologyClass): def _repr_(self): """ @@ -4904,8 +4910,8 @@ def right_ideals(self): EXAMPLES:: sage: heegner_points(11).reduce_mod(3).right_ideals() - (Fractional ideal (2 + 2*j + 28*k, 2*i + 26*k, 4*j + 12*k, 44*k), - Fractional ideal (2 + 2*j + 28*k, 2*i + 4*j + 38*k, 8*j + 24*k, 88*k)) + (Fractional ideal (4, 44*i, 2 + 8*i + 2*j, 34*i + 2*k), + Fractional ideal (8, 88*i, 2 + 52*i + 2*j, 4 + 78*i + 2*k)) """ return self.brandt_module().right_ideals() @@ -5135,14 +5141,10 @@ def cyclic_subideal_p1(self, I, c): sage: H = heegner_points(11).reduce_mod(7) sage: I = H.brandt_module().right_ideals()[0] sage: sorted(H.cyclic_subideal_p1(I, 3).items()) - [((0, 1), - Fractional ideal (2 + 2*j + 32*k, 2*i + 8*j + 82*k, 12*j + 60*k, 132*k)), - ((1, 0), - Fractional ideal (2 + 10*j + 28*k, 2*i + 4*j + 62*k, 12*j + 60*k, 132*k)), - ((1, 1), - Fractional ideal (2 + 2*j + 76*k, 2*i + 4*j + 106*k, 12*j + 60*k, 132*k)), - ((1, 2), - Fractional ideal (2 + 10*j + 116*k, 2*i + 8*j + 38*k, 12*j + 60*k, 132*k))] + [((0, 1), Fractional ideal (12, 132*i, 10 + 76*i + 2*j, 4 + 86*i + 2*k)), + ((1, 0), Fractional ideal (12, 132*i, 2 + 32*i + 2*j, 8 + 130*i + 2*k)), + ((1, 1), Fractional ideal (12, 132*i, 10 + 32*i + 2*j, 8 + 86*i + 2*k)), + ((1, 2), Fractional ideal (12, 132*i, 2 + 76*i + 2*j, 4 + 130*i + 2*k))] sage: len(H.cyclic_subideal_p1(I, 17)) 18 """ @@ -5267,24 +5269,12 @@ def kolyvagin_cyclic_subideals(self, I, p, alpha_quaternion): sage: alpha_quaternion = f(g[0]); alpha_quaternion 1 - 77/192*i - 5/128*j - 137/384*k sage: H.kolyvagin_cyclic_subideals(I, 5, alpha_quaternion) - [(Fractional ideal (2 + 2/3*i + 364*j + 231928/3*k, - 4/3*i + 946*j + 69338/3*k, - 1280*j + 49920*k, 94720*k), 0), - (Fractional ideal (2 + 2/3*i + 108*j + 31480/3*k, - 4/3*i + 434*j + 123098/3*k, - 1280*j + 49920*k, 94720*k), 1), - (Fractional ideal (2 + 2/3*i + 876*j + 7672/3*k, - 4/3*i + 434*j + 236762/3*k, - 1280*j + 49920*k, 94720*k), 2), - (Fractional ideal (2 + 2/3*i + 364*j + 61432/3*k, - 4/3*i + 178*j + 206810/3*k, - 1280*j + 49920*k, 94720*k), 3), - (Fractional ideal (2 + 2/3*i + 876*j + 178168/3*k, - 4/3*i + 1202*j + 99290/3*k, - 1280*j + 49920*k, 94720*k), 4), - (Fractional ideal (2 + 2/3*i + 1132*j + 208120/3*k, - 4/3*i + 946*j + 183002/3*k, - 1280*j + 49920*k, 94720*k), 5)] + [(Fractional ideal (2560, 1280 + 47360*i, 1146 + 37678*i + 4*j, 212 + 54664/3*i + 2*j + 2/3*k), 0), + (Fractional ideal (2560, 1280 + 47360*i, 2426 + 9262*i + 4*j, 2004 + 83080/3*i + 2*j + 2/3*k), 1), + (Fractional ideal (2560, 1280 + 47360*i, 1914 + 9262*i + 4*j, 1748 + 111496/3*i + 2*j + 2/3*k), 2), + (Fractional ideal (2560, 1280 + 47360*i, 2170 + 18734*i + 4*j, 212 + 111496/3*i + 2*j + 2/3*k), 3), + (Fractional ideal (2560, 1280 + 47360*i, 890 + 28206*i + 4*j, 1748 + 54664/3*i + 2*j + 2/3*k), 4), + (Fractional ideal (2560, 1280 + 47360*i, 634 + 37678*i + 4*j, 2516 + 83080/3*i + 2*j + 2/3*k), 5)] """ X = I.cyclic_right_subideals(p, alpha_quaternion) return [(J, i) for i, J in enumerate(X)] @@ -5630,6 +5620,7 @@ def kolyvagin_point_on_curve(self, D, c, E, p, bound=10): V = self.modp_dual_elliptic_curve_factor(E, p, bound) return [b.dot_product(k.element().change_ring(GF(p))) for b in V.basis()] + def kolyvagin_reduction_data(E, q, first_only=True): r""" Given an elliptic curve of positive rank and a prime `q`, this @@ -5836,6 +5827,7 @@ def kernel_of_reduction(ell): BrandtModule(ell_1,N).dimension(), BrandtModule(ell_2,N).dimension()) + class HeegnerQuatAlgEmbedding(SageObject): r""" The homomorphism `\mathcal{O} \to R`, where `\mathcal{O}` is the @@ -6119,6 +6111,7 @@ def quadratic_order(D, c, names='a'): R = K.order([t]) return R, R(t) + def class_number(D): """ Return the class number of the quadratic field with fundamental @@ -6149,6 +6142,7 @@ def class_number(D): raise ValueError("D (=%s) must be a fundamental discriminant" % D) return D.class_number() + def is_inert(D, p): r""" Return ``True`` if p is an inert prime in the field `\QQ(\sqrt{D})`. @@ -6172,6 +6166,7 @@ def is_inert(D, p): F = K.factor(p) return len(F) == 1 and F[0][1] == 1 + def is_split(D, p): r""" Return ``True`` if p is a split prime in the field `\QQ(\sqrt{D})`. @@ -6195,6 +6190,7 @@ def is_split(D, p): F = K.factor(p) return len(F) == 2 + def is_ramified(D, p): r""" Return ``True`` if p is a ramified prime in the field `\QQ(\sqrt{D})`. @@ -6216,6 +6212,7 @@ def is_ramified(D, p): """ return QuadraticField(D,'a').discriminant() % p == 0 + def nearby_rational_poly(f, **kwds): r""" Return a polynomial whose coefficients are rational numbers close @@ -6241,6 +6238,7 @@ def nearby_rational_poly(f, **kwds): R = QQ['X'] return R([a.nearby_rational(**kwds) for a in f]) + def simplest_rational_poly(f, prec): """ Return a polynomial whose coefficients are as simple as possible @@ -6263,6 +6261,7 @@ def simplest_rational_poly(f, prec): Z = RealField(prec) return R([Z(a).simplest_rational() for a in f]) + def satisfies_weak_heegner_hypothesis(N, D): r""" Check that `D` satisfies the weak Heegner hypothesis relative to `N`. @@ -6438,6 +6437,7 @@ def ell_heegner_point(self, D, c=ZZ(1), f=None, check=True): y = HeegnerPointOnX0N(self.conductor(), D, c, f, check=check) return y.map_to_curve(self) + def kolyvagin_point(self, D, c=ZZ(1), check=True): r""" Return the Kolyvagin point on this curve associated to the @@ -6470,6 +6470,7 @@ def kolyvagin_point(self, D, c=ZZ(1), check=True): """ return self.heegner_point(D,c,check=check).kolyvagin_point() + def ell_heegner_discriminants(self, bound): """ Return the list of ``self``'s Heegner discriminants between -1 and @@ -6519,6 +6520,7 @@ def ell_heegner_discriminants_list(self, n): D -= 1 return v + def heegner_point_height(self, D, prec=2, check_rank=True): r""" Use the Gross-Zagier formula to compute the Neron-Tate canonical @@ -7050,6 +7052,7 @@ def _heegner_index_in_EK(self, D): self.__heegner_index_in_EK[D] = index return index + def heegner_sha_an(self, D, prec=53): r""" Return the conjectural (analytic) order of Sha for E over the field `K=\QQ(\sqrt{D})`. @@ -7261,6 +7264,7 @@ def _heegner_forms_list(self, D, beta=None, expected_count=None): return all b += 2*N + def _heegner_best_tau(self, D, prec=None): r""" Given a discriminant `D`, find the Heegner point `\tau` in the @@ -7285,6 +7289,7 @@ def _heegner_best_tau(self, D, prec=None): # TODO: make sure a different choice of b is not better? return (-b + ZZ(D).sqrt(prec=prec)) / (2*N) + def satisfies_heegner_hypothesis(self, D): """ Return ``True`` precisely when `D` is a fundamental discriminant that diff --git a/src/sage/schemes/elliptic_curves/height.py b/src/sage/schemes/elliptic_curves/height.py index 88447c3bdbd..53f440f5db4 100755 --- a/src/sage/schemes/elliptic_curves/height.py +++ b/src/sage/schemes/elliptic_curves/height.py @@ -514,6 +514,7 @@ def nonneg_region(f): sign_changes += [infinity] return UnionOfIntervals(sign_changes) + def inf_max_abs(f, g, D): r""" Return `\inf_D(\max(|f|, |g|))`. diff --git a/src/sage/schemes/elliptic_curves/hom_velusqrt.py b/src/sage/schemes/elliptic_curves/hom_velusqrt.py index c7c6e434ce5..d8cf1971f45 100755 --- a/src/sage/schemes/elliptic_curves/hom_velusqrt.py +++ b/src/sage/schemes/elliptic_curves/hom_velusqrt.py @@ -135,6 +135,7 @@ from .ell_finite_field import EllipticCurve_finite_field from .hom import EllipticCurveHom, compare_via_evaluation + class _VeluBoundObj: """ Helper object to define the point in which isogeny @@ -165,6 +166,7 @@ def __repr__(self): _velu_sqrt_bound = _VeluBoundObj() + def _choose_IJK(n): r""" Helper function to choose an "index system" for the set @@ -201,6 +203,7 @@ def _choose_IJK(n): K = range(4*b*c+1, n, 2) return I, J, K + def _points_range(rr, P, Q=None): r""" Return an iterator yielding all points `Q + [i]P` where `i` runs diff --git a/src/sage/schemes/elliptic_curves/isogeny_class.py b/src/sage/schemes/elliptic_curves/isogeny_class.py index 2c710b09f0b..13edc68a022 100755 --- a/src/sage/schemes/elliptic_curves/isogeny_class.py +++ b/src/sage/schemes/elliptic_curves/isogeny_class.py @@ -1319,6 +1319,7 @@ def isogeny_degrees_cm(E, verbose=False): print("List of primes after filtering: %s" % L) return L + def possible_isogeny_degrees(E, algorithm='Billerey', max_l=None, num_l=None, exact=True, verbose=False): r""" diff --git a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py index 92199fb497e..6a0194fb0f9 100755 --- a/src/sage/schemes/elliptic_curves/isogeny_small_degree.py +++ b/src/sage/schemes/elliptic_curves/isogeny_small_degree.py @@ -45,6 +45,7 @@ # only finitely many `j`-invariants each. are also implemented. ########################################################################## + @cached_function def Fricke_polynomial(l): r""" @@ -813,6 +814,7 @@ def isogenies_3(E, minimal_models=True): # 6 special cases: `l` = 5, 7, 13 and `j` = 0, 1728. + def isogenies_5_0(E, minimal_models=True): r""" Return a list of all the 5-isogenies with domain ``E`` when the @@ -916,6 +918,7 @@ def isogenies_5_0(E, minimal_models=True): isogs = [isog * iso for isog in isogs] return isogs + def isogenies_5_1728(E, minimal_models=True): r""" Return a list of 5-isogenies with domain ``E`` when the j-invariant is @@ -1051,6 +1054,7 @@ def isogenies_5_1728(E, minimal_models=True): isogs = [isog * iso for isog in isogs] return isogs + def isogenies_7_0(E, minimal_models=True): r""" Return list of all 7-isogenies from E when the j-invariant is 0. @@ -1191,6 +1195,7 @@ def isogenies_7_0(E, minimal_models=True): isogs = [isog * iso for isog in isogs] return isogs + def isogenies_7_1728(E, minimal_models=True): r""" Return list of all 7-isogenies from E when the j-invariant is 1728. @@ -1290,6 +1295,7 @@ def isogenies_7_1728(E, minimal_models=True): isogs = [isog * iso for isog in isogs] return isogs + def isogenies_13_0(E, minimal_models=True): """ Return list of all 13-isogenies from E when the j-invariant is 0. @@ -1599,6 +1605,7 @@ def isogenies_13_1728(E, minimal_models=True): hyperelliptic_primes = [11, 17, 19, 23, 29, 31, 41, 47, 59, 71] + @cached_function def _hyperelliptic_isogeny_data(l): r""" diff --git a/src/sage/schemes/elliptic_curves/padics.py b/src/sage/schemes/elliptic_curves/padics.py index 624b3a11e7d..87f985e7052 100755 --- a/src/sage/schemes/elliptic_curves/padics.py +++ b/src/sage/schemes/elliptic_curves/padics.py @@ -420,6 +420,7 @@ def padic_height_pairing_matrix(self, p, prec=20, height=None, check_hypotheses= return M + def _multiply_point(E, R, P, m): r""" Compute coordinates of a multiple of `P` with entries in a ring. @@ -578,6 +579,7 @@ def _multiply_point(E, R, P, m): return theta, omega, psi_m * d + def _multiple_to_make_good_reduction(E): r""" Return the integer `n_2` such that for all points `P` in `E(\QQ)` @@ -653,6 +655,7 @@ def _multiple_to_make_good_reduction(E): n2 = LCM(li) return n2 + def padic_height(self, p, prec=20, sigma=None, check_hypotheses=True): r""" Compute the cyclotomic `p`-adic height. diff --git a/src/sage/schemes/elliptic_curves/period_lattice.py b/src/sage/schemes/elliptic_curves/period_lattice.py index 9db15a6eba7..e6008a09279 100755 --- a/src/sage/schemes/elliptic_curves/period_lattice.py +++ b/src/sage/schemes/elliptic_curves/period_lattice.py @@ -413,7 +413,7 @@ def basis(self, prec=None, algorithm='sage'): (tuple of Complex) `(\omega_1,\omega_2)` where the lattice is `\ZZ\omega_1 + \ZZ\omega_2`. If the lattice is real then `\omega_1` is real and positive, `\Im(\omega_2)>0` and - `\Re(\omega_1/\omega_2)` is either `0` (for rectangular + `\Re(\omega_2/\omega_1)` is either `0` (for rectangular lattices) or `\frac{1}{2}` (for non-rectangular lattices). Otherwise, `\omega_1/\omega_2` is in the fundamental region of the upper half-plane. If the latter normalisation is required @@ -498,7 +498,7 @@ def gens(self, prec=None, algorithm='sage'): (tuple of Complex) `(\omega_1,\omega_2)` where the lattice is `\ZZ\omega_1 + \ZZ\omega_2`. If the lattice is real then `\omega_1` is real and positive, `\Im(\omega_2)>0` and - `\Re(\omega_1/\omega_2)` is either `0` (for rectangular + `\Re(\omega_2/\omega_1)` is either `0` (for rectangular lattices) or `\frac{1}{2}` (for non-rectangular lattices). Otherwise, `\omega_1/\omega_2` is in the fundamental region of the upper half-plane. If the latter normalisation is required @@ -650,7 +650,7 @@ def _compute_periods_real(self, prec=None, algorithm='sage'): (tuple of Complex) `(\omega_1,\omega_2)` where the lattice has the form `\ZZ\omega_1 + \ZZ\omega_2`, `\omega_1` is real and - `\omega_1/\omega_2` has real part either `0` or `frac{1}{2}`. + `\omega_2/\omega_1` has real part either `0` or `frac{1}{2}`. EXAMPLES:: diff --git a/src/sage/schemes/elliptic_curves/saturation.py b/src/sage/schemes/elliptic_curves/saturation.py index 5f14db7ac19..9772b8f1d09 100755 --- a/src/sage/schemes/elliptic_curves/saturation.py +++ b/src/sage/schemes/elliptic_curves/saturation.py @@ -54,6 +54,7 @@ from sage.arith.misc import kronecker as kro from sage.structure.sage_object import SageObject + def reduce_mod_q(x, amodq): r"""The reduction of ``x`` modulo the prime ideal defined by ``amodq``. @@ -88,6 +89,7 @@ def reduce_mod_q(x, amodq): except AttributeError: # in case x is in QQ return Fq(x) + class EllipticCurveSaturator(SageObject): r""" Class for saturating points on an elliptic curve over a number field. @@ -585,6 +587,7 @@ def p_saturation(self, Plist, p, sieve=True): rankA = newrank count = 0 + def p_projections(Eq, Plist, p, debug=False): r""" diff --git a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py index 1fc2eb751a9..bbd3bc1e9d6 100755 --- a/src/sage/schemes/elliptic_curves/weierstrass_morphism.py +++ b/src/sage/schemes/elliptic_curves/weierstrass_morphism.py @@ -32,6 +32,7 @@ from sage.rings.integer import Integer from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing + class baseWI: r""" This class implements the basic arithmetic of isomorphisms between @@ -1071,6 +1072,7 @@ def order(self): raise NotImplementedError("the order of the endomorphism is not 1, 2, 3, 4 or 6") + def identity_morphism(E): r""" Given an elliptic curve `E`, return the identity morphism @@ -1088,6 +1090,7 @@ def identity_morphism(E): zero = R.zero() return WeierstrassIsomorphism(E, (R.one(), zero, zero, zero)) + def negation_morphism(E): r""" Given an elliptic curve `E`, return the negation endomorphism diff --git a/src/sage/schemes/generic/algebraic_scheme.py b/src/sage/schemes/generic/algebraic_scheme.py index ebe79be6471..9a0afa5fb93 100755 --- a/src/sage/schemes/generic/algebraic_scheme.py +++ b/src/sage/schemes/generic/algebraic_scheme.py @@ -134,6 +134,7 @@ from . import ambient_space from . import scheme + def is_AlgebraicScheme(x): """ Test whether ``x`` is an algebraic scheme. diff --git a/src/sage/schemes/generic/glue.py b/src/sage/schemes/generic/glue.py index 72171a57cb5..7733030a2ab 100755 --- a/src/sage/schemes/generic/glue.py +++ b/src/sage/schemes/generic/glue.py @@ -5,7 +5,7 @@ #******************************************************************************* # Copyright (C) 2006 William Stein # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #******************************************************************************* from sage.misc.lazy_import import lazy_import diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index 1468090f395..370049d2238 100755 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -658,6 +658,56 @@ def _element_constructor_(self, *v, **kwds): v = v[0] return self.extended_codomain()._point(self, v, **kwds) + def __iter__(self): + r""" + Return an iterator for the set of rational points on this scheme. + + By default, this calls the :meth:`points` method, which is implemented + when the base ring is a field + + - for affine homsets at :meth:`sage.schemes.affine.affine_homset.SchemeHomset_points_affine.points`; + - for projective homsets at :meth:`sage.schemes.projective.projective_homset.SchemeHomset_points_projective_field.points`; + - and toric homsets at :meth:`sage.schemes.toric.homset.SchemeHomset_points_toric_field._enumerator`. + + OUTPUT: iterator over points + + TESTS:: + + sage: E = EllipticCurve(GF(19), [1, 0]) + sage: list(E.point_homset()) + [(0 : 1 : 0), (0 : 0 : 1), (3 : 7 : 1), (3 : 12 : 1), (4 : 7 : 1), + (4 : 12 : 1), (5 : 4 : 1), (5 : 15 : 1), (8 : 8 : 1), (8 : 11 : 1), + (9 : 4 : 1), (9 : 15 : 1), (12 : 7 : 1), (12 : 12 : 1), (13 : 5 : 1), + (13 : 14 : 1), (17 : 3 : 1), (17 : 16 : 1), (18 : 6 : 1), (18 : 13 : 1)] + sage: _ == list(E) + True + sage: E.point_homset().cardinality() + 20 + + :: + + sage: A. = AffineSpace(2, GF(5)) + sage: list(A.point_homset()) + [(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), + (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), + (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), + (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), + (4, 0), (4, 1), (4, 2), (4, 3), (4, 4)] + sage: _ == list(A) + True + sage: A.point_homset().cardinality() + 25 + + :: + + sage: P1 = toric_varieties.P1(base_ring=GF(3)) + sage: list(P1.point_homset()) + [[0 : 1], [1 : 0], [1 : 1], [1 : 2]] + sage: P1.point_homset().cardinality() + 4 + """ + yield from self.points() + def extended_codomain(self): r""" Return the codomain with extended base, if necessary. diff --git a/src/sage/schemes/generic/hypersurface.py b/src/sage/schemes/generic/hypersurface.py index 0560697be25..a6bb63040b5 100755 --- a/src/sage/schemes/generic/hypersurface.py +++ b/src/sage/schemes/generic/hypersurface.py @@ -23,6 +23,7 @@ from sage.schemes.affine.affine_subscheme import AlgebraicScheme_subscheme_affine from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective + def is_Hypersurface(self): """ Return ``True`` if ``self`` is a hypersurface, i.e. an object of the type diff --git a/src/sage/schemes/generic/point.py b/src/sage/schemes/generic/point.py index 4bd18c39a5d..4158b350c16 100755 --- a/src/sage/schemes/generic/point.py +++ b/src/sage/schemes/generic/point.py @@ -16,6 +16,7 @@ # or defined by a morphism. ######################################################## + class SchemePoint(Element): """ Base class for points on a scheme, either topological or defined @@ -72,6 +73,7 @@ def _repr_(self): # Topological points on a scheme ######################################################## + def is_SchemeTopologicalPoint(x): from sage.misc.superseded import deprecation deprecation(38296, @@ -79,6 +81,7 @@ def is_SchemeTopologicalPoint(x): "use 'isinstance(..., SchemeTopologicalPoint)' instead.") return isinstance(x, SchemeTopologicalPoint) + class SchemeTopologicalPoint(SchemePoint): """ Base class for topological points on schemes. diff --git a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py index 6074f66e699..61cd934c0a0 100755 --- a/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py @@ -172,16 +172,44 @@ def _repr_(self): Hyperelliptic Curve over Rational Field defined by y^2 = 4*x^5 - 30*x^3 + 45*x - 22 sage: C = HyperellipticCurve(f,names='u,v'); C Hyperelliptic Curve over Rational Field defined by v^2 = 4*u^5 - 30*u^3 + 45*u - 22 + sage: C = HyperellipticCurve(x^5 + 1, x^3 + 2); C + Hyperelliptic Curve over Rational Field defined by y^2 + (x^3 + 2)*y = x^5 + 1 """ f, h = self._hyperelliptic_polynomials R = self.base_ring() y = self._printing_ring.gen() x = self._printing_ring.base_ring().gen() - if h == 0: + if h.is_zero(): return "Hyperelliptic Curve over %s defined by %s = %s" % (R, y**2, f(x)) - else: - return "Hyperelliptic Curve over %s defined by %s + %s = %s" % (R, y**2, h(x)*y, f(x)) + return "Hyperelliptic Curve over %s defined by %s + %s = %s" % (R, y**2, h(x)*y, f(x)) + + def _latex_(self): + r""" + LaTeX representation of hyperelliptic curves. + + EXAMPLES:: + + sage: P. = QQ[] + sage: f = 4*x^5 - 30*x^3 + 45*x - 22 + sage: C = HyperellipticCurve(f); latex(C) + \text{Hyperelliptic Curve over $\Bold{Q}$ defined by $y^{2} = 4 x^{5} - 30 x^{3} + 45 x - 22$} + sage: C = HyperellipticCurve(f,names='u,v'); latex(C) + \text{Hyperelliptic Curve over $\Bold{Q}$ defined by $v^{2} = 4 u^{5} - 30 u^{3} + 45 u - 22$} + sage: C = HyperellipticCurve(x^5 + 1, x^2 + 3); latex(C) + \text{Hyperelliptic Curve over $\Bold{Q}$ defined by $y^{2} + \left(x^{2} + 3\right) y = x^{5} + 1$} + """ + + f, h = self._hyperelliptic_polynomials + R = self.base_ring() + y = self._printing_ring.gen() + x = self._printing_ring.base_ring().gen() + if h.is_zero(): + return (fr'\text{{Hyperelliptic Curve over ${R._latex_()}$ ' + f'defined by ${(y**2)._latex_()} = {(f(x))._latex_()}$}}') + return (fr'\text{{Hyperelliptic Curve over ${R._latex_()}$ ' + f'defined by ${(y**2)._latex_()} + {(h(x)*y)._latex_()} = ' + f'{(f(x))._latex_()}$}}') def hyperelliptic_polynomials(self, K=None, var='x'): """ diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_g2.py b/src/sage/schemes/hyperelliptic_curves/jacobian_g2.py index b4b4259326e..970bb9cfbf0 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_g2.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_g2.py @@ -22,6 +22,7 @@ # + (4*a4 + 2*c0*c4 + c2^2)*x^4 + (4*a6 + 2*c0*c6 + 2*c2*c4)*x^3 # + (4*a8 + 2*c2*c6 + c4^2)*x^2 + (4*a10 + 2*c4*c6)*x + 4*a12 + c6^2 + class HyperellipticJacobian_g2(jacobian_generic.HyperellipticJacobian_generic): def kummer_surface(self): try: diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py b/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py index 29c98369259..0fdea5814f0 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py @@ -112,30 +112,40 @@ def __call__(self, P): (x + 2, y) sage: D1 + D2 (x^2 + 2*x + 2, y + 2*x + 1) + + TESTS: + + Test :issue:`38459`:: + + sage: K. = QQ[] + sage: C = HyperellipticCurve(u^5 - 1) + sage: J = C.jacobian() + sage: J(u - 1, 0) + (x - 1, y) """ if isinstance(P, (Integer, int)) and P == 0: - R = PolynomialRing(self.value_ring(), 'x') + R = self.curve().hyperelliptic_polynomials()[0].parent().change_ring(self.value_ring()) return JacobianMorphism_divisor_class_field(self, (R.one(), R.zero())) elif isinstance(P, (list, tuple)): if len(P) == 1 and P[0] == 0: - R = PolynomialRing(self.value_ring(), 'x') + R = self.curve().hyperelliptic_polynomials()[0].parent().change_ring(self.value_ring()) return JacobianMorphism_divisor_class_field(self, (R.one(), R.zero())) elif len(P) == 2: P1 = P[0] P2 = P[1] if isinstance(P1, Integer) and isinstance(P2, Integer): - R = PolynomialRing(self.value_ring(), 'x') + R = self.curve().hyperelliptic_polynomials()[0].parent().change_ring(self.value_ring()) P1 = R(P1) P2 = R(P2) return JacobianMorphism_divisor_class_field(self, (P1, P2)) if isinstance(P1, Integer) and isinstance(P2, Polynomial): - R = PolynomialRing(self.value_ring(), 'x') + R = self.curve().hyperelliptic_polynomials()[0].parent().change_ring(self.value_ring()) P1 = R(P1) return JacobianMorphism_divisor_class_field(self, (P1, P2)) if isinstance(P2, Integer) and isinstance(P1, Polynomial): - R = PolynomialRing(self.value_ring(), 'x') + R = self.curve().hyperelliptic_polynomials()[0].parent().change_ring(self.value_ring()) P2 = R(P2) return JacobianMorphism_divisor_class_field(self, (P1, P2)) if isinstance(P1, Polynomial) and isinstance(P2, Polynomial): @@ -148,7 +158,7 @@ def __call__(self, P): elif isinstance(P, SchemeMorphism): x0 = P[0] y0 = P[1] - R, x = PolynomialRing(self.value_ring(), 'x').objgen() + R, x = self.curve().hyperelliptic_polynomials()[0].parent().change_ring(self.value_ring()).objgen() return self((x - x0, R(y0))) raise TypeError("argument P (= %s) does not determine a divisor class" % P) diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py index 50ec2c63748..c0cbccd84ea 100755 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_morphism.py @@ -210,6 +210,7 @@ def cantor_reduction(a, b, f, h, genus): return cantor_reduction(a, b, f, h, genus) return (a, b) + def cantor_composition_simple(D1,D2,f,genus): r""" Given `D_1` and `D_2` two reduced Mumford @@ -268,6 +269,7 @@ def cantor_composition_simple(D1,D2,f,genus): a = a.monic() return (a, b) + def cantor_composition(D1,D2,f,h,genus): r""" EXAMPLES:: diff --git a/src/sage/schemes/hyperelliptic_curves/kummer_surface.py b/src/sage/schemes/hyperelliptic_curves/kummer_surface.py index dadf1200f01..8cf0104c560 100644 --- a/src/sage/schemes/hyperelliptic_curves/kummer_surface.py +++ b/src/sage/schemes/hyperelliptic_curves/kummer_surface.py @@ -25,6 +25,7 @@ # + (2*c3*c9 + c6^2 + 4*a8)*x^4 + (2*c0*c9 + 2*c3*c6 + 4*a6)*x^3 # + (2*c0*c6 + c3^2 + 4*a4)*x^2 + (2*c0*c3 + 4*a2)*x + c0^2 + 4*a0 + class KummerSurface(AlgebraicScheme_subscheme_projective): def __init__(self, J): """ diff --git a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py index 8e6e3df0d3c..a533b7d4e92 100755 --- a/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py +++ b/src/sage/schemes/hyperelliptic_curves/monsky_washnitzer.py @@ -2409,7 +2409,7 @@ def __init__(self, Q, R=None, invert_y=True): if not hasattr(self, '_curve'): if self._Q.degree() == 3: ainvs = [0, self._Q[2], 0, self._Q[1], self._Q[0]] - self._curve = EllipticCurve(ainvs, check_squarefree=R.is_field()) + self._curve = EllipticCurve(ainvs) else: self._curve = HyperellipticCurve(self._Q, check_squarefree=R.is_field()) diff --git a/src/sage/schemes/plane_quartics/quartic_constructor.py b/src/sage/schemes/plane_quartics/quartic_constructor.py index c1dd1a3d0b0..29d49c2d2c4 100755 --- a/src/sage/schemes/plane_quartics/quartic_constructor.py +++ b/src/sage/schemes/plane_quartics/quartic_constructor.py @@ -13,6 +13,7 @@ from .quartic_generic import QuarticCurve_generic + def QuarticCurve(F, PP=None, check=False): """ Return the quartic curve defined by the polynomial ``F``. diff --git a/src/sage/schemes/plane_quartics/quartic_generic.py b/src/sage/schemes/plane_quartics/quartic_generic.py index 514637e1d96..e41eb64d316 100755 --- a/src/sage/schemes/plane_quartics/quartic_generic.py +++ b/src/sage/schemes/plane_quartics/quartic_generic.py @@ -15,12 +15,13 @@ #***************************************************************************** # Copyright (C) 2006 David Kohel # Distributed under the terms of the GNU General Public License (GPL) -# http://www.gnu.org/licenses/ +# https://www.gnu.org/licenses/ #***************************************************************************** import sage.schemes.curves.projective_curve as projective_curve + def is_QuarticCurve(C): """ Check whether ``C`` is a Quartic Curve. diff --git a/src/sage/schemes/product_projective/homset.py b/src/sage/schemes/product_projective/homset.py index d10d2cc0ccb..658417398b9 100755 --- a/src/sage/schemes/product_projective/homset.py +++ b/src/sage/schemes/product_projective/homset.py @@ -27,6 +27,7 @@ from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme from sage.schemes.generic.homset import SchemeHomset_points + class SchemeHomset_points_product_projective_spaces_ring(SchemeHomset_points): r""" Set of rational points of a product of projective spaces. @@ -63,6 +64,7 @@ def _element_constructor_(self, v, **kwds): """ return self.codomain()._point(self, v, **kwds) + class SchemeHomset_points_product_projective_spaces_field(SchemeHomset_points_product_projective_spaces_ring): def points(self, **kwds): r""" diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index 97909025d19..1f29206dfd1 100755 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -173,6 +173,7 @@ def enum_product_projective_rational_field(X, B): return pts + def enum_product_projective_number_field(X, **kwds): r""" Enumerates product projective points on scheme ``X`` defined over a number field. @@ -247,6 +248,7 @@ def enum_product_projective_number_field(X, **kwds): pts.sort() return pts + def enum_product_projective_finite_field(X): r""" Enumerates projective points on scheme ``X`` defined over a finite field. diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py index b0b672755da..f183d2676aa 100755 --- a/src/sage/schemes/product_projective/space.py +++ b/src/sage/schemes/product_projective/space.py @@ -1080,6 +1080,7 @@ def segre_embedding(self, PP=None, var='u'): return phi + class ProductProjectiveSpaces_field(ProductProjectiveSpaces_ring): def _point(self, *args, **kwds): """ @@ -1220,6 +1221,7 @@ def points_of_bounded_height(self, **kwds): P[dim_prefix[i] + j] = pt[j] i += 1 + class ProductProjectiveSpaces_finite_field(ProductProjectiveSpaces_field): def _point(self, *args, **kwds): r""" diff --git a/src/sage/schemes/product_projective/subscheme.py b/src/sage/schemes/product_projective/subscheme.py index 8fe4fba1f6b..511f10a973e 100755 --- a/src/sage/schemes/product_projective/subscheme.py +++ b/src/sage/schemes/product_projective/subscheme.py @@ -23,6 +23,7 @@ from sage.schemes.projective.projective_subscheme import AlgebraicScheme_subscheme_projective from sage.schemes.projective.projective_space import ProjectiveSpace + class AlgebraicScheme_subscheme_product_projective(AlgebraicScheme_subscheme_projective): r""" Construct an algebraic subscheme of a product of projective spaces. diff --git a/src/sage/schemes/projective/projective_point.py b/src/sage/schemes/projective/projective_point.py index e0227a42ce7..7f941ec6726 100755 --- a/src/sage/schemes/projective/projective_point.py +++ b/src/sage/schemes/projective/projective_point.py @@ -50,6 +50,7 @@ _NumberFields = NumberFields() + # -------------------- # Projective varieties # -------------------- diff --git a/src/sage/sets/disjoint_set.pxd b/src/sage/sets/disjoint_set.pxd index 3c8351983e7..4d981718568 100644 --- a/src/sage/sets/disjoint_set.pxd +++ b/src/sage/sets/disjoint_set.pxd @@ -19,8 +19,8 @@ cdef class DisjointSet_class(SageObject): cpdef number_of_subsets(self) cdef class DisjointSet_of_integers(DisjointSet_class): - cpdef int find(self, int i) - cpdef void union(self, int i, int j) + cpdef int find(self, int i) except -1 + cpdef void union(self, int i, int j) except * cpdef root_to_elements_dict(self) cpdef element_to_root_dict(self) cpdef to_digraph(self) @@ -29,7 +29,7 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): cdef list _int_to_el cdef dict _el_to_int cpdef find(self, e) - cpdef void union(self, e, f) + cpdef void union(self, e, f) noexcept cpdef root_to_elements_dict(self) cpdef element_to_root_dict(self) cpdef to_digraph(self) diff --git a/src/sage/sets/disjoint_set.pyx b/src/sage/sets/disjoint_set.pyx index 1c2d93fea2a..02cf77fbdd7 100644 --- a/src/sage/sets/disjoint_set.pyx +++ b/src/sage/sets/disjoint_set.pyx @@ -448,7 +448,7 @@ cdef class DisjointSet_of_integers(DisjointSet_class): for i, parent in enumerate(l): self.union(parent, i) - cpdef int find(self, int i): + cpdef int find(self, int i) except -1: r""" Return the representative of the set that ``i`` currently belongs to. @@ -479,8 +479,9 @@ cdef class DisjointSet_of_integers(DisjointSet_class): sage: [e.find(i) for i in range(5)] [0, 1, 1, 1, 1] sage: e.find(2**10) - ValueError: i must be between 0 and 4 (1024 given) + Traceback (most recent call last): ... + ValueError: i must be between 0 and 4 (1024 given) .. NOTE:: @@ -492,7 +493,7 @@ cdef class DisjointSet_of_integers(DisjointSet_class): raise ValueError('i must be between 0 and %s (%s given)' % (card - 1, i)) return OP_find(self._nodes, i) - cpdef void union(self, int i, int j): + cpdef void union(self, int i, int j) except *: r""" Combine the set of ``i`` and the set of ``j`` into one. @@ -520,8 +521,9 @@ cdef class DisjointSet_of_integers(DisjointSet_class): sage: d {{0, 1, 2, 4}, {3}} sage: d.union(1, 5) - ValueError: j must be between 0 and 4 (5 given) + Traceback (most recent call last): ... + ValueError: j must be between 0 and 4 (5 given) .. NOTE:: @@ -797,7 +799,7 @@ cdef class DisjointSet_of_hashables(DisjointSet_class): cdef int r = OP_find(self._nodes, i) return self._int_to_el[r] - cpdef void union(self, e, f): + cpdef void union(self, e, f) noexcept: r""" Combine the set of ``e`` and the set of ``f`` into one. diff --git a/src/sage/structure/indexed_generators.py b/src/sage/structure/indexed_generators.py index c0b7312d9dc..9f3c8b710ea 100644 --- a/src/sage/structure/indexed_generators.py +++ b/src/sage/structure/indexed_generators.py @@ -650,6 +650,7 @@ def _latex_generator(self, m): return left + s + right return "%s_{%s}" % (prefix, s) + def split_index_keywords(kwds): """ Split the dictionary ``kwds`` into two dictionaries, one containing diff --git a/src/sage/structure/list_clone_timings.py b/src/sage/structure/list_clone_timings.py index f91eaab558b..a072b7287a5 100644 --- a/src/sage/structure/list_clone_timings.py +++ b/src/sage/structure/list_clone_timings.py @@ -134,6 +134,7 @@ def add1_internal(bla): blo.check() return blo + def add1_immutable(bla): """ TESTS:: @@ -147,6 +148,7 @@ def add1_immutable(bla): lbla[i] += 1 return bla.__class__(bla.parent(), lbla) + def add1_mutable(bla): """ TESTS:: @@ -162,6 +164,7 @@ def add1_mutable(bla): blo.check() return blo + def add1_with(bla): """ TESTS:: diff --git a/src/sage/structure/proof/proof.py b/src/sage/structure/proof/proof.py index 6da86141cc6..f214864cac2 100644 --- a/src/sage/structure/proof/proof.py +++ b/src/sage/structure/proof/proof.py @@ -3,6 +3,7 @@ from sage.structure.sage_object import SageObject + class _ProofPref(SageObject): """ An object that holds global proof preferences. For now these are merely @@ -203,7 +204,8 @@ def polynomial(self, t=None): self._require_proof["polynomial"] = bool(t) -_proof_prefs = _ProofPref(True) #Creates the global object that stores proof preferences. +_proof_prefs = _ProofPref(True) # Creates the global object that stores proof preferences. + def get_flag(t=None, subsystem=None): """ diff --git a/src/sage/structure/test_factory.py b/src/sage/structure/test_factory.py index 9835a06f909..11b90f48f20 100644 --- a/src/sage/structure/test_factory.py +++ b/src/sage/structure/test_factory.py @@ -25,6 +25,7 @@ class A(): # something we can weakref pass + class UniqueFactoryTester(UniqueFactory): def create_key(self, *args, **kwds): diff --git a/src/sage/symbolic/expression_conversion_sympy.py b/src/sage/symbolic/expression_conversion_sympy.py index ecfffc6841d..df7fda7fbed 100644 --- a/src/sage/symbolic/expression_conversion_sympy.py +++ b/src/sage/symbolic/expression_conversion_sympy.py @@ -26,6 +26,8 @@ ######### # Sympy # ######### + + class SympyConverter(Converter): """ Convert any expression to SymPy. diff --git a/src/sage/tensor/modules/alternating_contr_tensor.py b/src/sage/tensor/modules/alternating_contr_tensor.py index 515b315175c..ca03cbfa14f 100644 --- a/src/sage/tensor/modules/alternating_contr_tensor.py +++ b/src/sage/tensor/modules/alternating_contr_tensor.py @@ -39,6 +39,7 @@ class :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor`. from sage.tensor.modules.free_module_tensor import FreeModuleTensor from sage.tensor.modules.comp import Components, CompFullyAntiSym + class AlternatingContrTensor(FreeModuleTensor): r""" Alternating contravariant tensor on a free module of finite rank diff --git a/src/sage/tensor/modules/comp.py b/src/sage/tensor/modules/comp.py index b60916f6b6e..32ac954c7b4 100644 --- a/src/sage/tensor/modules/comp.py +++ b/src/sage/tensor/modules/comp.py @@ -5504,6 +5504,7 @@ def interior_product(self, other): #****************************************************************************** + class KroneckerDelta(CompFullySym): r""" Kronecker delta `\delta_{ij}`. diff --git a/src/sage/tensor/modules/ext_pow_free_module.py b/src/sage/tensor/modules/ext_pow_free_module.py index f9250e59e35..e5218372a8f 100644 --- a/src/sage/tensor/modules/ext_pow_free_module.py +++ b/src/sage/tensor/modules/ext_pow_free_module.py @@ -62,6 +62,7 @@ from sage.tensor.modules.alternating_contr_tensor import AlternatingContrTensor from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm + class ExtPowerFreeModule(FiniteRankFreeModule_abstract): r""" Exterior power of a free module of finite rank over a commutative diff --git a/src/sage/tensor/modules/free_module_alt_form.py b/src/sage/tensor/modules/free_module_alt_form.py index 68ebdb9fd66..3ba9ec0a4a0 100644 --- a/src/sage/tensor/modules/free_module_alt_form.py +++ b/src/sage/tensor/modules/free_module_alt_form.py @@ -40,6 +40,7 @@ from sage.tensor.modules.free_module_tensor import FreeModuleTensor from sage.tensor.modules.comp import Components, CompFullyAntiSym + class FreeModuleAltForm(FreeModuleTensor): r""" Alternating form on a free module of finite rank over a commutative ring. diff --git a/src/sage/tensor/modules/free_module_basis.py b/src/sage/tensor/modules/free_module_basis.py index 4e531b54e6e..f882b88e300 100644 --- a/src/sage/tensor/modules/free_module_basis.py +++ b/src/sage/tensor/modules/free_module_basis.py @@ -35,6 +35,7 @@ from sage.sets.family import AbstractFamily from sage.structure.unique_representation import UniqueRepresentation + class Basis_abstract(UniqueRepresentation, AbstractFamily): """ Abstract base class for (dual) bases of free modules. @@ -419,6 +420,7 @@ def set_name(self, symbol, latex_symbol=None, indices=None, #****************************************************************************** + class FreeModuleCoBasis(Basis_abstract): r""" Dual basis of a free module over a commutative ring. @@ -549,6 +551,7 @@ def _repr_(self): #****************************************************************************** + class FreeModuleBasis(Basis_abstract): r""" Basis of a free module over a commutative ring `R`. diff --git a/src/sage/tensor/modules/free_module_linear_group.py b/src/sage/tensor/modules/free_module_linear_group.py index bb9ccf74e9a..9893ba32420 100644 --- a/src/sage/tensor/modules/free_module_linear_group.py +++ b/src/sage/tensor/modules/free_module_linear_group.py @@ -35,6 +35,7 @@ from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule from sage.tensor.modules.free_module_automorphism import FreeModuleAutomorphism + class FreeModuleLinearGroup(UniqueRepresentation, Parent): r""" General linear group of a free module of finite rank over a commutative diff --git a/src/sage/tensor/modules/tensor_free_module.py b/src/sage/tensor/modules/tensor_free_module.py index 7e44a076694..8a02751c471 100644 --- a/src/sage/tensor/modules/tensor_free_module.py +++ b/src/sage/tensor/modules/tensor_free_module.py @@ -70,6 +70,7 @@ from .tensor_free_submodule_basis import TensorFreeSubmoduleBasis_sym + class TensorFreeModule(ReflexiveModule_tensor, FiniteRankFreeModule_abstract): r""" Class for the free modules over a commutative ring `R` that are diff --git a/src/sage/tensor/modules/tensor_with_indices.py b/src/sage/tensor/modules/tensor_with_indices.py index f6e5104ea14..e65277935a7 100644 --- a/src/sage/tensor/modules/tensor_with_indices.py +++ b/src/sage/tensor/modules/tensor_with_indices.py @@ -27,6 +27,7 @@ # The dot is special syntax for unnamed index positions. _alph_or_dot_pattern = r"([.]|[^\d\W_])" + class TensorWithIndices(SageObject): r""" Index notation for tensors. diff --git a/src/sage/tests/finite_poset.py b/src/sage/tests/finite_poset.py index d04221dcc13..3d4cec06129 100644 --- a/src/sage/tests/finite_poset.py +++ b/src/sage/tests/finite_poset.py @@ -91,6 +91,7 @@ sublattice_closed = ['distributive', 'modular', 'semidistributive', 'join_semidistributive', 'meet_semidistributive'] + def test_attrcall(name, L): """ Return a function by name. @@ -122,6 +123,7 @@ def test_attrcall(name, L): return L.is_orthocomplemented(unique=True) return attrcall(name)(L) + def test_finite_lattice(L): """ Test several functions on a given finite lattice. diff --git a/src/sage/tests/functools_partial_src.py b/src/sage/tests/functools_partial_src.py index d352d160230..e8c983356aa 100644 --- a/src/sage/tests/functools_partial_src.py +++ b/src/sage/tests/functools_partial_src.py @@ -4,6 +4,7 @@ """ from functools import partial + def base(x): """ Test function to make sure diff --git a/src/sage/topology/cell_complex.py b/src/sage/topology/cell_complex.py index 38caf541192..7b64a3d36dd 100644 --- a/src/sage/topology/cell_complex.py +++ b/src/sage/topology/cell_complex.py @@ -709,16 +709,17 @@ def betti(self, dim=None, subcomplex=None): sage: S2c.betti(2) # needs sage.modules 1 """ - dict = {} + dic = {} H = self.homology(dim, base_ring=QQ, subcomplex=subcomplex) try: for n in H.keys(): - dict[n] = H[n].dimension() + dic[n] = H[n].dimension() if n == 0: - dict[n] += 1 - return dict + dic[n] += 1 except AttributeError: return H.dimension() + else: + return dic def is_acyclic(self, base_ring=ZZ): """ diff --git a/src/sage/topology/delta_complex.py b/src/sage/topology/delta_complex.py index 6cd2ee7acc6..b9ce4d5fb62 100644 --- a/src/sage/topology/delta_complex.py +++ b/src/sage/topology/delta_complex.py @@ -1388,10 +1388,10 @@ def _epi_from_standard_simplex(self, idx=-1, dim=None): simplex_cells = simplex.cells() self_cells = self.cells() if dim > 0: - map = {dim: {tuple(simplex_cells[dim][0]): idx}} + mapping = {dim: {tuple(simplex_cells[dim][0]): idx}} else: - map = {dim: {(0,): idx}} - faces_dict = map[dim] + mapping = {dim: {(0,): idx}} + faces_dict = mapping[dim] for n in range(dim, 0, -1): n_cells = faces_dict faces_dict = {} @@ -1407,8 +1407,8 @@ def _epi_from_standard_simplex(self, idx=-1, dim=None): for j in one_cell: if j not in faces_dict: faces_dict[j] = one_cell[j] - map[n-1] = faces_dict - return map + mapping[n-1] = faces_dict + return mapping def _is_glued(self, idx=-1, dim=None): r""" diff --git a/src/sage/topology/moment_angle_complex.py b/src/sage/topology/moment_angle_complex.py index 04e14ef1ce4..3291b9ef104 100644 --- a/src/sage/topology/moment_angle_complex.py +++ b/src/sage/topology/moment_angle_complex.py @@ -200,7 +200,7 @@ def __classcall_private__(cls, simplicial_complex): immutable_complex = SimplicialComplex(is_mutable=False) return super().__classcall__(cls, immutable_complex) - def __init__(self, simplicial_complex): + def __init__(self, simplicial_complex) -> None: """ Initialize ``self``. @@ -295,7 +295,7 @@ def cubical_complex(self): .. WARNING:: - The construction can be very slow, it is not reccomended unless + The construction can be very slow, it is not recommended unless the corresponding simplicial complex has 5 or less vertices. EXAMPLES:: @@ -343,14 +343,14 @@ def simplicial_complex(self): """ return self._simplicial_complex - def components(self): + def components(self) -> dict: r""" Return the dictionary of components of ``self``, indexed by facets of the associated simplicial complex. OUTPUT: - A dictonary, whose values are lists, representing spheres + A dictionary, whose values are lists, representing spheres and disks described in the construction of the moment-angle complex. ``The 2-simplex`` represents a 2-disk, and ``Minimal triangulation of the 1-sphere`` represents a 1-sphere. @@ -507,7 +507,7 @@ def _homology_group(self, i, base_ring, cohomology, algorithm, verbose, reduced) return HomologyGroup(m, base_ring, invfac) def homology(self, dim=None, base_ring=ZZ, cohomology=False, - algorithm='pari', verbose=False, reduced=True): + algorithm='pari', verbose=False, reduced=True) -> dict: r""" The (reduced) homology of ``self``. @@ -615,15 +615,15 @@ def homology(self, dim=None, base_ring=ZZ, cohomology=False, 17: 0} sage: Z = MomentAngleComplex([[0,1,2,3], [0,1,2,4], [0,1,3,5], ....: [0,1,4,5], [0,2,3,6], [0,2,4,6]]) - sage: Z.homology(dim=range(0,5), reduced=True) + sage: Z.homology(dim=range(5), reduced=True) {0: 0, 1: 0, 2: 0, 3: Z x Z x Z x Z, 4: Z x Z} - sage: Z.homology(dim=range(0,5), reduced=False) + sage: Z.homology(dim=range(5), reduced=False) {0: Z, 1: 0, 2: 0, 3: Z x Z x Z x Z, 4: Z x Z} sage: all(Z.homology(i,reduced=True) == Z.homology(i,reduced=False) ....: for i in range(1, dim(Z))) True sage: all(Z.homology(i,reduced=True) == Z.homology(i,reduced=False) - ....: for i in range(0, dim(Z))) + ....: for i in range(dim(Z))) False """ if dim is not None: @@ -641,7 +641,7 @@ def homology(self, dim=None, base_ring=ZZ, cohomology=False, algorithm=algorithm, verbose=verbose, reduced=reduced) for i in dims} def cohomology(self, dim=None, base_ring=ZZ, algorithm='pari', - verbose=False, reduced=True): + verbose=False, reduced=True) -> dict: r""" The reduced cohomology of ``self``. @@ -672,7 +672,7 @@ def cohomology(self, dim=None, base_ring=ZZ, algorithm='pari', return self.homology(dim=dim, cohomology=True, base_ring=base_ring, algorithm=algorithm, verbose=verbose, reduced=reduced) - def betti(self, dim=None): + def betti(self, dim=None) -> dict: r""" Return the Betti number (or numbers) of ``self``. @@ -698,16 +698,17 @@ def betti(self, dim=None): sage: Z.betti(dim=6) {6: 2} """ - dict = {} + dic = {} H = self.homology(dim=dim, base_ring=QQ) try: for n in H: - dict[n] = H[n].dimension() + dic[n] = H[n].dimension() if n == 0: - dict[n] += 1 - return dict + dic[n] += 1 except AttributeError: return H.dimension() + else: + return dic def euler_characteristic(self): """ @@ -762,7 +763,7 @@ def product(self, other): simplicial_complex = self._simplicial_complex.join(other._simplicial_complex, rename_vertices=True) return MomentAngleComplex(simplicial_complex) - def has_trivial_lowest_deg_massey_product(self): + def has_trivial_lowest_deg_massey_product(self) -> bool: """ Return whether ``self`` has a non-trivial lowest degree triple Massey product. diff --git a/src/sage/topology/simplicial_complex_examples.py b/src/sage/topology/simplicial_complex_examples.py index c51954d7d9a..97958848bb0 100644 --- a/src/sage/topology/simplicial_complex_examples.py +++ b/src/sage/topology/simplicial_complex_examples.py @@ -614,8 +614,8 @@ def QuaternionicProjectivePlane(): (3, 4, 6, 7, 11, 12, 13, 14, 15), # L (3, 4, 6, 7, 10, 12, 13, 14, 15)] # N - return UniqueSimplicialComplex([[g(index) for index in tuple] - for tuple in start_list + return UniqueSimplicialComplex([[g(index) for index in tup] + for tup in start_list for g in PermutationGroup([P, S])]) diff --git a/src/sage/topology/simplicial_set.py b/src/sage/topology/simplicial_set.py index 920df5e0437..974feac8510 100644 --- a/src/sage/topology/simplicial_set.py +++ b/src/sage/topology/simplicial_set.py @@ -2119,16 +2119,17 @@ def betti(self, dim=None, subcomplex=None): sage: BC3.betti(range(4)) # needs sage.groups sage.modules {0: 1, 1: 0, 2: 0, 3: 0} """ - dict = {} + dic = {} H = self.homology(dim, base_ring=QQ, subcomplex=subcomplex) try: for n in H.keys(): - dict[n] = H[n].dimension() + dic[n] = H[n].dimension() if n == 0: - dict[n] += 1 - return dict + dic[n] += 1 except AttributeError: return H.dimension() + else: + return dic def n_chains(self, n, base_ring=ZZ, cochains=False): r""" diff --git a/src/sage/topology/simplicial_set_morphism.py b/src/sage/topology/simplicial_set_morphism.py index c5285335a22..9d54e2e1b5e 100644 --- a/src/sage/topology/simplicial_set_morphism.py +++ b/src/sage/topology/simplicial_set_morphism.py @@ -817,10 +817,11 @@ def is_injective(self): if self._is_identity: return True domain = self.domain() - for n in range(domain.dimension()+1): - input = domain.n_cells(n) - output = {self(sigma) for sigma in input if self(sigma).is_nondegenerate()} - if len(input) > len(output): + for n in range(domain.dimension() + 1): + domain_cells = domain.n_cells(n) + output = {self(sigma) for sigma in domain_cells + if self(sigma).is_nondegenerate()} + if len(domain_cells) > len(output): return False return True diff --git a/src/sage/typeset/ascii_art.py b/src/sage/typeset/ascii_art.py index 83d92af8959..e470e2bd88d 100644 --- a/src/sage/typeset/ascii_art.py +++ b/src/sage/typeset/ascii_art.py @@ -44,11 +44,12 @@ sage: shell.run_cell('%display ascii_art') sage: shell.run_cell("i = var('i')") # needs sage.symbolic sage: shell.run_cell('sum(factorial(i)*x^i, i, 0, 10)') # needs sage.symbolic - 10 9 8 7 6 5 4 3 - 3628800*x + 362880*x + 40320*x + 5040*x + 720*x + 120*x + 24*x + 6*x + 10 9 8 7 6 5 4 3 > + 3628800*x + 362880*x + 40320*x + 5040*x + 720*x + 120*x + 24*x + 6*x > - 2 - + 2*x + x + 1 + > 2 + > + 2*x + x + 1 + sage: shell.run_cell('3/(7*x)') # needs sage.symbolic 3 --- diff --git a/src/sage/version.py b/src/sage/version.py index b9ae8e5a1c9..bf2f786a4bf 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.beta2' -date = '2024-08-10' -banner = 'SageMath version 10.5.beta2, Release Date: 2024-08-10' +version = '10.5.beta3' +date = '2024-09-03' +banner = 'SageMath version 10.5.beta3, Release Date: 2024-09-03' diff --git a/src/sage_docbuild/conf.py b/src/sage_docbuild/conf.py index ddd64c2718f..0f0333338e3 100644 --- a/src/sage_docbuild/conf.py +++ b/src/sage_docbuild/conf.py @@ -27,11 +27,12 @@ import sphinx.ext.intersphinx as intersphinx from sphinx import highlighting from sphinx.transforms import SphinxTransform +from sphinx.util.docutils import SphinxDirective from IPython.lib.lexers import IPythonConsoleLexer, IPyLexer from sage.misc.sagedoc import extlinks from sage.env import SAGE_DOC_SRC, SAGE_DOC, PPLPY_DOCS, MATHJAX_DIR from sage.misc.latex_macros import sage_mathjax_macros -from sage.features import PythonModule +from sage.features.sphinx import JupyterSphinx from sage.features.all import all_features import sage.version @@ -56,12 +57,15 @@ 'sphinx_inline_tabs', 'IPython.sphinxext.ipython_directive', 'matplotlib.sphinxext.plot_directive', - 'jupyter_sphinx', ] +if JupyterSphinx().is_present(): + extensions.append('jupyter_sphinx') + jupyter_execute_default_kernel = 'sagemath' if SAGE_LIVE_DOC == 'yes': + JupyterSphinx().require() SAGE_JUPYTER_SERVER = os.environ.get('SAGE_JUPYTER_SERVER', 'binder') if SAGE_JUPYTER_SERVER.startswith('binder'): # format: "binder" or @@ -1037,6 +1041,14 @@ def apply(self): parent.insert(index + 1, container) +class Ignore(SphinxDirective): + + has_content = True + + def run(self): + return [] + + # This replaces the setup() in sage.misc.sagedoc_conf def setup(app): app.connect('autodoc-process-docstring', process_docstring_cython) @@ -1050,6 +1062,12 @@ def setup(app): app.add_transform(SagemathTransform) if SAGE_LIVE_DOC == 'yes' or SAGE_PREPARSED_DOC == 'yes': app.add_transform(SagecodeTransform) + if not JupyterSphinx().is_present(): + app.add_directive("jupyter-execute", Ignore) + app.add_directive("jupyter-kernel", Ignore) + app.add_directive("jupyter-input", Ignore) + app.add_directive("jupyter-output", Ignore) + app.add_directive("thebe-button", Ignore) # When building the standard docs, app.srcdir is set to SAGE_DOC_SRC + # 'LANGUAGE/DOCNAME'. @@ -1071,12 +1089,7 @@ def setup(app): # https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#tags # https://www.sphinx-doc.org/en/master/usage/configuration.html#conf-tags # https://github.com/readthedocs/readthedocs.org/issues/4603#issuecomment-1411594800 -# Workaround to allow importing this file from other confs -if 'tags' not in locals(): - class Tags(set): - has = set.__contains__ - tags = Tags() - - -for feature in all_features(): - tags.add('feature_' + feature.name.replace('.', '_')) +def feature_tags(): + for feature in all_features(): + if feature.is_present(): + yield 'feature_' + feature.name.replace('.', '_') diff --git a/src/tox.ini b/src/tox.ini index dc244c115f6..404b040b452 100644 --- a/src/tox.ini +++ b/src/tox.ini @@ -315,7 +315,7 @@ passenv = RUFF_OUTPUT_FORMAT # 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,E713,PLW0602,PLR1711,E714,PLR1701,PLR1704,PLW3301,PLW1510,E721,PLW0120,F811,PLC2401,PLC0414,E743,PLE0101,PLR0124,PLW0127,F541,PLW1508,PLC3002,E742,PLE0302,PLW0129,F402,PLC0208 {posargs:{toxinidir}/sage/} +commands = ruff check --ignore PLR2004,I001,F401,E741,F821,PLR0912,PLR0913,E402,PLR0915,PLW2901,PLR5501,PLR0911,E731,F405,PLR1714,PLR1730,PLR1736,F403,PLR0402,PLW0603,F841,E713,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/} [flake8] rst-roles = diff --git a/tox.ini b/tox.ini index 3e3d2656553..654e221aa07 100644 --- a/tox.ini +++ b/tox.ini @@ -280,7 +280,7 @@ setenv = linuxmint-21.3: BASE_IMAGE=linuxmintd/mint21.3 # # https://hub.docker.com/_/fedora - # as of 2024-01, latest=39, rawhide=40 + # as of 2024-08, latest=40, rawhide=41 fedora: SYSTEM=fedora fedora: BASE_IMAGE=fedora fedora: IGNORE_MISSING_SYSTEM_PACKAGES=yes @@ -299,6 +299,7 @@ setenv = fedora-38: BASE_TAG=38 fedora-39: BASE_TAG=39 fedora-40: BASE_TAG=40 + fedora-41: BASE_TAG=41 # # https://hub.docker.com/r/scientificlinux/sl # @@ -855,8 +856,8 @@ setenv = ubuntu-{xenial-toolchain-gcc_9,bionic-gcc_8,focal,jammy,lunar,mantic,noble} \ debian-{bullseye,bookworm,trixie,sid} \ linuxmint-{20.1,20.2,20.3,21,21.1,21.2,21.3} \ - fedora-{30,31,32,33,34,35,36,37,38,39,40} \ - centos-stream-9-python3.9 \ + fedora-{30,31,32,33,34,35,36,37,38,39,40,41} \ + centos-stream-{9,9-python3.12} \ almalinux-{8-python3.9,9-python3.11} \ gentoo-python{3.10,3.11,3.12} \ archlinux-latest \